<aside> ✅

사용자가 본인 계좌에서 다른 계좌로 송금하는 유스케이스

</aside>

3.1. 계층으로 구성하기

코드를 구조화하는 첫 번째 접근법은 계층을 이용하는 것

계층으로 구성하면 기능적인 측면들이 섞이기 쉽다.

계층으로 구성하면 기능적인 측면들이 섞이기 쉽다.

웹, 도메인, 영속성 계층 각각에 대해 전용 패키지를 두었다. 간단한 구조의 계층은 적합한 구조가 아닐 수 있어서 의존성 역전 원칙을 이용해 의존성이 domain 패키지에 있는 도메인 코드만을 향하도록 만들었다.

이 패키지는 최적의 구조가 아니다

3.2. 기능으로 구성하기

기능을 기준으로 코드를 구성하면 기반 아키텍처가 명확하게 보이지 않는다.

기능을 기준으로 코드를 구성하면 기반 아키텍처가 명확하게 보이지 않는다.

가장 본질적인 변경은 계좌와 관련된 모든 코드를 최상위의 account 패키지에 넣었으며, 계층 패키지들도 없앴다.

각 기능을 묶은 새로운 그룹은 account와 같은 레벨의 새로운 패키지로 들어가고, 패키지 외부에서 접근되면 안 되는 클래스들에 대해 package-private 접근 수준을 이용해 패키지 간의 경계를 강화할 수 있다.

패키지 경계를 package-private 접근 수준과 결합하면 각 기능 사이의 불필요한 의존성을 방지할 수 있다.

추가로 AccountService의 책임을 좁히기 위해 SendMoneyService로 클래스명을 바꿨다.

이제 ‘송금하기’ 유스케이스를 구현하는 코드는 클래스명만으로도 찾을 수 있게 됐다.

그러나 기능에 의한 패키징 방식은 계층에 의한 패키징 방식보다 아키텍처의 가시성을 훨씬 더 떨어뜨린다. 어댑터를 나타내는 패키지명이 없고, 인커밍 포트, 아웃고잉 포트를 확인할 수 없다.

심지어 도메인 코드와 영속성 코드 간의 의존성을 역전시켜 SendMoneyService가 AccountRepository 인터페이스만 알고 있고 구현체는 알 수 없도록 했음에도 불구하고, package-private 접근 수준을 이용해 도메인 코드가 실수로 영속성 코드에 의존하는 것을 막을 수 없다.