Why Make Software Engineer Principles SOLID?
소프트웨어 엔지니어 원칙을 SOLID로 만드는 이유는 무엇인가요?
Introduction: 소개:
Let’s start the blog with a deep breath. This Blog is not about the states of matter like solid, liquid, or gases (what software engineers have to do with chemistry. we don’t need chemicals to burn systems. poorly written code is enough).
블로그를 깊은 숨을 쉬며 시작해봅시다. 이 블로그는 고체, 액체 또는 기체와 같은 물질의 상태에 관한 것이 아닙니다(소프트웨어 엔지니어가 화학과 무슨 관계가 있나요. 시스템을 태우기 위해 화학 물질이 필요하지 않습니다. 잘못 작성된 코드면 충분합니다).
This blog is about good programming practices, design principles and to be specific we are discussing SOLID principles.
이 블로그는 좋은 프로그래밍 관행, 디자인 원칙에 관한 것이며, 구체적으로 우리는 SOLID 원칙에 대해 논의하고 있습니다.
Note: this blog is not for beginners. beginners should focus on writing a lot of code even it is a very dirty code(inefficient). they should first learn a language fundamental. write a lot of code, do personal projects, or any kind of shit you like. do a lot of mistakes in code and it is completely fine for beginners. (but what about when you are working in the company)
참고: 이 블로그는 초보자를 위한 것이 아닙니다. 초보자는 비효율적인 매우 더러운 코드라도 많은 코드를 작성하는 데 집중해야 합니다. 그들은 먼저 언어의 기초를 배워야 합니다. 많은 코드를 작성하고, 개인 프로젝트를 하거나 좋아하는 어떤 것을 하세요. 코드에서 많은 실수를 해도 초보자에게는 전혀 문제가 없습니다. (하지만 회사에서 일할 때는 어떻게 될까요)
Think of it as a football game when a newbie plays nobody expects a perfect pass or shoot. newbie should not focus on the tactics involved in a team game. you can’t learn football in a single day it needs a lot of practice and that involved lot of mistakes.
신입 선수가 경기를 할 때 완벽한 패스나 슈팅을 기대하지 않는 축구 게임으로 생각해 보세요. 신입 선수는 팀 게임에 관련된 전술에 집중해서는 안 됩니다. 축구는 하루 만에 배울 수 없으며 많은 연습이 필요하고 그 과정에서 많은 실수가 발생합니다.
If an experienced software professional is writing dirty code uhhhh then you are in the wrong profession. you should try to become a singer, boxer, painter, etc whatever your passion.
경험이 풍부한 소프트웨어 전문가가 더러운 코드를 작성하고 있다면, 당신은 잘못된 직업에 있는 것입니다. 당신의 열정에 따라 가수, 복서, 화가 등으로 전향해 보아야 합니다.
What are Principles and why should learn? :
원칙이란 무엇이며 왜 배워야 할까요?
it is important to understand first about principle. why the word principles exist in the coding world?
원칙에 대해 먼저 이해하는 것이 중요하다. 코딩 세계에 왜 원칙이라는 단어가 존재하는가?
what is the meaning of principles?
원칙의 의미는 무엇인가요?
it is a fundamental law that is validated by people over many years. people have executed it for many years and finally when they can’t disproof. it becomes principles. so simply we can say it is a fundamental truth.
사람들이 수년 동안 검증해온 기본 법칙입니다. 사람들은 수년 동안 이를 실행해왔고, 결국 그들이 반증할 수 없을 때, 그것은 원칙이 됩니다. 그래서 간단히 말하면, 그것은 기본적인 진리라고 할 수 있습니다.
why we need principles? 원칙이 필요한 이유는 무엇인가요?
To put it simply, we need principles to not repeat mistakes.
간단히 말해서, 우리는 실수를 반복하지 않기 위한 원칙이 필요합니다.
When professionals are developing software for years they realized they are doing a common design mistake(i am not discussing missing semicolon in end dumbo).
전문가들이 수년 동안 소프트웨어를 개발하면서 그들이 공통적인 디자인 실수를 하고 있다는 것을 깨달았습니다(나는 끝에 세미콜론이 빠진 것에 대해 논의하고 있지 않습니다, 바보야).
While developing software they realized it is hard to maintain a codebase or it is not easy to make it extendable(means feature requirement grows).
소프트웨어를 개발하는 동안 그들은 코드베이스를 유지하는 것이 어렵거나 확장 가능하게 만드는 것이 쉽지 않다는 것을 깨달았다(기능 요구 사항이 증가한다는 의미).
how to deal with growing complexity due to growing features? Remember most software start with a basic feature(login, signup, etc) later it becomes set of unlimited feature. take the example of Facebook it is started with basic functionality (signup, login, profile, friends list, etc) but now it consists of unlimited features.
기능이 증가함에 따라 증가하는 복잡성을 어떻게 처리할까요? 대부분의 소프트웨어는 기본 기능(로그인, 가입 등)으로 시작하지만 나중에 무한한 기능 세트로 발전합니다. Facebook의 예를 들어보면, 기본 기능(가입, 로그인, 프로필, 친구 목록 등)으로 시작했지만 이제는 무한한 기능을 포함하고 있습니다.
So the goal is to make software easy to maintain, flexible(easy to extend), and understandable. so professionals in history developed numerous software and done a lot of mistakes in design. faced a lot of problems to deal with the growing complexity of the codebase consider the case when thousands of people are working simultaneously(how to deal with the complexity of the project). Then they realized they are not alone in this. Everyone is facing these challenges.
그래서 목표는 소프트웨어를 유지보수하기 쉽고, 유연하며(확장하기 쉬움) 이해하기 쉽게 만드는 것입니다. 그래서 역사 속의 전문가들은 수많은 소프트웨어를 개발하고 디자인에서 많은 실수를 저질렀습니다. 코드베이스의 증가하는 복잡성을 처리하는 데 많은 문제에 직면했습니다. 수천 명이 동시에 작업할 때의 경우를 고려해 보십시오(프로젝트의 복잡성을 어떻게 처리할 것인가). 그러고 나서 그들은 이 문제에 혼자가 아니라는 것을 깨달았습니다. 모든 사람이 이러한 도전에 직면하고 있습니다.
To put it simply principles exist to save your ass. the goal of principles is to save developers from mistakes that numerous developers have already done. principles are not created overnight it is a sum equal to a decade's experience of professionals. it saves the cost of effort, time & money for the organization.
간단히 말하자면, 원칙은 당신을 구하기 위해 존재합니다. 원칙의 목표는 수많은 개발자들이 이미 저지른 실수로부터 개발자를 보호하는 것입니다. 원칙은 하룻밤 사이에 만들어지지 않으며, 이는 전문가들의 10년 경험의 합입니다. 이는 조직의 노력, 시간 및 비용을 절약합니다.
principles help make software look simple, easy to use, easy to read, extendable to unlimited features, and require low maintenance costs. it is only possible when design and code quality is good for the codebase.
원칙은 소프트웨어를 단순하고 사용하기 쉽고 읽기 쉬우며 무한한 기능으로 확장 가능하게 만들고 유지 관리 비용을 낮게 유지하는 데 도움을 줍니다. 이는 디자인과 코드 품질이 코드베이스에 대해 좋을 때만 가능합니다.
Why the hell I need clean code or good design? when I can write a lot of code and make functionality complete
왜 깨끗한 코드나 좋은 디자인이 필요한가? 많은 코드를 작성하고 기능을 완성할 수 있는데
It is important to discuss why we need good design and clean code practices?
우리가 좋은 디자인과 깔끔한 코드 관행이 필요한 이유에 대해 논의하는 것이 중요합니다
How much disastrous it can go? we will discuss those people who focus solely on completing features anyhow and how it significantly impacts business.
얼마나 재앙적일 수 있을까요? 우리는 어떻게든 기능을 완성하는 데만 집중하는 사람들과 그것이 비즈니스에 미치는 중대한 영향을 논의할 것입니다.
Let’s take a simple example to understand real-world case:
실제 사례를 이해하기 위해 간단한 예를 들어보겠습니다:
There is a new project started in the company like a newborn baby.
회사가 마치 갓 태어난 아기처럼 새로운 프로젝트를 시작했습니다.
Starting they have a limited feature list and need to quickly rock and roll in the market so they hired few developers.
시작할 때 그들은 제한된 기능 목록을 가지고 있으며 시장에서 빠르게 록앤롤할 필요가 있어 몇 명의 개발자를 고용했습니다.
the manager sent the feature list to the developer and told them to complete it quickly with a timeline of a weak(we need to rock and roll in market boy ).
매니저는 기능 목록을 개발자에게 보내고 그들에게 약한 일정으로 빠르게 완료하라고 말했습니다(우리는 시장에서 성공해야 합니다).
The developers started working they are professional dumb developers. they focused on completing the feature list instead of design and code quality.
개발자들은 작업을 시작했지만 그들은 전문적인 멍청한 개발자들이다. 그들은 디자인과 코드 품질 대신 기능 목록을 완성하는 데 집중했다.
as soon as the feature is completed they are in hurry to go home to spend time with a beautiful wife or children(or get drunk at night) without worry about the poor design of the system and code quality(who cares feature is complete).
기능이 완료되자마자 그들은 시스템의 설계와 코드 품질에 대한 걱정 없이 아름다운 아내나 자녀와 시간을 보내기 위해 집에 가거나(혹은 밤에 술에 취하기 위해) 서두른다(기능이 완료되었으니 누가 신경 쓰겠는가).
They know management wants the feature to get completed and they are not technical people who understand the quality of work.
그들은 경영진이 기능이 완료되기를 원한다는 것을 알고 있으며, 그들은 작업의 품질을 이해하는 기술적인 사람들이 아니다.
Management is happy that they have hired the right people who complete features quickly. Boss is happy he is appreciating the team for their effort.
경영진은 기능을 빠르게 완성하는 적합한 인재를 채용한 것에 만족하고 있다. 상사는 팀의 노력을 인정하며 기뻐하고 있다.
This is happy perfect life everyone is happy. the whole room is spread with the light of enthusiasm. people are on top of their motivation and ready to conquer the market from their product.
이것은 행복한 완벽한 삶으로, 모든 사람이 행복합니다. 방 전체가 열정의 빛으로 가득 차 있습니다. 사람들은 자신의 동기 부여가 최고조에 달해 있으며, 자신의 제품으로 시장을 정복할 준비가 되어 있습니다.
After 1–2 years things are different from the start. now the project is not a newborn baby. it is running as a mature product in the market.
1-2년 후 상황은 처음과 다릅니다. 이제 프로젝트는 갓 태어난 아기가 아닙니다. 시장에서 성숙한 제품으로 운영되고 있습니다.
it has a large user base. starting you can make many mistakes as few people are using, but now even a slight mistake in functionality impacts user experience. competition is tough in the market as opponents also doing the same thing, so the company needs to constantly improve the product.
사용자 기반이 큽니다. 시작할 때는 사용자가 적어 많은 실수를 할 수 있지만, 이제는 기능에서의 작은 실수조차 사용자 경험에 영향을 미칩니다. 경쟁이 치열한 시장에서 경쟁자들도 같은 일을 하고 있기 때문에 회사는 제품을 지속적으로 개선해야 합니다.
Now codebase is large it has tons of files, classes, methods, etc. it is not a small repo now. this is the starting of problems now a real test of the project and developers started.
이제 코드베이스가 커져서 파일, 클래스, 메서드 등이 엄청나게 많아졌습니다. 이제 작은 저장소가 아닙니다. 이것이 문제의 시작이며, 이제 프로젝트와 개발자에 대한 진정한 테스트가 시작되었습니다.
Management gives a new set of feature lists for the product.
경영진이 제품에 대한 새로운 기능 목록을 제공합니다.
when developers started implementing features they felt it is tougher to add features in comparison to starting. now projects contain tons of files, components, class, etc and they are interrelated to each other. any change in class affects much connected classes.
개발자들이 기능을 구현하기 시작했을 때, 그들은 시작할 때에 비해 기능을 추가하는 것이 더 어렵다고 느꼈습니다. 이제 프로젝트에는 수많은 파일, 구성 요소, 클래스 등이 포함되어 있으며, 이들은 서로 연결되어 있습니다. 클래스의 어떤 변경도 많은 연결된 클래스에 영향을 미칩니다.
it is hard to find what purpose class serves by directly looking into it. naming is not consistent also so hard to read code. bugs are coming more frequently than in starting. the rate of bugs on the server is increasing.
클래스가 어떤 목적을 가지고 있는지 직접 살펴보는 것은 어렵다. 이름이 일관되지 않아 코드를 읽기 어렵다. 버그가 처음보다 더 자주 발생하고 있다. 서버의 버그 발생률이 증가하고 있다.
now developers are afraid to make changes as it can affect previous functionality they might lose the job if some functionality gets broken on production. who will test the already tested feature( involves cost time and time is gold)?
이제 개발자들은 변경을 두려워합니다. 변경이 이전 기능에 영향을 미칠 수 있기 때문입니다. 만약 프로덕션에서 어떤 기능이 깨지면 그들은 직업을 잃을 수도 있습니다. 이미 테스트된 기능을 누가 테스트할까요(비용과 시간이 소요되며 시간은 금이죠)?
So-called software professionals knew that they have done mistakes for not focusing on good design and clean code early. now, projects can’t be stopped or they can not spend months for rework.
소위 소프트웨어 전문가들은 초기 단계에서 좋은 설계와 깔끔한 코드를 중시하지 않아 실수를 했다는 것을 알고 있었습니다. 이제 프로젝트는 중단할 수 없거나 재작업에 몇 달을 할애할 수 없습니다.
Time for another idea to make management fool. the evergreen idea we need more developers to work on the project.
관리자를 속일 또 다른 아이디어의 시간입니다. 프로젝트에 더 많은 개발자가 필요하다는 영원한 아이디어입니다.
To save the ass more hiring is a good idea. we can win by brute force then intelligence. all people are thinking project is big and complex. they have a more user base now they really need more developers to meet the needs of markets. nobody is ready to accept their design and code sucks that’s why it needs a lot of people to manage.
더 많은 인력을 고용하는 것은 좋은 생각이다. 우리는 힘으로 이길 수 있다면 지능으로도 이길 수 있다. 모든 사람들은 프로젝트가 크고 복잡하다고 생각하고 있다. 그들은 이제 더 많은 사용자 기반을 가지고 있으며, 시장의 요구를 충족시키기 위해 정말로 더 많은 개발자가 필요하다. 아무도 그들의 디자인과 코드가 형편없다는 것을 받아들이고 싶어하지 않기 때문에 많은 사람들이 관리해야 한다.
management can’t do anything (don’t know about it). so it started hiring more people.
경영진은 아무것도 할 수 없었다(그것에 대해 알지 못했다). 그래서 더 많은 사람을 고용하기 시작했다.
think about the scenario when you see the big mess and instead of cleaning it, you add many new people to make a bigger mess. this is the same case.
큰 혼란을 보았을 때 청소하는 대신 많은 새로운 사람들을 추가하여 더 큰 혼란을 만드는 상황을 생각해 보세요. 이것은 같은 경우입니다.
now the project contains a hell lot of people. they all working on the same code base and foundation design of the project.
이제 프로젝트에는 많은 사람들이 있습니다. 그들은 모두 같은 코드 베이스와 프로젝트의 기본 설계에서 작업하고 있습니다.
Now every changing year management needs to spend many times cost(compare to the previous year) on developers. even a small change in the product takes a lot of time. maintenance cost is extremely high.
이제 매년 변화하는 관리에서는 개발자에게 이전 해에 비해 많은 비용을 지출해야 합니다. 제품의 작은 변화조차도 많은 시간이 소요됩니다. 유지보수 비용이 매우 높습니다.
Think about the project after 5 years? what will happen when a hell lot of people work in poor design and do dirty code practices.
5년 후 프로젝트에 대해 생각해 보세요. 형편없는 디자인에서 많은 사람들이 일하고 더러운 코딩 관행을 따를 때 어떤 일이 발생할까요?
now after 5 years management realized the product is taking a lot of cost for maintenance, they need to hire a lot of developers every year and the project is not flexible like they can add new feature easily. they can not create a new same project (business is running it don’t get develop overnight) or can rework it(involves cost and time).
이제 5년이 지난 후, 경영진은 제품 유지 관리에 많은 비용이 소요되고 있다는 것을 깨달았습니다. 매년 많은 개발자를 고용해야 하며, 프로젝트는 새로운 기능을 쉽게 추가할 수 있을 만큼 유연하지 않습니다. 그들은 같은 새로운 프로젝트를 만들 수 없거나(비즈니스가 운영되고 있어 하룻밤 사이에 개발되지 않습니다) 재작업할 수 없습니다(비용과 시간이 소요됩니다).
now the founder developer of the project is long gone from a company they can't blame anyone. they don’t have an option they can only drag the project more if they have a lot of money still left in a pocket or can decide to close the product(death for the project). if the company is making a lot of money they might drag the project 5 years more but it will still be a big mess.
이제 프로젝트의 창립 개발자는 회사에서 오래 전에 떠났기 때문에 그들은 누구를 탓할 수 없다. 그들은 선택의 여지가 없으며, 주머니에 돈이 많이 남아 있다면 프로젝트를 계속 끌고 갈 수밖에 없고, 그렇지 않으면 제품을 종료할 수밖에 없다(프로젝트의 죽음). 회사가 많은 돈을 벌고 있다면 프로젝트를 5년 더 끌 수 있지만 여전히 큰 혼란이 될 것이다.
Moral of the story: 이야기의 교훈:
Put simply products get died with poor design and dirty code. now I hope you can understand how disastrous the myopia view can be.
간단히 말해, 제품은 형편없는 디자인과 더러운 코드로 인해 죽습니다. 이제 당신이 근시안적인 시각이 얼마나 재앙적일 수 있는지 이해할 수 있기를 바랍니다.
long term problems required long-term solutions. good design and clean code practice is not the fruit that grows overnight or in a weak. it is a proper plant with beautiful flowers and yummy fruits. it is a long-term view of the project.
장기적인 문제는 장기적인 해결책을 필요로 합니다. 좋은 디자인과 깔끔한 코드 실천은 하룻밤 사이에 자라는 열매가 아니며, 약한 것에서도 자라지 않습니다. 그것은 아름다운 꽃과 맛있는 열매를 가진 올바른 식물입니다. 그것은 프로젝트에 대한 장기적인 관점입니다.
the principle exists to make software simple irrespective of growing complexity.it is the fundamental concept that every professional must know and should implement(part of the work).
원칙은 증가하는 복잡성과 관계없이 소프트웨어를 단순하게 만들기 위해 존재합니다. 이는 모든 전문가가 알아야 하고 구현해야 하는 기본 개념입니다(작업의 일부).
Now we can discuss the main star SOLID principles because we are clear why we need it(at least me).
이제 우리는 왜 그것이 필요한지(적어도 나에게는) 명확하므로 주요 스타 SOLID 원칙에 대해 논의할 수 있습니다.
SOLID PRINCIPLES: SOLID 원칙:
Yes, software development is not a Jenga game. While playing this game you have to be careful. you need to add and remove the block carefully so the whole building doesn’t get collapsed.
네, 소프트웨어 개발은 젠가 게임이 아닙니다. 이 게임을 할 때는 조심해야 합니다. 전체 구조물이 무너지지 않도록 블록을 조심스럽게 추가하고 제거해야 합니다.
Don’t play Jenga with software. suppose block of Jenga is a new feature or component(whatever you want to call) of software. you should not be afraid to add or remove blocks from the software.
소프트웨어와 함께 젠가를 하지 마세요. 젠가의 블록이 소프트웨어의 새로운 기능이나 구성 요소(원하는 대로 부르세요)라고 가정해 보세요. 소프트웨어에서 블록을 추가하거나 제거하는 것을 두려워해서는 안 됩니다.
it should not be like that if a block removed(or add) the whole software gets collapsed. software should have the flexibility to stand strong(easily maintainable) & extendable(add any feature) to any limit.
블록이 제거되거나 추가되면 전체 소프트웨어가 무너져서는 안 됩니다. 소프트웨어는 강력하게 유지될 수 있는 유연성과 무한히 확장 가능한 기능을 가져야 합니다.
the individual block should not be tightly dependent on each other any kind of change in one block should not impact another block.
개별 블록은 서로 긴밀하게 의존해서는 안 되며, 한 블록의 어떤 변화도 다른 블록에 영향을 미쳐서는 안 됩니다.
SOLID principles were first introduced by Robert J. martin also known as Uncle BOB. he is also the author of the famous book clean code, clean architecture(go and read). I encouraged every software developer to read it.
SOLID 원칙은 로버트 J. 마틴(일명 Uncle BOB)에 의해 처음 소개되었습니다. 그는 유명한 책인 "클린 코드", "클린 아키텍처"의 저자이기도 합니다(가서 읽어보세요). 저는 모든 소프트웨어 개발자에게 이 책을 읽어보라고 권장합니다.
The SOLID principle's purpose is simple it is a set of practices. you follow the practice to develop software simple (break complexity into simplicity), easy to maintain & extendable with time.
SOLID 원칙의 목적은 간단합니다. 그것은 일련의 관행입니다. 이 관행을 따르면서 소프트웨어를 개발하면 복잡성을 단순성으로 나누어 간단하고, 유지 관리가 용이하며, 시간이 지남에 따라 확장 가능하게 됩니다.
Note: it is a common simple definition you can get from anywhere around the web. but don’t think if you read the principle you can develop the software easily like that.
참고: 이것은 웹 어디에서나 얻을 수 있는 일반적인 간단한 정의입니다. 하지만 원칙을 읽었다고 해서 그렇게 쉽게 소프트웨어를 개발할 수 있다고 생각하지 마세요.
see anyone can read and remember the theory part. do you think just knowing principles theoretically will make you a great software developer(don’t daydream)? it is not a viva test that you can learn one night ago and brag in front of a teacher to prove you are smart af.
누구나 이론 부분을 읽고 기억할 수 있습니다. 이론적으로 원칙을 아는 것만으로 훌륭한 소프트웨어 개발자가 될 수 있다고 생각하나요(망상하지 마세요)? 그것은 당신이 하룻밤 만에 배워서 선생님 앞에서 똑똑하다고 자랑할 수 있는 구술 시험이 아닙니다.
Only from constant practice (daily), you can truly implement principles. It is a practice recommended by professionals from their years of experience(it saves your ass).
오직 지속적인 연습(매일)만이 원칙을 진정으로 구현할 수 있습니다. 이는 전문가들이 그들의 수년간의 경험에서 추천하는 연습입니다(당신을 구해줍니다).
while working you need to implement it daily to truly understand it. don’t write code just to complete the functionality. completion of a feature is an easy task(they give it because you can complete it) real work start after that. it is the nature of work(practices means) that you need to implement inside.
작업을 하면서 매일 그것을 구현해야 진정으로 이해할 수 있습니다. 기능을 완성하기 위해 코드를 작성하지 마십시오. 기능의 완성은 쉬운 작업입니다(그것은 당신이 완료할 수 있기 때문에 주어집니다). 진짜 작업은 그 이후에 시작됩니다. 그것은 당신이 내부에서 구현해야 하는 작업의 본질입니다(관행을 의미합니다).
Think about the rocket scientist. Maybe he has read a lot of theory and believes can make a great rocket. but what is the benefit if hasn’t contributed to the development of the single rocket? is he really a rocket scientist. real work applies to the world not in dreams.
로켓 과학자를 생각해 보세요. 아마 그는 많은 이론을 읽었고 훌륭한 로켓을 만들 수 있다고 믿고 있을 것입니다. 하지만 그가 단 하나의 로켓 개발에 기여하지 않았다면 그게 무슨 소용이 있을까요? 그는 정말 로켓 과학자인가요? 진정한 작업은 꿈이 아닌 현실 세계에 적용됩니다.
SOLID stands for SOLID는 다음을 의미합니다
S: Single Responsibility Principle
O: Open-Closed Principle
L: Liskov Substitution Principle
I: Interface Segregation Principle
D: Dependency Inversion Principle
S: 단일 책임 원칙 O: 개방-폐쇄 원칙 L: 리스코프 치환 원칙 I: 인터페이스 분리 원칙 D: 의존성 역전 원칙
Single Responsibility Principle
단일 책임 원칙
To put simply “Do one thing and do it well” is the single responsibility principle.
간단히 말하면 "한 가지 일을 하고 잘하라"는 단일 책임 원칙입니다.
Whether you make method, service class or component rule is simple and straightforward, it should do only and only one thing. don’t complicate code by mixing things. actually in the coding world multitasking is bad.
메서드, 서비스 클래스 또는 컴포넌트를 만들든 규칙은 간단하고 명확합니다. 그것은 오직 하나의 일만 해야 합니다. 혼합하여 코드를 복잡하게 만들지 마십시오. 실제로 코딩 세계에서 멀티태스킹은 나쁩니다.
let’s take a very simple example to understand it.
이해를 돕기 위해 아주 간단한 예를 들어보겠습니다.
void createBook() {
// logic to create book
Book book = new Book();
book.setName(“bla bla bla”);
book.setprice(“bla bla bla”);
……..
// logic to create author of book
Author author = new Author();
author.setName(“bla bla bla”);
author.setNumberOfPublications(“bla bla bla bla”);
………
// logic to creat publication of book
Publication publi = new Publication();
publi.setName(“bla bla bla”);
…….
book.setAuthor(author);
book.publication(publi);
}
The above method is creating a new book and it involves the creation of the author and publication of the book also.
위의 방법은 새로운 책을 생성하는 것이며, 여기에는 저자와 책의 출판도 포함됩니다.
Now take a minute to think and answer what is wrong in code(not asking for any error exists). is it a good code or my work is completed?
이제 잠시 생각해보고 코드에서 무엇이 잘못되었는지 대답해 보세요(어떤 오류가 존재하는지 묻는 것이 아닙니다). 이것이 좋은 코드인가요, 아니면 제 작업이 완료된 건가요?
The above method clearly violating the single responsibility principle. it is doing a lot of things creating the book, author, and publication. now imagine you want to add new data for the book later in the future like the number of users, pages, calculate profit, etc will change the same method every time. it will impact the existing functionality and clearly, it is not extendible.
위의 방법은 명확하게 단일 책임 원칙을 위반하고 있습니다. 이 방법은 책, 저자 및 출판물을 생성하는 많은 작업을 수행하고 있습니다. 이제 나중에 책에 대한 새로운 데이터를 추가하고 싶다고 상상해 보십시오. 예를 들어 사용자 수, 페이지 수, 이익 계산 등을 추가하면 매번 같은 방법을 변경해야 합니다. 이는 기존 기능에 영향을 미치고 명백히 확장할 수 없습니다.
so it must do only one thing let’s rewrite it again.
그래서 그것은 오직 한 가지만 해야 합니다. 다시 작성해 봅시다.
void createBook() {
// logic to create book
Book book = new Book();
book.setName(“bla bla bla”);
book.setprice(“bla bla bla”);
......
book.setAuthor(createAuthor());
book.publication(createPublication());
}
Author createAuthor() {
// logic to create author of book
Author author = new Author();
author.setName(“bla bla bla”);
author.setNumberOfPublications(“bla bla bla bla”);
………
return author;
}
Publication createPublication() {
// logic to creat publication of book
Publication publi = new Publication();
publi.setName(“bla bla bla”);
…….
return publi;
}
Now it is better every method has a single responsibility. creating the book, author, and publication. later if want to do a change on the author we only need to work on the author method or we need to add a new feature to the book we can add a new method and can associate the feature(extendible).
이제 모든 메서드가 단일 책임을 갖는 것이 더 좋습니다. 책, 저자 및 출판물을 생성합니다. 나중에 저자에 대한 변경을 원할 경우 저자 메서드에서만 작업하면 되며, 책에 새로운 기능을 추가해야 할 경우 새로운 메서드를 추가하고 기능을 연관시킬 수 있습니다(확장 가능).
if you have observed it looks cleaner and readable.
더 깔끔하고 읽기 쉬워 보인다면.
let’s take one more example (i want to explain more even if you are bored).
하나의 예를 더 들어보겠습니다 (당신이 지루하더라도 더 설명하고 싶습니다).
checkout this service interface.
public Interface Employee {
Employee createEmployee();
Employee getEmployee();
Manager getEmployeeManager();
String getEmployeeManagerName();
Department getEmployeeDepartment();
void assignEmployeeDepartment();
}
Anything wrong in this huh think think think think ?
이거 잘못된 거 있어? 생각 생각 생각 생각?
Employee Interface is doing a hell lot of things it is managing employees, managers, and departments. Think about the implementation class when it is managing all those unrelated purposes. it creates a lot of dependency within code hence it is not extendible, or manageable.
직원 인터페이스는 직원, 관리자 및 부서를 관리하는 많은 일을 하고 있습니다. 관련 없는 모든 목적을 관리할 때 구현 클래스를 생각해 보십시오. 이는 코드 내에서 많은 의존성을 생성하므로 확장 가능하거나 관리할 수 없습니다.
Simply think Employee, manager, and department all are an independent entity. why do they need to depend on each other? they should not directly access each other without abstraction.
단순히 직원, 관리자 및 부서는 모두 독립적인 엔티티라고 생각하십시오. 그들은 왜 서로 의존해야 합니까? 그들은 추상화 없이 서로를 직접 접근해서는 안 됩니다.
it is clearly violating the single responsibility principle which everyone is meant for doing one and only one thing.
이는 모든 사람이 하나의 일만 하도록 되어 있는 단일 책임 원칙을 명백히 위반하고 있다.
let’s rework it a little bit. let's break the single service into many services. (divide and conquer)
조금 수정해봅시다. 단일 서비스를 여러 서비스로 나눕시다. (분할 정복)
public Interface Employee {
Employee createEmployee();
Employee getEmployee();
}
public Interface Manager {
Employee getEmployeeManager();
String getEmployeeManagerName();
}
public Interface Department {
Department getEmployeeDepartment();
void assignEmployeeDepartment();
}
Now we have a separation of concern each thing meant for doing one thing. Department code change won’t affect the employee or manager (independent of each other). all depend on each other through abstraction and totally unaware of what is happening behind the curtain?
이제 우리는 각 사안이 하나의 일을 수행하기 위한 분리를 가지고 있습니다. 부서 코드 변경은 직원이나 관리자에게 영향을 미치지 않습니다(서로 독립적입니다). 모든 것은 추상화를 통해 서로 의존하며, 커튼 뒤에서 무슨 일이 일어나고 있는지 전혀 알지 못합니다.
I have given a very simple example that is easy to understand but the principle is relevant from the method, class up to service, component level. Take it as a rule that applied even to smaller blocks as well as bigger blocks (made up of smaller blocks). so every method, class, service interface, component, etc should always try to do only and only one thing. remove dependency as much as you can to make it maintainable and extendible.
나는 이해하기 쉬운 매우 간단한 예를 제시했지만, 이 원칙은 메서드, 클래스에서 서비스, 컴포넌트 수준까지 관련이 있다. 더 작은 블록뿐만 아니라 더 큰 블록(더 작은 블록으로 구성된)에도 적용되는 규칙으로 받아들여라. 따라서 모든 메서드, 클래스, 서비스 인터페이스, 컴포넌트 등은 항상 오직 하나의 일만 하도록 노력해야 한다. 유지 관리 가능하고 확장 가능하게 만들기 위해 가능한 한 의존성을 제거하라.
it is just a blog with a simple theory and example to truly implement it. you need to think a lot when you are writing code. it needs years of practice to write very good clean code but we can start trying now(there is no code that is perfect but it can be improved). the rule is simple don’t violate any principle and the result code will be clean.
그것은 단순한 이론과 예제를 통해 이를 진정으로 구현하는 블로그일 뿐입니다. 코드를 작성할 때는 많은 생각을 해야 합니다. 매우 좋은 깨끗한 코드를 작성하려면 수년간의 연습이 필요하지만 지금부터 시도할 수 있습니다(완벽한 코드는 없지만 개선할 수 있습니다). 규칙은 간단합니다. 어떤 원칙도 위반하지 않으면 결과 코드는 깨끗할 것입니다.
Open-Closed Principle 개방-폐쇄 원칙
As the name suggests the software entity(method, class, module anything) should be open for extension but closed for modification.
이름에서 알 수 있듯이 소프트웨어 엔티티(메서드, 클래스, 모듈 등)는 확장을 위해 열려 있어야 하지만 수정에는 닫혀 있어야 합니다.
Open closed is an important principle as it makes code extendible without changing existing code. the purpose is simply to add a lot of new features(code) without changing the existing code. Do you like to rewrite the code? once written the code we should not worry about changing later in the future when new code was written on top of that.
열린 닫힌 원칙은 기존 코드를 변경하지 않고 코드를 확장할 수 있게 해주기 때문에 중요한 원칙입니다. 목적은 기존 코드를 변경하지 않고 많은 새로운 기능(코드)을 추가하는 것입니다. 코드를 다시 작성하는 것을 좋아하나요? 한 번 작성한 코드는 나중에 새로운 코드가 그 위에 작성될 때 변경하는 것에 대해 걱정할 필요가 없습니다.
Let’s understand a simple example. you have the requirement to make a rectangle, circle, and calculation feature for the area.
간단한 예를 이해해 봅시다. 사각형, 원, 그리고 면적 계산 기능을 만들어야 하는 요구사항이 있습니다.
public class Rectangle {
Double length;
Double breadth;
}
public class Circle {
Double radious;
}
public class Area {
Double calculateArea(Object shape) {
Double result = 0.0;
//check class of object
if(shape.getClass() == Rectangle.class) {
Rectangle rect = (Rectangle)shape;
result = rect.length * rect.breadth;
} else if(shape.getClass() == Circle.class) {
Circle circle = (Circle)shape;
result = Math.pi * Math.pow(circle.radious, 2);
}
return result;
}
}
We have a Rectangle class with property length & breadth and a circle with radius Then we have an area class that calculates the area of the shape by checking its class.
우리는 길이와 너비 속성을 가진 Rectangle 클래스와 반지름이 있는 원을 가지고 있습니다. 그런 다음 우리는 모양의 클래스를 확인하여 면적을 계산하는 면적 클래스를 가지고 있습니다.
Many questions are popping in mind like What is wrong with the implementation? do I not need to change again in the future if a new requirement came? is it violates the Open-Closed principle? let’s check it.
많은 질문이 떠오릅니다. 구현에 무엇이 잘못되었나요? 새로운 요구 사항이 생기면 다시 변경할 필요가 없나요? 개방-폐쇄 원칙을 위반하나요? 확인해 봅시다.
Later if we want to add more shapes like triangle, square, hexagon, etc. what I need to do then? first I will create a new class with properties(triangle, square ……) then will add the calculation logic to the existing method of calculateArea it means the modification of existing code. so it violates the Open-Closed Principle (means we fail :( ). we should extend the code without touching it.
나중에 삼각형, 사각형, 육각형 등과 같은 더 많은 도형을 추가하고 싶다면, 그때 무엇을 해야 할까요? 먼저 속성(삼각형, 사각형 ……)이 있는 새 클래스를 만들고, 기존의 calculateArea 메서드에 계산 로직을 추가할 것입니다. 이는 기존 코드를 수정하는 것을 의미합니다. 그래서 개방-폐쇄 원칙을 위반하게 됩니다(즉, 우리는 실패합니다 :( ). 우리는 코드를 건드리지 않고 확장해야 합니다.
Let’s rewrite the code to make it extendible(think how you can improve it ? ).
코드를 확장 가능하게 만들기 위해 다시 작성해 봅시다(어떻게 개선할 수 있을지 생각해 보세요?).
if we have observed it we know rectangle, square are all shapes (let’s use inheritance), and later also in the future, we will add more shapes( still that will be a shape only). also, we need to calculate the area of shape so the area is common property in all of them. let’s redesign it.
우리가 그것을 관찰했다면 우리는 직사각형, 정사각형이 모두 도형임을 알고 있습니다(상속을 사용합시다). 그리고 나중에 미래에 더 많은 도형을 추가할 것입니다(여전히 그것은 도형일 뿐입니다). 또한, 우리는 도형의 면적을 계산해야 하므로 면적은 그들 모두의 공통 속성입니다. 다시 설계해 봅시다.
public Interface Shape {
void area();
}
public class Rectangle implements Shape {
Double length;
Double breadth;
Double area() {
return length * breadth;
}
}
public class Circle implements Shape {
Double radious;
Double area() {
return result = Math.pi * Math.pow(circle.radious, 2); // pi * r2
}
}
public class Area {
// passing parent class polymorphism
Double calculateArea(Shape shape) {
return shape.area();
}
}
Now we created an interface and defined the common property of all shape areas. then we are creating a separate class of different shapes and implementing the method to calculate area. Then we are using polymorphism to pass shape object and calling area method.
이제 우리는 인터페이스를 만들고 모든 도형 면적의 공통 속성을 정의했습니다. 그런 다음 우리는 서로 다른 도형의 별도 클래스를 만들고 면적을 계산하는 메서드를 구현하고 있습니다. 그런 다음 우리는 다형성을 사용하여 도형 객체를 전달하고 면적 메서드를 호출하고 있습니다.
Read it 10 times and think is it extendible? can I add new shapes without changing the existing code?
10번 읽고 확장 가능성이 있는지 생각해보세요. 기존 코드를 변경하지 않고 새로운 도형을 추가할 수 있나요?
if we have to add a triangle we just need to make a new class, implement parent interface Shape, and bingo it is done. no need to touch the existing code so means it becomes open for extension and closed for modification.
삼각형을 추가해야 한다면, 새로운 클래스를 만들고 부모 인터페이스인 Shape를 구현하기만 하면 됩니다. 그러면 끝입니다. 기존 코드를 건드릴 필요가 없으므로 확장에는 열려 있고 수정에는 닫혀 있게 됩니다.
Suppose you are creating a house you created ground floor so the first floor only extends the ground floor it doesn’t affect it right ? all floor is extendible you can add more without affecting other. think how much costly it can be when the top floor affects the ground floor? (fixing cost of that) software is also the same don’t be a bad architecture.
집을 짓고 있다고 가정해 보세요. 1층을 만들었으니 2층은 1층만 확장하면 되고, 1층에는 영향을 주지 않죠? 모든 층은 확장 가능하며 다른 층에 영향을 주지 않고 더 추가할 수 있습니다. 만약 최상층이 1층에 영향을 준다면 얼마나 비용이 많이 들까요? (수리 비용) 소프트웨어도 마찬가지입니다. 나쁜 아키텍처가 되지 마세요.
Liskov Substitution Principle
리스코프 치환 원칙
Liskov Principle (Source Wikipedia)
리스코프 원칙 (출처: 위키백과)
if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of the program (correctness, a task performed, etc.).
만약 S가 T의 하위 유형이라면, T 유형의 객체는 S 유형의 객체로 대체될 수 있습니다(즉, T 유형의 객체는 S의 하위 유형의 객체로 대체될 수 있습니다) 프로그램의 바람직한 속성(정확성, 수행된 작업 등)을 변경하지 않고도.
it is hard to understand this statement let’s put it in a simple definition.
이 진술을 이해하기 어렵기 때문에 간단한 정의로 정리해 보겠습니다.
All Parent class objects should be replaceable from any Subclass Objects without affecting the program.
모든 부모 클래스 객체는 프로그램에 영향을 주지 않고 모든 서브클래스 객체로 교체 가능해야 한다.
Holi Moli did you understood the statement? it’s simple every parent class object in the program should be replaceable with any of its own subclass object without affecting the program(didn’t break anything working same).
홀리 몰리, 당신은 그 문장을 이해했나요? 간단합니다. 프로그램의 모든 부모 클래스 객체는 프로그램에 영향을 주지 않고(작동하는 것을 깨뜨리지 않고) 자신의 하위 클래스 객체로 대체할 수 있어야 합니다.
why the hell this weird rule exist? it simply enforced the same behavior in a child as of parent. means you have the exact same behavior as your father. if someone replaces you with your father nobody will notice it.
왜 이 이상한 규칙이 존재하는 걸까요? 그것은 단순히 자녀에게 부모와 동일한 행동을 강요합니다. 즉, 당신은 아버지와 똑같은 행동을 하게 됩니다. 만약 누군가 당신을 아버지로 대체한다면 아무도 알아차리지 못할 것입니다.
Remember it is not the same object (inheritance hope you know about it). the subclass has its feature also. so basically subclass has all the features of the parent class(that’s why it is replaceable) and also its own feature.
기억하세요, 같은 객체가 아닙니다(상속에 대해 알고 있기를 바랍니다). 서브클래스는 자신의 특징도 가지고 있습니다. 기본적으로 서브클래스는 부모 클래스의 모든 특징(그래서 교체 가능함)과 자신의 특징을 가지고 있습니다.
now if you think about it you might argue. hey dude! I am using inheritance means automatically subclass is extending the whole object so why need principle? (one minute pause)
이제 생각해보면 당신은 이렇게 주장할 수 있습니다. 이봐, 친구! 나는 상속을 사용하고 있으니 자동으로 서브클래스가 전체 객체를 확장하고 있는데 왜 원칙이 필요하죠? (1분 정지)
When subclass extending parent class it automatically adds all the method and properties. but it can also override(public method) so the principle is to enforce that the behavior of a child should same as a parent.
부모 클래스를 확장하는 서브클래스는 자동으로 모든 메서드와 속성을 추가합니다. 그러나 공용 메서드를 재정의할 수도 있으므로 원칙은 자식의 동작이 부모와 동일해야 한다는 것입니다.
let’s try to understand with the example we can say every square is a rectangle?
모든 정사각형은 직사각형이라고 말할 수 있다고 가정해 보겠습니다
class Rectangle {
Double length;
Double breadth;
void setSide(Double length, Double breadth) {
this.length = length;
this.breadth = breadth;
} Double getArea() {
return this.length * this.breadth;
}
}//Every Square is Rectangle
class Square extends Rectangle{
@Override
void getArea(Double length, Double breadth) {
if(length != breadth) {
throw new Exception(“Not a Square”);
}
this.length = length;
this.breadth = length;
}
}class RectangleTest {
void calculateAreaTest(Rectangle r) {
r.setSide(2.0, 3.0); // exception will throw "Not a Square"
assert(r.getArea(), 6.0); // here also will fail for square
}
}public class Main {
public static void main(String[] args) {
Square square = new Square();
RectangleTest test = new RectangleTest();
test.calculateAreaTest(square);
}
}
Check the above code will it fail or run? We have created a rectangle class with length, breadth, and the method to calculate area. we know every square is a rectangle so override the existing method of setSide to enforce the side must be equal.
위 코드를 확인해 보세요. 실패할까요, 실행될까요? 우리는 길이와 너비가 있는 사각형 클래스를 만들었고, 면적을 계산하는 메서드를 만들었습니다. 모든 정사각형은 사각형이므로 setSide의 기존 메서드를 재정의하여 변의 길이가 같아야 함을 강제합니다.
Did it violate the Liskov principle (is Liskov happy )? Liskov said all parents must be substitutable from the child without affecting the program. we have a RectangleTest class that tests the area of the rectangle. But when we replace/pass the square it fails. means it affects the code when we substitute child so clearly it violates the Liskov principle.
리스코프 원칙을 위반했나요 (리스코프는 행복한가요)? 리스코프는 모든 부모는 프로그램에 영향을 주지 않고 자식으로 대체 가능해야 한다고 말했습니다. 우리는 사각형의 면적을 테스트하는 RectangleTest 클래스가 있습니다. 그러나 우리가 정사각형으로 교체/전달할 때 실패합니다. 이는 자식을 대체할 때 코드에 영향을 미친다는 것을 의미하므로 명백히 리스코프 원칙을 위반합니다.
We can say since it violates the Liskov principle so we should not do inheritance between rectangle and square because the behavior of rectangle is not replaceable with square.
우리는 이것이 리스코프 원칙을 위반하므로 사각형과 정사각형 간의 상속을 해서는 안 된다고 말할 수 있습니다. 왜냐하면 사각형의 동작은 정사각형으로 대체할 수 없기 때문입니다.
Let’s take another example.
또 다른 예를 들어보겠습니다.
Interface Animal {
void eat();
void sleep();
void bark();
void meow();
void play();
}Interface Dog extends Animal{
void bringNewspaper();
}Interface Cat extends Animal {
void doAllUselessThing(); //cat is stupid i don’t like
}
Check the code it violates the Liskov principle? can we replace all animal object with dog or cat? do it enforce the same behavior? simply no, because dogs don’t meowwww and cats don’t bark (I haven’t seen). surely it will fail when the dog tries to become a cat.
코드가 리스코프 원칙을 위반하는지 확인하세요. 모든 동물 객체를 개나 고양이로 교체할 수 있나요? 동일한 동작을 강제하나요? 간단히 말해, 아니요. 왜냐하면 개는 야옹거리지 않고 고양이는 짖지 않기 때문입니다(나는 본 적이 없습니다). 확실히 개가 고양이가 되려고 하면 실패할 것입니다.
now let’s rework it. 이제 다시 작업해 봅시다.
Interface Animal {
void eat();
void sleep();
void play();
}Interface Dog extends Animal{
void bark();
void bringNewspaper();
}Interface Cat extends Animal {
void meow();
void doAllUselessThing(); //cat is stupid i don’t like
}
We can say eat, sleep & play is a common behavior and all animal on the planet follow it. so it makes sense to enforce these behaviors on children. Dogs and cats also have their own feature. so when we replace the animal objects with dog or cat in code it doesn’t violate the principle since basic behavior is the same in all animals (eat, sleep or play) means it will not affect the code.
우리는 먹고, 자고, 노는 것이 일반적인 행동이며 지구상의 모든 동물이 이를 따른다고 말할 수 있습니다. 그래서 이러한 행동을 아이들에게 강요하는 것이 합리적입니다. 개와 고양이도 각자의 특징이 있습니다. 따라서 코드에서 동물 객체를 개나 고양이로 교체할 때 기본 행동이 모든 동물에서 동일하기 때문에 원칙을 위반하지 않습니다(먹고, 자고, 놀기) 이는 코드에 영향을 미치지 않을 것입니다.
Interface Segregation Principle
인터페이스 분리 원칙
The client should not depend on the feature of the interface that they don’t use.
클라이언트는 사용하지 않는 인터페이스의 기능에 의존해서는 안 된다.
Think when there is summer season and you go to an ice cream shop. you ordered your favorite vanilla ice cream (yummy) then the shopkeeper asked your name, mother name, father name then he told you to do 10 push-ups. you asked why the hell required these detail and 10 push-ups? I need damn simple ice cream.
여름철에 아이스크림 가게에 가는 상황을 생각해 보세요. 당신은 좋아하는 바닐라 아이스크림(맛있다)을 주문했습니다. 그러자 가게 주인이 당신의 이름, 어머니 이름, 아버지 이름을 물어보고 10개의 푸시업을 하라고 했습니다. 당신은 왜 이런 세부사항과 10개의 푸시업이 필요한지 물었습니다. 나는 그저 간단한 아이스크림이 필요할 뿐입니다.
He replied sir it is part of our service and mandatory for the client to do it.
그는 대답했습니다, "그것은 우리의 서비스의 일부이며 고객이 반드시 해야 하는 일입니다."
So the simple idea is the client should only depend on the feature that it uses. Customers only want to order ice cream not interested in doing push-ups or flip.
그래서 간단한 아이디어는 클라이언트가 사용하는 기능에만 의존해야 한다는 것입니다. 고객은 아이스크림을 주문하고 싶어할 뿐 푸시업이나 플립을 하는 데는 관심이 없습니다.
What is the interface? it is a 100 percent abstraction of implementation detail so outside nobody knew what is behind the curtain (do you know)?
인터페이스란 무엇인가? 그것은 구현 세부 사항의 100% 추상화로, 외부에서는 커튼 뒤에 무엇이 있는지 아무도 알지 못한다(너는 아는가)?
if you remember the single responsibility principle which states that everything is meant to do only one thing and it should do it well. interface segregation principle is also similar it enforced that interface should not be big means doing many things.
단일 책임 원칙을 기억한다면, 이는 모든 것이 오직 한 가지 일만 수행해야 하며 그 일을 잘 수행해야 한다고 말합니다. 인터페이스 분리 원칙도 유사하며, 인터페이스는 크지 않아야 하며 많은 일을 수행해서는 안 된다는 것을 강조합니다.
What is the problem with the big interface(big is better see hulk)? think when many classes are implementing the same interface. so classes should not be forced to implement the method that they don’t need. classes should only implement the method that they want to use. when checking a class you should not think about why this method is here?
큰 인터페이스의 문제는 무엇인가요(큰 것이 더 낫다는 것을 헐크에서 보세요)? 많은 클래스가 동일한 인터페이스를 구현할 때를 생각해 보세요. 따라서 클래스는 필요하지 않은 메서드를 구현하도록 강요받아서는 안 됩니다. 클래스는 사용하고자 하는 메서드만 구현해야 합니다. 클래스를 확인할 때 이 메서드가 왜 여기에 있는지에 대해 생각해서는 안 됩니다.
let’s take a simple example.
간단한 예를 들어보겠습니다.
Interface BankService {
void openAccount();
void checkAccountBalance();
void createLoan();
void payEmi();
}class AccountService implements BankService {
@Override
void openAccount() {
// logic to open account
}
@Override
void checkAccountBalance() {
// logic to check account balance
}
@Override
void createLoan() {
throw new Exception(“Unsupported Operation”);
}
@Override
void payEmi() {
throw new Exception(“Unsupported Operation”);
}
}class LoanService implements BankService {
@Override
void openAccount() {
throw new Exception(“Unsupported Operation”);
}
@Override
void checkAccountBalance() {
throw new Exception(“Unsupported Operation”);
}
@Override
void createLoan() {
// logic to create loan
}
@Override
void payEmi() {
// logic to pay emi
}
}
we have a BankService interface that provides a feature for account & loan management. we have two implementation classes for loan and account.
우리는 계좌 및 대출 관리를 위한 기능을 제공하는 BankService 인터페이스가 있습니다. 우리는 대출과 계좌에 대한 두 개의 구현 클래스를 가지고 있습니다.
so when they are implementing an interface they are forced to define the definition of the method. Loan Service doesn’t provide a loan, vice versa. so clearly we need to do that we don’t want to do. it is a violation of the principle that simply states implementation classes should not be forced to define methods they don't need.
그래서 그들이 인터페이스를 구현할 때, 메서드의 정의를 정의해야만 합니다. 대출 서비스는 대출을 제공하지 않으며, 그 반대도 마찬가지입니다. 따라서 우리는 원하지 않는 일을 해야 한다는 것이 분명합니다. 이는 구현 클래스가 필요하지 않은 메서드를 정의하도록 강요받아서는 안 된다는 원칙을 위반하는 것입니다.
To fix the above code we need two separate interfaces for account & loan because the implementation class serves a different purpose.
위 코드를 수정하기 위해서는 계좌와 대출을 위한 두 개의 별도 인터페이스가 필요합니다. 왜냐하면 구현 클래스가 다른 목적을 수행하기 때문입니다.
Let’s take another example
다른 예를 들어보겠습니다
Inteface ServiceABCD {
void A();
void B();
void C();
void D();
}class OperationA implements ServiceABCD {
@Override
void A() {
// perform operation A
}
@Override
void B() {
throw new Exception(“Unsupported Operation”);
}
@Override
void C() {
throw new Exception(“Unsupported Operation”);
}
@Override
void D() {
throw new Exception(“Unsupported Operation”);
}
}class OperationCD implements ServiceABCD {
@Override
void A() {
throw new Exception(“Unsupported Operation”);
}
@Override
void B() {
throw new Exception(“Unsupported Operation”);
}
@Override
void C() {
// perform operation C
}
@Override
void D() {
// perform operation D
}
}class OperationABCD implements ServiceABCD {
@Override
void A() {
// perform operation A
}
@Override
void B() {
// perform operation B
}
@Override
void C() {
// perform operation C
}
@Override
void D() {
// perform operation D
}
}
code is simple there is Interface ServiceABCD. OperationA class performs only operation A. OperationCD class perform operation C & D. OperationABCD class perform A, B, C & D.
코드는 간단합니다. 인터페이스 ServiceABCD가 있습니다. OperationA 클래스는 오직 A 작업만 수행합니다. OperationCD 클래스는 C 및 D 작업을 수행합니다. OperationABCD 클래스는 A, B, C 및 D를 수행합니다.
clearly, it is a violation of principle. we are throwing Exception(“Unsupported Operation”) for the operation that is not supported. but the question is can you fix the code?
명백히, 이는 원칙의 위반입니다. 지원되지 않는 작업에 대해 Exception(“지원되지 않는 작업”)을 던지고 있습니다. 하지만 질문은 코드를 수정할 수 있습니까?
Let’s rewrite it again 다시 작성해 보겠습니다
Interface ServiceA {
void A();
}Interface ServiceB {
void B();
}Interface ServiceCD {
void C();
void D();
}class OperationA implements ServiceA{
@Override
void A() {
// perform operation A
}
}class OperationCD implements ServiceCD {
@Override
void C() {
// perform operation C
}
@Override
void D() {
// perform operation D
}
}class OperationABCD implements ServiceA, ServiceB, ServiceCD {
@Override
void A() {
// perform operation A
}
@Override
void B() {
// perform operation B
}
@Override
void C() {
// perform operation C
}
@Override
void D() {
// perform operation D
}
}
now we broke the bigger interface into the smaller interface. so implementation classes only need to define what they meant for.
이제 우리는 더 큰 인터페이스를 더 작은 인터페이스로 나누었습니다. 따라서 구현 클래스는 자신이 의미하는 바만 정의하면 됩니다.
it helps to remove unwanted dependency that is not needed hence low maintenance. it improved readability a lot. by the only first look, you can know what purpose the interface is serving. we should avoid providing a big picture on a single screen. we should divide it into more small pictures that will easy to manage.
원하지 않는 의존성을 제거하는 데 도움이 되므로 유지 관리가 적습니다. 가독성이 많이 향상되었습니다. 처음 보기만으로도 인터페이스가 어떤 목적을 수행하는지 알 수 있습니다. 우리는 단일 화면에서 큰 그림을 제공하는 것을 피해야 합니다. 더 관리하기 쉬운 작은 그림으로 나누어야 합니다.
Divide and Conquer: this trick is classic, works everywhere. you already know how the British came to India and ruled us by divide and conquer(know from childhood story). they made our elders fool hahaha(don’t be serious).
분할 정복: 이 기법은 고전적이며 어디서나 통합니다. 당신은 이미 영국인들이 어떻게 인도에 와서 분할 정복으로 우리를 지배했는지 알고 있습니다(어린 시절 이야기에서 알게 되었습니다). 그들은 우리의 어른들을 속였습니다 하하하(진지하게 받아들이지 마세요).
let’s apply it to software development. we have a lot of feature sets. so instead of making single services doing many tasks (multitasking). we divide the feature into many small features. we can do it in the team without affecting each other work since all services are independent. it makes code manageable as well as readable. if something fails we know where to look since we already broke the whole picture into a much smaller picture. that makes code very easy to maintain.
소프트웨어 개발에 적용해 봅시다. 우리는 많은 기능 세트를 가지고 있습니다. 그래서 여러 작업을 수행하는 단일 서비스를 만드는 대신(멀티태스킹), 기능을 여러 개의 작은 기능으로 나눕니다. 모든 서비스가 독립적이기 때문에 서로의 작업에 영향을 주지 않고 팀 내에서 이를 수행할 수 있습니다. 이는 코드를 관리 가능하고 읽기 쉽게 만듭니다. 만약 어떤 것이 실패하면, 우리는 이미 전체 그림을 훨씬 더 작은 그림으로 나누었기 때문에 어디를 봐야 할지 알 수 있습니다. 이는 코드를 매우 쉽게 유지 관리할 수 있게 합니다.
You can rule the kingdom of software by dividing them into a small manageable independent component.
소프트웨어의 왕국을 작은 관리 가능한 독립 구성 요소로 나누어 지배할 수 있습니다.
Dependency Inversion Principle
의존성 역전 원칙
The principle states that all code dependency in the project should only be based on abstraction then concrete implementation.
원칙은 프로젝트의 모든 코드 의존성이 구체적인 구현이 아닌 추상화에 기반해야 한다고 명시합니다.
Let’s take a simple example electric socket in the house. the device is always independent of the electric socket means it can charge the mobile, laptop, connect tv, washing machine any electric device. we don’t have a socket in our house that only meant for one specific device. charging socket and devices are dependent on abstraction. As long as any device provides the implementation detail it will work. how simple is that to understand by real-world example?
집에 있는 간단한 예로 전기 소켓을 생각해 보겠습니다. 이 장치는 전기 소켓과 항상 독립적이며, 모바일, 노트북, TV, 세탁기 등 어떤 전기 장치도 충전할 수 있습니다. 우리 집에는 특정 장치만을 위해 만들어진 소켓이 없습니다. 충전 소켓과 장치는 추상화에 의존합니다. 어떤 장치가 구현 세부 사항을 제공하는 한 작동할 것입니다. 실제 세계의 예로 이해하기 얼마나 간단합니까?
we know abstraction means hiding implementation detail, concrete means when we show implementation detail.
우리는 추상화가 구현 세부 사항을 숨기는 것을 의미하고, 구체화는 구현 세부 사항을 보여줄 때를 의미한다는 것을 알고 있다.
The principle states that we should only use abstract classes or interfaces for dependency, not a concrete implementation. the reason is simple if the class has a dependency on another concrete implementation of the class. then code change in concreate class will affect the class that is referring it aren’t you agree?
이 원칙은 의존성을 위해 추상 클래스나 인터페이스만 사용해야 하며, 구체적인 구현은 사용하지 말아야 한다고 말합니다. 그 이유는 간단합니다. 만약 클래스가 다른 구체적인 클래스의 구현에 의존하고 있다면, 구체적인 클래스의 코드 변경이 그것을 참조하는 클래스에 영향을 미치게 됩니다. 동의하지 않으신가요?
another reason is when we are referring to one module in another. if we change the module code we don’t want other modules to recompiled dependency again. if one module is changed why the hell other dependent modules will recompile? it happens when you depend on the concrete implementation. using interfaces smartly will give the advantage to add code in class without affecting other modules. means you can add a lot of code without other modules even knowing about it.
또 다른 이유는 우리가 한 모듈을 다른 모듈에서 참조할 때입니다. 모듈 코드를 변경하면 다른 모듈이 다시 의존성을 재컴파일하지 않기를 원합니다. 하나의 모듈이 변경되면 왜 다른 의존 모듈이 재컴파일되어야 합니까? 이는 구체적인 구현에 의존할 때 발생합니다. 인터페이스를 스마트하게 사용하면 다른 모듈에 영향을 주지 않고 클래스에 코드를 추가할 수 있는 이점이 있습니다. 즉, 다른 모듈이 그것에 대해 알지 못한 채 많은 코드를 추가할 수 있습니다.
Note: 노트:
achieving 100% abstraction dependency not possible ex. String class is the concrete implementation so we depend on many concrete implementations. but these classes are very stable they don’t get change easily. depending on concrete implementation is a problem when things are changing frequently.
100% 추상화 의존성을 달성하는 것은 불가능하다. 예를 들어, String 클래스는 구체적인 구현이므로 우리는 많은 구체적인 구현에 의존한다. 하지만 이러한 클래스는 매우 안정적이며 쉽게 변경되지 않는다. 구체적인 구현에 의존하는 것은 상황이 자주 변할 때 문제가 된다.
if the concrete stable implementation that not going to change for a long time. obviously, we can use them since the whole purpose is that changing code should not affect.
만약 구체적인 안정적인 구현이 오랫동안 변경되지 않을 것이라면, 분명히 우리는 그것들을 사용할 수 있습니다. 전체 목적이 코드 변경이 영향을 미치지 않아야 하기 때문입니다.
abstraction should not depend on details. details should depend on abstraction.
추상화는 세부 사항에 의존해서는 안 된다. 세부 사항은 추상화에 의존해야 한다.
it is good if you are already understood the statement. just referring to abstract implementation is not enough. our abstraction should not depend on details means whenever implementation details change should not affect abstraction. then the whole point of principle is gone if it affects.
당신이 이미 그 진술을 이해하고 있다면 좋습니다. 추상 구현만 언급하는 것은 충분하지 않습니다. 우리의 추상화는 세부 사항에 의존해서는 안 되며, 구현 세부 사항이 변경될 때 추상화에 영향을 미치지 않아야 합니다. 만약 그것이 영향을 미친다면 원칙의 전체 의미가 사라집니다.
Abstraction detail should never change. first, we define abstraction then we do the implementation class. obviously, it makes sense abstraction should not depend on the concrete implementation. other modules using the abstraction should assume that it is not going to change(will not going to affect with change).
추상화 세부 사항은 절대 변경되어서는 안 됩니다. 먼저 우리는 추상화를 정의한 다음 구현 클래스를 만듭니다. 분명히, 추상화는 구체적인 구현에 의존해서는 안 됩니다. 추상화를 사용하는 다른 모듈은 그것이 변경되지 않을 것이라고 가정해야 합니다(변경에 영향을 받지 않을 것입니다).
we need to design code smartly so that we can use abstraction for referring and also the underlying change of concreate class is independent of abstraction. (how cool is that? ) if you do the change without affecting other nobody will get mad at you.
우리는 코드를 스마트하게 설계해야 하며, 이를 통해 추상화를 사용하여 참조할 수 있고 구체 클래스의 기본 변경이 추상화와 독립적이도록 해야 합니다. (얼마나 멋진가요?) 다른 사람에게 영향을 주지 않고 변경을 하면 아무도 당신에게 화를 내지 않을 것입니다.
Now let’s learn from the electric socket of your house. electric socket is independent of devices means you can use charging mobile, refrigerator, washing machine, etc.
이제 집의 전기 소켓에서 배워봅시다. 전기 소켓은 장치와 독립적이므로 휴대폰 충전기, 냉장고, 세탁기 등을 사용할 수 있습니다.
think electric socket as another module and devices are concrete implementations. How can we do that in software? the ability to inject different concrete implementations. this is only possible with abstraction means we can inject different classes implementing the same abstraction.
전기 소켓을 또 다른 모듈로 생각하고 장치들은 구체적인 구현체라고 할 수 있습니다. 소프트웨어에서 이를 어떻게 할 수 있을까요? 다양한 구체적인 구현체를 주입할 수 있는 능력입니다. 이는 추상화 덕분에 가능하며, 우리는 동일한 추상화를 구현하는 다양한 클래스를 주입할 수 있습니다.
Suppose there is an animal interface and we have many classes Dog, Cat, Lion, etc implementing the animal interface. now we can inject any class from abstraction. you want a dog then inject it or like a cat take it or want a lion why not? depending on abstraction gives us so many advantages.
동물 인터페이스가 있고 개, 고양이, 사자 등 여러 클래스가 이 동물 인터페이스를 구현한다고 가정해 보겠습니다. 이제 우리는 추상화에서 어떤 클래스든 주입할 수 있습니다. 개가 필요하면 주입하고, 고양이를 원하면 가져가고, 사자가 필요하면 왜 안 되겠습니까? 추상화에 따라 많은 이점을 제공합니다.
Enough theory let’s try the example.
이론은 충분하니 예제를 시도해 봅시다.
class LightBlub {
void on {
System.out.println(“Blub is on”);
}
void off {
System.out.println(“Blub is off”);
}
}class ElectricSocket {
Blub blub = new Blub(); // depend on blub
void switchOn() {
blub.on();
}
void switchoff() {
blub.off();
}
}
what is the problem with the above code? the first problem is ElectricSocket depends on the concrete implementation of LightBlub. so LightBlub method change will affect the ElectricSocket(if add the parameter in method).
위 코드의 문제는 무엇인가요? 첫 번째 문제는 ElectricSocket이 LightBlub의 구체적인 구현에 의존한다는 것입니다. 따라서 LightBlub 메서드가 변경되면 ElectricSocket에 영향을 미칩니다(메서드에 매개변수를 추가하는 경우).
the second problem is ElectricSocket can only perform the operation on LightBlub what if I need the fan, refrigerator, or washing machine? then I need to again reference the object. in technical terms, it is tightly coupled we need to make it loosely coupled.
두 번째 문제는 ElectricSocket이 LightBulb에서만 작업을 수행할 수 있다는 것입니다. 만약 내가 선풍기, 냉장고 또는 세탁기가 필요하다면? 그러면 나는 다시 객체를 참조해야 합니다. 기술적인 용어로, 이것은 강하게 결합되어 있습니다. 우리는 이를 느슨하게 결합해야 합니다.
Now let’s refactor the code.
이제 코드를 리팩토링합시다.
Interface ElectricDevice {
void on();
void off();
}class ElectricBlub implements ElectricDevice{
void on {
System.out.println(“Blub is on”);
}
void off {
System.out.println(“Blub is off”);
}
}class Fan implements ElectricDevice{
void on {
System.out.println(“Fan is on”);
}
void off {
System.out.println(“Fan is off”);
}
}class ElectricSocket {
ElectricDevice device;
ElectricSocket(ElectricDevice device) {
this.device = device; // lossely coupled pass any subclass
}
void switchOn() {
device.on();
}
void switchoff() {
device.off();
}
}
Now check loosely coupled code. now we depend on the abstract interface ElectricDevice that is implemented by any device like fan, electric blub, washing machine, etc. we can inject any device class through constructor during run time that makes it loosely coupled. so it is independent of concrete implementation by using abstraction and also loosely coupled to make it extendible. (wow)
이제 느슨하게 결합된 코드를 확인해 보세요. 이제 우리는 팬, 전구, 세탁기 등과 같은 모든 장치에 의해 구현된 추상 인터페이스인 ElectricDevice에 의존합니다. 우리는 실행 시간 동안 생성자를 통해 어떤 장치 클래스든 주입할 수 있어 느슨하게 결합됩니다. 따라서 추상을 사용하여 구체적인 구현에 독립적이며 확장 가능하도록 느슨하게 결합되어 있습니다. (와우)
Final Note: 최종 메모:
Time to end the blog(felt I have written enough). the beauty of the SOLID principle is it applies from small class to the whole project level. you can be a newbie software developer that manages class level code or senior developer or architecture of the system. doesn’t matter what position you are in? as long as you are designing code on any level SOLID principles still apply.
블로그를 마칠 시간입니다(충분히 썼다고 느낍니다). SOLID 원칙의 아름다움은 작은 클래스에서 전체 프로젝트 수준까지 적용된다는 것입니다. 클래스 수준 코드를 관리하는 초보 소프트웨어 개발자일 수도 있고, 시스템의 선임 개발자나 아키텍트일 수도 있습니다. 당신이 어떤 위치에 있든 상관없습니다. 어떤 수준에서든 코드를 설계하는 한 SOLID 원칙은 여전히 적용됩니다.
I am not saying that senior-level position design is also simple as junior level(no dumbo). my point is it follows the same fundamental. law of gravity is applied everywhere. somebody can build a space rocket or firecracker rocket. but still, gravity applied to both cases.
나는 고급 직위의 설계가 주니어 수준만큼 간단하다고 말하는 것이 아니다(바보는 아니다). 내 요점은 그것이 동일한 기본 원칙을 따른다는 것이다. 중력의 법칙은 어디에나 적용된다. 누군가는 우주 로켓이나 폭죽 로켓을 만들 수 있다. 하지만 여전히 두 경우 모두 중력이 적용된다.
at the junior level, since you are only looking at few classes (small code base) it is good to practice these principles. did my written code follow best practice? what I am doing wrong? it is ok to make mistake in that position. it doesn't matter if you experiment with something. you already have the senior people to review it.
주니어 수준에서는 몇 개의 클래스(작은 코드베이스)만 보고 있기 때문에 이러한 원칙을 연습하는 것이 좋습니다. 내가 작성한 코드는 모범 사례를 따랐나요? 내가 잘못하고 있는 것은 무엇인가요? 그 위치에서는 실수를 해도 괜찮습니다. 무언가를 실험해도 상관없습니다. 이미 시니어들이 그것을 검토해 줄 것입니다.
This principle is not learned overnight nobody can know football by reading theory about it. it needs daily practice. at the higher position (senior developer or something higher not talking about god) nobody guides you(who is the reviewer of god work?). so if you haven’t followed the best coding practices from starting then that senior guy is devil.
이 원칙은 하룻밤 사이에 배울 수 있는 것이 아니다. 누구도 이론을 읽는 것만으로 축구를 알 수 없다. 매일 연습이 필요하다. 더 높은 직위(선임 개발자 또는 그보다 높은 직위, 신에 대해 이야기하는 것이 아님)에서는 아무도 당신을 안내하지 않는다(신의 작업을 검토하는 사람은 누구인가?). 따라서 처음부터 최상의 코딩 관행을 따르지 않았다면 그 선임자는 악마이다.
The newbie can do a lot of mistakes in designing code as it not involve much cost or effort (time is money). but if some seniors follow poor design OH MY GOD! who is going to tell they are doing wrong? imagine the cost of doing a mistake on a higher level?
초보자는 코드를 설계할 때 많은 실수를 할 수 있습니다. 왜냐하면 큰 비용이나 노력이 들지 않기 때문입니다(시간은 돈입니다). 하지만 만약 몇몇 선배들이 잘못된 설계를 따른다면, 오 마이 갓! 누가 그들이 잘못하고 있다고 말해줄까요? 더 높은 수준에서 실수를 하는 비용을 상상해 보세요.