각각 구현한 유스케이스, 웹 어댑터, 영속성 어댑터를 동작하는 애플리케이션으로 조립하기
유스케이스와 어댑터를 필요할 때마다 인스턴스화한다면? 의존성이 여러 방향으로 퍼질 수도 있다.
모든 의존성이 애플리케이션 코어(도메인 코드)쪽인 올바른 방향으로 향해야 한다.
이것이 아웃고잉 포트 인터페이스이 존재 이유 - 유스케이스는 인터페이스만 알아야 하고, 런타임에 인터페이스의 구현을 제공받는다.
필요한 모든 객체를 생성자로 받을 수 있다면, 테스트시 목 객체를 받아서 격리된 단위 테스트를 생성하기 쉬워진다.
1. 웹 어댑터 인스턴스 생성
2. HTTP 요청이 실제로 웹 어댑터로 전달되도록 보장
3. 유스케이스 인스턴스 생성
4. 웹 어댑터에 유스케이스 인스턴스 제공
5. 영속성 어댑터 인스턴스 생성
6. 유스케이스에 영속성 어댑터 인스턴스 제공
7. 영속성 어댑터가 실제로 데이터베이스에 접근할 수 있도록 보장
8. 설정 파일, 커맨드라인 파라미터 등 설정 파라미터 소스에 접근, 애플리케이션 컴포넌트에 제공 (db 설정, 서버 설정, 행동 양식 제어 등)
책임이 굉장히 많다 → 변경할 이유가 많다 → SRP 위반
하지만 나머지 코드를 깔끔하게 유지하기 위해 어쩔 수 없다.
public class CleanArchitectureApplication {
public static void main(String[] args) {
AccountRepository accountRepository = new AccountRepository();
ActivityRepository activityRepository = new ActivityRepository();
AccountPersistenceAdapter accountPersistenceAdapter = new AccountPersistenceAdapter(accountRepository,
activityRepository, new AccountMapper());
SendMoneyUseCase sendMoneyUseCase = new SendMoneyService(
accountPersistenceAdapter, accountPersistenceAdapter, new NoOpAccountLock(), new MoneyTransferProperties());
SendMoneyController sendMoneyController = new SendMoneyController(sendMoneyUseCase);
startProcessingWebRequests(sendMoneyController);
}
}
main()에서 필요한 모든 클래스의 인스텉스를 생성한 후 연결
SendMoneyController
의 접근제어자를 package-private에서 public으로 변경Application Context
: 애플리케이션을 조립한 결과물Bean
: 애플리케이션을 구성하는 모든 객체위의 지저분한 작업을 대신해줄 수 있는 의존성 주입 프레임워크 - 그 중 자바의 스프링 프레임워크
스프링은 클래스패스 스캐닝으로 클래스패스에서 접근 가능한 모든 클래스를 확인해서 @Component
가 붙은 클래스를 찾고, 이 클래스들의 각 객체를 생성한다.
적절한 곳에 @Component
를 붙이고 생성자를 잘 만들기
애플리케이션 컨텍스트에 등록할 빈을 생성, 제어하는 설정 클래스
@Configuration
@EnableJpaRepositories(basePackages = "com.woowa.cleanarchitecture.account")
public class PersistenceAdapterConfiguration {
@Bean
AccountPersistenceAdapter accountPersistenceAdapter(
AccountRepository accountRepository,
ActivityRepository activityRepository,
AccountMapper accountMapper) {
return new AccountPersistenceAdapter(accountRepository, activityRepository, accountMapper);
}
@Bean
AccountMapper accountMapper() {
return new AccountMapper();
}
}
@Configuration
: 스프링의 클래스패스 스캐닝에서 발견해야 할 설정 클래스@EnableJpaRepositories
: 스프링 부트가 직접 jpa 리포지토리 인터페이스의 구현체 생성해서 제공accountPersistenceAdpter()
의 파라미터인 accountRepository
, activityRepository
@Component
를 붙이도록 강제하지 않는다.(+) 패키지만 알려주면 알아서 스프링이 애플리케이션을 조립하므로 아주 편리한 기능이다.
(-) 코드의 규모가 커지면 어떤 빈이 애플리케이션 컨텍스트에 등록되는지 정확히 알 수 없다.
(-) 테스트할 때 컨텍스트의 일부만 독립적으로 띄우기 어렵다.
(+) 애플리케이션의 변경할 이유(책임)이 줄어든다.
(+) 서로 다른 모듈로부터 독립되어 응집도가 매우 높은 모듈을 만들 수 있다.
(-) 유지보수하는데 더 많은 시간을 투자해야 한다.