일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 자바
- 커스텀상태
- mockito
- k8s
- 안드로이드강좌
- theming
- 알고리즘
- kotlin강좌
- Rxjava
- 안드로이드
- Gradle
- Kotlin
- 회고
- Coroutine
- 스레드
- ReactiveProgramming
- 글또
- Compose
- 코틀린
- 디자인패턴
- 병럴프로그래밍
- android
- 알게되는
- viewmodel
- g 단위테스트
- 안드로이드스튜디오
- 책
- 테스트
- 코루틴
- 병렬프로그래밍
- Today
- Total
선생님, 개발을 잘하고 싶어요.
[오브젝트] 챕터 9 - 유연한 설계 본문
설계가 유연하기 위해서는 의존성을 잘 다룰 수 있어야합니다.
설계가 유연하다는 건 새로운 기능을 추가하거나 제거할 때 큰 비용이 들지 않는 다는 걸 의미합니다.
의존성은 변화의 가능성을 의미합니다. 의존하고 있는 대상이 변경되면 그 변경의 여파가 의존하는 대상에게 까지 미친다는 뜻입니다.
전체 프로젝트를 몰아치는 변화는 큰 비용입니다. 그러니 작은 비용으로 수정을 하고 싶다면 변화와 관련된 의존성을 격리하는 것 부터 시작해야합니다.
그래서 이번 챕터는 주로 의존성에 대한 이야기를 합니다. 우리가 익히 들어 알고있는 OCP에 대한 이야기도 나오게 됩니다.
OCP는 코드 수정에는 닫혀있고 기능 확장에는 열린 코드가 좋은 코드라고 말합니다.
컴파일타임 의존성과 런타임 의존성의 차이를 이해하게 되면서 이 문장이 좀 더 와닿게 되는 것 같습니다.
개인적으로 이번 챕터에서 느낀 점은 기존 나의 DI에 대한 몰이해 였습니다.
저는 DI는 생성자 호출과 같은 귀찮은 작업을 대신해주는 정도로 여겼습니다. 그리고 안드로이드 프로젝트에 적용하며 매우 제한적인 용례로만 사용한 것 같습니다. Repository 객체 생성 및 주입, Singleton 객체 생성 및 주입 등으로 말이죠.
이번 챕터에서는 생성과 사용을 분리하라는 얘기가 나옵니다. 제가 DI 없이 생성자를 각 코드에 작성했을 때 피봤던 내용이죠.
하지만 여기서 멈추지 않고 더 나아갑니다. 단순히 생성자를 통한 의존성 주입 뿐 아니라 setter, method의 인자로 넘겨서 주입하는 내용까지 다루게 됩니다.
그러면서 DI는 매우 제한적 용례에서 사용되는 기술이 아니고 객체지향 시스템을 설계하고 있다면, 그리고 충분히 유연한 설계를 달성하고 싶다면 활용할 수 있는 일종의 만능 헬퍼같은 느낌이였습니다.
그리고 이렇게 주입되는 객체들만 살피는 것으로 기능을 명세할 수 있다는 말에, Dagger의 Module을 일종의 기능 명세서 혹은 Configuration 처럼 바라보게 되는 것 같습니다.
또 이 책에서 마음에 드는 부분은 무턱대고 유연성을 추구했던 나같은 사람도 중심을 잡아주기 위해서 트레이드 오프를 꾸준히 강조한다는 점입니다.
유연성이 필요한 케이스는 다양한 Context에서 그 객체가 재활용 될 가능성이 있을 때 필요합니다. 당연하지요? 그렇다면 그 Context가 무엇인지 협력, 책임, 역할 차원에서 시스템 설계가 잘 되어있어야 함을 강조합니다. 그 전에 무비판적 의존성 해결은 무의미하다며 말이죠.
<aside> 💡 의존성 관리 기법 관련된 원칙 정리
</aside>
- 개방-폐쇄 원칙 (OCP)
- 동작 확장은 열려있다.
- 코드 수정은 닫혀있다.
- 컴파일타임 의존성을 고정시키고 런타임 의존성을 변경하라
- 둘은 동일하지 않다.
- OCP를 지킨 코드는 컴파일타임 의존성을 수정하지 않고 런타임 의존성을 쉽게 변경한다.
- 추상화가 핵심이다
- 추상화에 의존하는 것이 핵심
- 추상화 부분은 코드 수정에 대해 닫혀있다.
- 모든 요소가 추상화에 의존해야 수정에 대한 영향이 최소화된다.
- 챕터 8에서 사용한 기법을 활용해 행동을 확장할 수 있다.
- 생성 사용 분리
- 변화가 외부로 전파되지 않는 경우
- 메시지를 전송하지 않고 객체 생성만 한다면
- 객체 생성하지 않고 메시지를 전송하기만 했다면
- 객체 생성할 책임을 클라이언트로 옮기기
- Factory 추가하기
- 객체 생성과 관련된 책임만 전담하는 별도의 객체(Factory) 추가하고 Client가 이 객체를 사용
- 순수한 가공물에 책임 할당하기
- Factory 추가는 순수한 기술적 결정
- 도메인과 아무런 상관 없는 가공의 객체가 등장한다.
- 인공적으로 창조한 객체가 도메인 개념을 반영하는 객체보다 오히려 더 많은 비중을 차지하는 게 일반적
- </aside>
- 변화가 외부로 전파되지 않는 경우
- </aside>
- 의존성을 연결하는 시작 단계와
- 의존성 주입
- 객체 외부에서 인스턴스 생성 후 넘겨 의존성 해결하는 방법
- 숨겨진 의존성은 나쁘다
- 의존성 문제를 런타임으로 옮긴다.
- 의존성 대상 설정 시점과 해결 시점이 멀다.
- 의존성 역전 원칙
- 협력에서 중요한 정책 및 의사결정 → 상위 객체
- 구현 → 하위 객체
- 상위 객체가 하위 객체에 의존하면 골치아픔
- 구체 클래스는 의존성의 시작이라야 한다.
- 인터페이스 소유권도 역전
- 인터페이스 소유권을 서버가 아닌 클라이언트에 위치 시킨다.
- </aside>
- 유연성에 대한 조언
- 런타임과 컴파일타임 의존성 차이 인식 & 동일한 컴파일타임 의존성으로 부터 다양한 런타임 의존성을 만들 수 있는 코드
- 유연함 ↔ 단순함
- 설계가 유연할수록 클래스 구조와 런타임 구조 사이의 거리는 멀어진다.
- 변경이 필요한 경우만 유연성을 가져야한다.
- 정적인 프로그램과 동적인 프로세스 사이의 간극을 줄일 수록 이해하기 쉽다.
- 결국 협력과 책임이 중요하다.
- </aside>
- </aside>
- </aside>
'일상 > 책 리뷰' 카테고리의 다른 글
[오브젝트] 챕터 11 - 합성과 유연한 설계 (0) | 2022.03.20 |
---|---|
[오브젝트] 챕터 10 - 상속과 코드 재사용 (0) | 2022.03.19 |
[오브젝트] 챕터 8 - 의존성 관리하기 (0) | 2022.03.14 |
[오브젝트] 챕터 7 - 객체 분해 (0) | 2022.03.05 |
[오브젝트] 챕터 6 - 메시지와 인터페이스 (0) | 2022.03.05 |