- 육각형 아키텍처는 도메인 중심의 아키텍처에 적합하다.
유스케이스 둘러보기#
- 일반적으로 유스케이스는 다음과 같은 단계를 따른다.
- 입력을 받는다.
- 입력 유효성 검증은 다른 곳에서 처리한다. (유스케이스 코드가 도메인 로직에만 신경 써야하고 입력 유효성 검증으로 오염되면 안된기 떄문)
- 비즈니스 규칙을 검증한다.
- 도메인 엔티티와 유스케이스가 책임을 공유한다.
- 모델 상태를 조작한다.
- 영속성 어댑터를 통해 구현된 포트로 변경된 상태를 전달해서 저장될 수 있게 한다.
- 출력을 반환한다.

입력 유효성 검증#
- 입력 유효성 검증은 입력 모델의 생성자 내에서 이루어진다.
- 자바의 bean Validation API 등을 통해서 반복적인 검증을 쉽게 처리할 수 있다.
class SendMoneyCommand extends SelfValidating<SendMoneyCommand> {
@NotNull
private final AccountId sourceAccountId;
@NotNull
private final AccountId targetAccountId;
@NotNull
private final Money money;
public SendMoneyCommand(
AccountId sourceAccountId,
AccountId targetAccountId,
Money money) {
this.sourceAccountId = sourceAccountId;
this.targetAccountId = targetAccountId;
this.money = money;
this.validateSelf();
}
}
유스케이스마다 다른 입력 모델#
- 각 유스케이스 전용 입력 모델은 유스케이스를 훨씬 명확하게 만들고 다른 유스케이스와의 결합도 제거해서 불필요한 부수효과가 발생하지 않게 된다.
- 거의 비슷한 입력 모델이라고 공유하면 코드 스멜을 유발하기 쉽다.
비즈니스 규칙 검증하기#
- 입력 유효성을 검증하는 것은 구문상(syntactical) 유효성을 검증하는 것이고, 비즈니스 규칙은 유스케이스의 맥락 속에서 의미적인(semantical) 유효성을 검증하는 일이라고 할 수 있다.
- 도메인 엔티티에서 비즈니스 규칙을 검증하고, 도메인 엔티티에서 비즈니스 규칙을 검증하기가 여의치 않다면 유스케이스 코드에서 검증할 수 있다.
풍부한 도메인 모델 vs. 빈약한 도메인 모델#
- 풍부한 도메인 모델: 애플리케이션의 코어에 있는 엔티티에서 가능한 한 많은 도메인 로직이 구현된다.
- 빈약한 도메인 모델: 엔티티는 상태를 표현하는 필드와 값을 읽고 바꾸기 위한 getter, setter 메서드만 포함하고 어떤 도메인 로직도 가지고 있지 않다.
- 빈약한 도메인 모델은 도메인 로직이 모두 유스케이스 클래스에 구현돼 있다.
- 두 가지 스타일 모두 육각형 아키텍처에 접목이 가능하다.
유스케이스마다 다른 출력 모델#
- 유스케이스의 출력은 호출자에게 꼭 필요한 데이터만 들고 있어야 한다.
- 유스케이스들 간 같은 출력 모델을 공유하게 되면 유스케이스들도 강하게 결합된다.
- 같은 이유로 도메인 엔티티를 출력 모델로 사용하고 싶은 유혹도 견뎌야 한다.
읽기 전용 유스케이스는 어떨까?#
- 읽기 전용 작업은 유스케이스라고 언급하는 것은 조금 이상하다.
- 애플리케이션 코어 관점에는 간단한 데이터 쿼리이기 때문에, 실제 유스케이스와 구분하기 위해 쿼리로 구분할 수 있다.
- 읽기 전용 쿼리를 쓰기가 가능한 유스케이스와 구분하는 방식은 CQS(Command-Query Separation)나 CQRS(Command responsibility Segregation) 같은 개념과 아주 잘 맞는다.
@RequiredArgsConstructor
class GetAccountBalanceService implements GetAccountBalanceQuery {
private final LoadAccountPort loadAccountPort;
@Override
public Money getAccountBalance(AccountId accountId) {
return loadAccountPort.loadAccount(accountId, LocalDateTime.now())
.calculateBalance();
}
}
유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 뙬까?#
- 입출력 모델을 독립적으로 모델랑한다면 원치 않는 부수효과를 피할 수 있다.
- 유스케이스 간에 모델을 공유하는 것보다는 더 많은 작업이 필요하지만, 분리한다면 유스케이스를 명확하게 이해할 수 있고, 장기적으로 유지보수하기도 더 쉽다.