보통 패키지 구조를 잡는 방법으로 다음 두 가지 방법을 사용하곤 합니다.

계층으로 구성하기

웹 계층, 도메인 계층, 영속성 계층을 각각 나누는 방법으로, 이렇게 하면 계층 간의 모든 의존성이 안쪽으로 향하게 한다는 클린 아키텍처의 규칙이 지켜집니다. 그러나 기능 조각이나 특성을 구분 짓는 패키지 경계가 없고, 애플리케이션이 어떤 유스 케이스들을 제공하는지 파악할 수 없고, 패키지 구조를 통해 목표로 하는 아키텍처를 파악할 수 없다는 단점들로 인해 최적의 구조라고 할 수 없습니다.

기능으로 구성하기

기능으로 구성하는 것은 각 기능을 묶어 기능을 기준으로 패키지를 나누고 해당 패키지에 관련된 모든 코드들을 넣어놓는 방법으로, 패키지 경계를 package-private 접근 수준과 결합하면 각 기능 사이의 불필요한 의존성을 방지할 수 있다는 장점이 있습니다.

하지만 이 방식은 사실 계층에 의한 패키징 방식보다 아키텍처의 가시성을 훨씬 더 떨어트리고, 심지어 package-private 접근 수준을 이용해 도메인 코드가 실수로 영속성 코드에 의존하는 것을 막을 수 없습니다.

아키텍처적으로 표현력 있는 패키지 구조로 구성하기

아키텍처 다이어그램의 특정 박스가 어떤 코드를 나타내는지 알 수 있다면 아키텍처를 파악하기 좀 더 쉬울 것입니다. 그렇다면 어떻게 해야 아키텍처를 잘 반영한 패키지 구조를 만들 수 있을까요?

헥사고날 아키텍처를 패키지 구조에 반영해 봅시다. 헥사고날 아키텍처에서 핵심적인 요소는 엔티티, 유스 케이스, 인커밍/아웃고잉 포트, 인커밍/아웃고잉 어댑터입니다. 이 요소들들 표현하는 패키지 구조를 만들면 아키텍처적으로 표현력 있는 패키지 구조를 만들 수 있겠죠. 이러한 구조는 아키텍처에 대한 적극적인 사고를 촉진하며, DDD(Domain-Driven-Design) 개념에 직접적으로 대응시킬 수 있다는 장점이 있습니다.

패키지 구조가 아키텍처를 반영할 수 없다면 시간이 지남에 따라 코드는 점점 목표하던 아키텍처로부터 멀어지게 됩니다. 그러므로 표현력 있는 구조를 구성함으로써 코드와 아키텍처 간의 간격을 줄일 수 있도록 해야 합니다.