설계나 코드 조직화와 관련된 몇가지 접근법계층 기반 패키지(수평적 계층화)기능 기반 패키지(수직적 계층화)포트와 어댑터컴포넌트 기반 패키지조직화 vs 캡슐화다른 결합 분리 모드(Gradle의 Multi Project Build같이)
이 장에서는 클린 아키텍처는 잠시 한쪽으로 제쳐 놓고, 설계나 코드 조직화와 관련된 몇 가지 접근법을 살펴보자.
설계나 코드 조직화와 관련된 몇가지 접근법
계층 기반 패키지(수평적 계층화)
- 가장 단순한 첫 번째 설계 방식은 전통적인 수평 계층형 아키텍처
- 이 아키텍처는 엄청난 복잡함을 겪지 않고도 무언가를 작동시켜 주는 아주 빠른 방법임
- 문제는 마틴이 지적했듯이 소프트웨어가 커지고 복잡해지기 시작하면 머지않아 큰 그릇 3개만으로는 모든 코드를 담기엔 부족하다는 사실을 깨닫고, 더 잘게 모듈화해야 할지를 고민하게 될 것
- 또한 계층형 아키텍처는 업무 도메인에 대해 아무것도 말해주지 않는다는 문제도 있음
단점
- 구현 관점에서 보면 각 계층은 일반적으로 자바 패키지에 해당한다. 코드의 접근성 관점에서 OrdersController가 OrdersService 인터페이스에 의존하려면 OrdersService 인터페이스는 반드시 public 으로 선언되어야 하는데, 두 인터페이스는 서로 다른 패키지에 속하기 때문.
- 비순환 의존성 그래프가 그려질 것이라고 생각하지만, 일부 개발자의 실수로 의존성이 건너뛰게 되면 보기에는 여전히 좋은 비순환 의존성 그래프가 생성된다는 사실.
- 정적 빌드 도구로 강제하는 방법이 있음 → 그러나 이는 그 결과를 알게 되는 주기가 필요 이상으로 길다는 문제가 있음
- 가능하면 컴파일러를 사용해서 아키텍처를 강제하는 방식을 선호(package private 등을 이용해서 아예 접근이 불가능하도록 하는)
기능 기반 패키지(수직적 계층화)
- 서로 연관된 기능, 도메인 개념 또는 Aggregate Root에 기반하여 수직의 얇은 조각으로 코드를 나누는 방식임
- Controller, Service, Repository가 모두 하나의 패키지에 속하게 된다. 이로써 코드의 상위 수준 구조가 업무 도메인에 대해 무언가를 알려주게 된다. 드디어 우리는 이 코드 베이스가 웹, 서비스, 리포지토리가 아니라 주문과 관련한 무언가를 한다는 걸 볼 수 있다.
포트와 어댑터
- 엉클 밥에 따르면 ‘포트와 어댑터’ 혹은 ‘육각형 아키텍처’, ‘경계, 컨트롤러, 엔티티’(BCE) 등의 방식으로 접근하는 이유는 업무/도메인에 대해 초점을 둔 코드가 프레임워크나 데이터베이스 같은 기술적인 세부 구현과 독립적이며 분리된 아키텍처를 만들기 위해서다.
- ‘내부’ 영역은 도메인 개념을 모두 포함하는 반면, ‘외부’영역은 외부세계와의 상호작용을 포함한다.
- 여기서 주요 규칙은 바로 ‘외부’가 ‘내부’에 의존하며, 절대 그 반대로는 안된다는 점
컴포넌트 기반 패키지
- 포트와 어댑터에서 웹을 그저 또 다른 전달 메커니즘으로 취급하는 것과 마찬가지로, 컴포넌트 기반 패키지에서도 사용자 인터페이스를 큰 단위의 컴포넌트로부터 분리해서 유지한다.
- Controller따로 그리고 업무로직, 영속성 관련 코드를 하나로 묶어서 컴포넌트로 이용
조직화 vs 캡슐화
- 만약 자바 애플리케이션에서 모든 타입을 public으로 지정한다면, 패키지는 단순히 조직화를 위한 메커니즘으로 전락하여 캡슐화를 위한 메커니즘이 될 수 없다.
- public 타입이 적으면 적을수록 필요한 의존성의 수도 적어진다. package private을 사용하면 패키지 외부의 코드에서는 해당 클래스를 직접 사용할 수 있는 방법이 전혀 없다. ⇒ 따라서 컴파일러의 도움을 받아 컴포넌트 기반 패키지 아키텍처 접근법을 강제할 수 있다.
다른 결합 분리 모드(Gradle의 Multi Project Build같이)
- 모듈 시스템을 제대로 사용하면 public으로 지정하더라도 그중 일부 타입만을 외부에서 사용할 수 있도록 공표할 수 있다.