소개

3장: 코드 구성하기

계층으로 구성하기

buckapl |--- domain | |----- Account | |----- Activity | |----- AccountRepository | |----- AccountService |--- persistence | |----- AccountRepositoryImpl |--- web | |----- AccountController
JavaScript
복사
문제점
1.
계층으로 코드를 구성하면 기능적인 측면들이 섞이기 쉽다.
2.
애플리케이션의 기능 조각(functional slice)이나 특성(feature)을 구분 짓는 패키지 경계가 없다
3.
애플리케이션이 어떤 유스케이스들을 제공하는지 파악할 수 없다
4.
패키지 구조를 통해서는 우리가 목표로 하는 아키텍처를 파악할 수 없다

기능으로 구성하기

buckapl |--- account | |----- Account | |----- Activity | |----- AccountRepository | |----- SendMoneyService | |----- AccountRepositoryImpl | |----- AccountController
JavaScript
복사
장점
1.
패키지 경계를 package-private 접근 수준과 결합하면 각 기능 사이의 불필요한 의존성을 방지할 수 있다.
문제점
1.
기능을 기준으로 코드를 구성하면 기반 아키텍처가 명확하게 보이지 않는다

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

buckapl |--- account | |----- adapter | | |----- in | | | |---- web | | | | |---- AccountController | | |----- out | | | |---- persistence | | | | |---- AccountPersistenceAdapter | | | | |---- SpringDataAccountRepository | |---- domain | | |----- Account | | |----- Activity | |---- application | | |----- SendMoneyService | | |----- port | | | |---- in | | | | |---- SendMoneyUseCase | | | |---- out | | | | |---- LoadAccountPort | | | | |---- UpdateAccountStatePort
JavaScript
복사
장점
1.
각 아키텍처 요소들에 정해진 위치가 있어 직관적이다.
2.
필요한 경우 하나의 어댑터를 다른 구현으로 쉽게 교체할 수 있다.
3.
DDD 개념을 직접적으로 대응할 수 있다.
문제점
1.
패키지가 많다는 것은 모든 것을 public으로 만들어 패키지 간의 접근을 허용해야 하는거 아닌가?
a.
application 패키지 내에 있는 포트 인터페이스를 통하지 않고서 바깥으로 호출되지 않기 때문에 package-private 접근 수준으로 둬도 된다.
2.
JPA의 1차 캐시 등을 적극 활용할 수 없다.

의존성 주입의 역할

어댑터는 그저 애플리케이션 계층에 위치한 서비스를 호출할 뿐이다.
영속성 어댑터와 같이 outgoing 어댑터에 대해서는 제어 흐름의 반대 방향으로 의존성을 돌리기 위해 DIP를 이용해야 한다.
Controller 가 UseCase 인터페이스를 필요로 하기 떄문에, 의존성 주입을 통해 Service 클래스의 인스턴스를 주입한다.
컨트롤러는 인터페이스만 알면 되기 때문에 자신이 Service 인스턴스를 실제로 가지고 있는지도 모른다.

Conclusion

우리가 목표로 하는 아키텍처에 가깝게 코드 구조를 만들어 보았으며,
다음 장에서는 애플리케이션 계층, 웹 어댑터, 영속성 어댑터를 이용해서 유스케이스를 구현하며 패키지 구조와 의존성 주입에 대해 조금 더 살펴본다.