소개
객체지향 설계와 도메인-주도 설계에 관심이 많으며 행복한 팀과 깔끔한 코드, 존중과 협력이 훌륭한 소프트웨어를 낳는다는 믿음을 가지고 있는 평범한 개발자입니다. 개발자, 교육자, 관리자를 오가며 익힌 다양한 경험을 바탕으로 좋은 코드와 함께 좋은 프로덕트를 만들기 위해 노력하고 있습니다.
저서로는 『객체지향의 사실과 오해』와 『오브젝트』가 있고 번역서로는 『엘레강트 오브젝트』가 있으며 『만들면서 배우는 클린 아키텍처』에 감수자로 참여했습니다.
💡개인블로그 : https://eternity-object.tistory.com/
강의
전체1수강평
- 정말 좋은강의 감사합니다
dgpark
2024.09.12
1
- 백엔드개발자의 필수 코스입니다.
niceview.love
2024.09.09
1
- 정말 피가 되고 살이 되는 소중한 강의 감사합니다!
Jacoba
2024.09.05
1
게시글
질문&답변
2024.09.13
2-4 강에서 제공된 수업 노트 관련 질문 드려요
Tai Sun Park님 안녕하세요. 🙂 리팩토링을 하기 전의 코드는 '2-1 절차적인 설계'의 수업 노트에 github 주소가 적혀있습니다. https://github.com/eternity-oop/object-basic-02-01 해당 코드를 fork하셔서 연습하시면 될것 같습니다. 혹시라도 필요하신 예제가 위 코드가 아니면 다시 요청 남겨 주세요. 행복한 추석 연휴 보내시고요. 감사합니다. 🙂
- 0
- 2
- 21
질문&답변
2024.08.31
[6-2] 응집도의 변경 관점에서, [속도] 관련
김지환님 안녕하세요. 속도는 변경의 빈도라고 이해하시면 됩니다. 예를 들어서 하나의 클래스 안에 A와 B라는 변경이 공존하고 있다고 해보겠습니다. A가 한달에 한번 1일에 변경이 일어나고 B가 한달에 두 번 1일과 15일에 변경이 일어난다고 가정해 보겠습니다. A와 B는 매월 1일 같은 시점에 변경되지만 A가 한달 주기로 변경되는데 비해 B는 15일 주기로 변경되기 때문에 결과적으로 A는 변경되지 않지만 B는 변경되는 상황이 발생합니다. 따라서 A와 B는 같은 시점에 변경이 일어나지만 서로 다른 주기로 변경이 일어나기 때문에(즉, 변경의 속도가 다르기 때문에) 서로 다른 클래스로 분리되어야 합니다. '동일 시점에 동일한 속도'라는 말을 동일한 주기로 함께 변경되는 코드 집합이라고 이해하시면 될 것 같아요. 감사합니다. 🙂
- 0
- 2
- 61
질문&답변
2024.08.28
객체 지향 설계 첫번째 원칙
코딩천국님 안녕하세요. 🙂 책보다 더 쉽게 이해하실 수 있도록 강의를 구성했는데 도움이 되신다니 다행이네요. 강의 들어주셔서 감사드리고 궁금한 부분 있으면 그때그때 질문 주시면 최대한 빠르게 답변드릴게요. '객체를 선택하기 전에 요청을 결정하기 때문에 코드를 수정하지 않고도 협력하는 객체를 교체할 수 있게 해준다'라는 문장을 두 개로 나눠서 답변드릴게요. 먼저 '객체를 선택하기 전에 요청을 결정한다'라는 말은 질문에 남겨주신 'calculateDiscount 행동을 먼저 정하고 이 행동을 하기에 적합한 객체를 선택한다'라는 말과 같은 의미입니다. 책임 주도 설계에서는 메시지 전송자가 협력을 위해 'calculateDiscount'를 요청할 필요가 있다는 사실(다시 말해서 메시지를 전송할 필요)을 결정한 후에 이 요청을 수행하기에 적합한 객체를 선택합니다. 결과적으로 메시지 수신자의 입장에서는 calculateDiscount라는 행동을 먼저 결정한 후에 객체를 결정하게 되는 것이죠. 아마 궁금한 부분은 '코드를 수정하지 않고도 협력하는 객체를 교체할 수 있게 해준다'라는 부분일것 같은데 이것은 바로 앞에서 설명한 '요청을 결정한 후에 객체를 선택'하기 때문에 가능한 일입니다. 요청(메시지, 행동)를 결정한 후 객체를 선택했기 때문에 메시지 전송자는 calculateDiscount 요청에 따라 적합한 행동을 제공할 수 있는 객체라면 누구와도 협력이 가능하게 됩니다. 다시 말해서 calculateDiscount라는 행동을 제공할 수 있는 객체라면 협력에 참여할 수 있기 때문에 '협력하는 객체를 교체'할 수 있는 것입니다. 일단 객체를 교체할 수 있도록 협력을 구성한 후에는 실제로 코드 레벨에서 객체를 교체할 수 있도록 구조를 만들 필요가 있습니다. 이 방법은 강의에서 아래 부분에 상세한 내용이 정리되어 있기 때문에 강의를 보시고나면 아주 쉽게 이해가 되실거에요. 5-2 메시지와 메서드의 분리 5-3 유연하고 일관적인 협력 답변이 되었는지 모르겠네요. 🙂
- 0
- 2
- 67
질문&답변
2024.08.23
객체 협력, 클래스구조와 런타임, 컴파일타임의 관계
꼬꼬록님 안녕하세요. 🙂 강의가 도움이 된다니 정말 다행이네요. 말씀 듣고나니 컴파일타임과 런타임이라는 용어에 대해 오브젝트 책에서는 간략히나마 설명해 놓았었는데 강의에서는 충분히 설명드리지 못했다는 생각이 드네요. 오브젝트 책 257페이지의 내용을 인용하도록 하겠습니다. 의존성과 관련해서 다루어야 하는 또 다른 주제는 런타임 의존성(run-time dependency) 과 컴파일타임 의존성(compile-time dependency) 의 차이다. 먼저 여기에서 사용하는 런타임과 컴파일타임의 의미를 이해할 필요가 있다. 런타임 은 간단하다. 말 그대로 애플리케이션이 실행되는 시점을 가리킨다. 컴파일타임은 약간 미묘하다. 일반적으로 컴파일타임 이란 작성된 코드를 컴파일하는 시점을 가리지키지만 문맥에 따라서는 코드 그 자체를 가리키기도 한다. 컴파일 타임 의존성이 바로 이런 경우에 해당한다. 컴파일타임 의존성이라는 용어가 중요하게 생각하는 것은 시간이 아니라 우리가 작성한 코드의 구조이기 때문이다. 또한 동적 타입 언어의 경우에는 컴파일 타임이 존재하지 않기 때문에 컴파일 타임 의존성이라는 용어를 실제로 컴파일이 수행되는 시점으로 이해하면 의미가 모호해질 수 있다. 따라서 어딘가에서 컴파일타임이라는 용어를 보게된다면 그것이 정말 컴파일이 진행되는 시점을 가리키는 것인지 아니면 코드를 작성하는 시점을 가리키는 것인지를 파악하는 것이 중요하다. 객체지향 애플리케이션에서 런타임 의 주인공은 객체 다 . 따라서 런타임 의존성이 다루는 주제는 객체 사이의 의존성이다. 반면에 코드 관점에서 주인공은 클래스 다. 따라서 컴파일타임 의존성이 다루는 주제는 클래스 사이의 의존성이다. 질문해 주신 ' 객체 협력(런타임)에서 클래스 구조(컴파일타임)의 순서로 진행 '은 말 그대로 런타임의 구조를 먼저 고민한 이후에 런타임 구조에 맞는 컴파일타임 구조를 설계해야 한다는 말입니다. 객체지향에서 런타임 구성 요소는 객체이고 (클래스 기반의 객체지향 언어의 경우) 컴파일타임 구성 요소(즉, 코드의 단위)는 클래스이기 때문에 객체의 구조와 객체 사이의 협력 관계를 먼저 결정한 후에 클래스 내부와 클래스 사이의 관계를 설계해야 한다고 이해하시면 됩니다. 답변이 되었는지 모르겠네요. 🙂
- 1
- 1
- 104
질문&답변
2024.08.18
DIP vs OCP
김민정님 안녕하세요. 궁금하신 부분에 대해 좀 더 부연 설명드리도록 하겠습니다. 🙂 의존성 역전 원칙(Dependency Inversion Priciple, DIP) 는 다음과 같이 정리할 수 있습니다. a. 상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안된다. 둘 모두 추상화에 의존해야 한다. b. 추상화는 구체적인 사항에 의존해서는 안 된다. 구체적인 사항은 추상화에 의존해야 한다. DIP의 목적은 상위 수준의 중요한 정책이 하위 수준의 메커니즘에 의해 영향을 받지 않도록 만드는 것입니다. 여기에서 상위 수준의 정책을 객체 사이의 협력으로 생각하셔도 무방합니다. 해당 질문에서 ReservationService가 CustomerDAO를 이용해서 데이터를 조회한다는 것은 상위 수준의 정책입니다. (사진) 데이터베이스에서 Customer를 어떻게 쿼리하는지를 구현한 CustomerJdbcDAO는 세부사항입니다. 이 세부사항이 변경되더라도 ReservationService가 CustomerDAO와 협력해서 데이터를 조회하는 상위 수준의 협력은 영향을 받지 말아야 합니다. 이런 이유로 ReservationService와 CustomerJdbcDAO 모두 추상화 인 CustomerDAO에 의존하도록 만든 것입니다. 여기에서 추상화 가 핵심인데 DIP는 자주 변하는 것이 아니라 자주 변하지 않는 안정적인 추상화에 의존하라고 가이드하고 있기 때문입니다. 간단히 말해서 DIP는 중요하지 않은 세부사항의 변경으로 인해 중요한 상위 정책이 영향을 받지 않도록 추상화에 의존하도록 의존성을 제어하는 원칙입니다. 개방 폐쇄 원칙(Open-Closded Principle, OCP) 은 다음과 같이 정리할 수 있습니다. 소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다. OCP는 유연한 설계란 기존 코드를 수정하지 않고도 기능을 확장할 수 있어야 한다고 이야기합니다. OCP의 목적은 코드를 수정하지 않고도 다양한 환경에서 코드를 재사용할 수 있도록 만드는 것입니다. 어떤 메커니즘을 사용하건 이 목적을 만족할 수만 있다면 개방 폐쇄 원칙을 만족한다고 할 수 있습니다. 객체지향에서 OCP를 만족시키는 가장 일반적인 방법은 다형성을 사용하는 것입니다. 일반적으로 다형성을 이용해서 OCP를 만족시키기 위해서는 DIP와 LSP(Liskov Substitution Principle)를 조합해서 코드를 작성합니다. 강의에서도 이 방식을 소개하고 있기 때문에 DIP와 OCP가 혼란스럽게 느껴지신것 같습니다. DIP를 적용했다고 해서 OCP가 보장되는 것은 아니기 때문입니다. 하지만 다형성을 통해 OCP를 달성하기 위해서는 기반 구조에 DIP를 적용할 필요는 있습니다. OCP를 만족시키는 방법이 다형성만 있는 것은 아닙니다. 예를 들어 변경사항을 외부의 데이터로 빼서 코드는 수정하지 않은채 데이터만 변경해서 애플리케이션의 행동을 확장하는 것도 OCP의 한가지 방법입니다(룰 엔진이나 게임에서 많이 사용됩니다). 아래 공유드리는 책에 OCP를 만족시키기 위해 데이터를 사용하는 설계의 예가 나옵니다. 정리하면 OCP는 기존 코드를 수정하지 않으면서 행동을 확장하는 원칙을 가리키며 DIP는세부사항의 변경에 의해 상위 정책이 영향을 받지 않도록 의존성을 제어하는 원칙입니다. 둘 모두 추상화에 의존한다는 공통점 이 있지만 의도는 조금 다릅니다. 흔히 OPC는 달성하려는 목적을, DIP는 이를 위한 메커니즘이라고 이야기 하기도 합니다. 더 상세한 내용이 궁금하시면 아래 책을 보시면 많은 도움이 되실 거에요. https://product.kyobobook.co.kr/detail/S000001875106 정리하면 질문에 적어주신 아래 내용이 다소 부정확하기는 하지만 어느 정도는 핵심을 짚으신 것이라고 할 수 있습니다. OCP는 다양한 DAO구현체를 제공하기 위한 것에 초점을 맞춘 것이고, DIP는 의존성을 끊기 위한 것에 초점을 맞춘 것이라고 이해하면 될까요 답변이 됐는지 모르겠네요. 🙂
- 2
- 1
- 155