유스케이스 역할 살펴보기
- 입력을 받는다.
- 비즈니스 규칙을 검증한다.
- 모델 상태를 조작한다.
- 출력을 반환한다.
유스케이스는 인커밍 어댑터로부터 입력을 받습니다.
이 단계는 “입력 유효성 검증”을 하는 것이 아니라, Controller에서 받은 입력값을 유스케이스 서비스에 맞게 매핑하여 전달합니다. (SendMoneyRequest → SendMoneyCommand)
유스케이스는 비즈니스 규칙을 검증할 책임이 있으며, 비즈니스 규칙을 충족하면 유스케이스는 입력을 기반으로 모델의 상태를 변형합니다.
일반적으로 도메인 객체의 상태를 바꾸고, 영속성 어댑터를 통해 구현된 포트로 이 상태를 전달하여 데이터베이스의 값을 변경하거나 저장합니다. (하나의 유스케이스는 여러 개의 아웃고잉 어댑터를 호출할 수 있습니다.)
아웃고인 어댑터에서 받은 출력값을, 유스케이스를 호출한 어댑터로 반환할 출력 객체로 변환합니다.
public class SendMoneyService implements SendMoneyUseCase {
private final LoadAccountPort loadAccountPort;
private final UpdateAccountStatePort updateAccountStatePort;
@override
public boolean sendMoney(SendMoneyCommand command) {
// 비즈니스 규칙 검증
// 모델 상태 조작
// 출력 값 반환
}
}
서비스 동작 설명
- 인커밍 포트 인터페이스인 SendMoneyUseCase를 구현합니다.
- 계좌를 불러오기 위한 아웃고잉 포트 인터페이스 LoadAccountPort를 호출합니다.
- 데이터베이스의 계좌 상태 업데이트를 위해 UpdateStateAccountStatePort를 호출합니다.
유스케이스마다 다른 입력 모델
각기 다른 유스케이스에 동일한 입력 모델을 사용한다면, 하나의 클래스로 처리할 수는 있겠지만, 유효성 입력 검증과 해당 입력 모델을 봤을 때, 정말 필요로 하는 데이터 필드가 무엇인지 파악하기 어려운 단점이 있습니다.
그래서 각 유스케이스마다 전용 입력 모델을 만들어 유스케이스를 명확하게 만들어, 다른 유스케이스와의 결합을 제거합니다.
- 서로 다른 유효성 검증 로직 작성 가능
- 불필요한 부수 효과 발생하지 않음
비즈니스 규칙 검증하기
입력 유효성 검증은 유스케이스 로직의 일부는 아니다. 반면, 비즈니스 규칙 검증은 유스케이스 로직의 일부로 중요한 부분이다.
이 둘 사이의 구분점은 비즈니스 규칙을 검증하는 것은 도메인 모델의 현재 상태에 접근하는 반면, 입력 유효성 검증은 그럴 필요 없이 입력받은 값만 검증합니다.
📌 입력 유효성을 검증하는 것은 구문상의(syntactical) 유효성을 검증하는 것이며, 비즈니스 규칙은 유스케이스의 맥락 속에서의 의미적인(semantical) 유효성을 검증하는 일입니다.
ex)
비즈니스 규칙 : 출금 계좌는 초과 출금이 되어서는 안 된다. (기존 계좌의 상태를 확인해야 함)
입력 유효성 검증 : 송금되는 금액은 0보다 커야 한다. (입력 값을 확인해야 함)
비즈니스 규칙 검증은 도메인 모델 안에 넣어 관리할 수 있습니다.
public class Account {
// 출금
public boolean withdraw(Money money, AccountId targetAccountId) {
if (!mayWithdraw(money)) {
return false;
}
}
}
만약 도메인 모델에 비즈니스 규칙을 검증하기 어렵다면, 유스케이스 코드에서 도메인 모델을 사용하기 전에 검증을 처리할 수 있습니다.
public class SendMoneyService implements SendMoneyUseCase {
private final LoadAccountPort loadAccountPort;
private final UpdateAccountStatePort updateAccountStatePort;
@override
public boolean sendMoney(SendMoneyCommand command) {
requireAccountExists();
requireAccountExists();
}
}
유스케이스마다 다른 출력 모델
입력과 비슷하게 출력도 가능하면 각 유스케이스에 맞게 구체적일수록 좋다.
출력은 호출자에게 꼭 필요한 데이터만 들고 있어야 합니다. (출력 모델만 봤을 때 다른 개발자가 봤을 때 어떤 값을 반환하는지 파악할 수 있음)
유스케이스들 간에 같은 출력 모델을 공유하게 되면 유스케이스들도 강하게 결합됩니다. 다른 유스케이스에서 출력 모델에 새로운 필드를 추가해야 된다면, 이와 관련 없는 유스케이스에서도 이 필드를 처리해줘야 합니다.
단일 책임 원칙을 적용하여 출력 모델을 분리해서 관리하는 것이 유스케이스의 결합을 제거하는 데 도움이 됩니다.
결론
📌 각 유스케이스에 맞는 입출력 모델을 만든다면, 유스케이스 간에 모델을 공유하는 것보다는 더 많은 작업이 필요합니다. (각 유스케이스마다 별도의 모델을 만들고, 매핑까지 해줘야 함)
하지만, 유스케이스별로 모델을 만들면 유스케이스를 명확하게 이해할 수 있어, 장기적 유지보수 측면에서 좋습니다.
'개발 도서 > 만들면서 배우는 클린 아키텍처' 카테고리의 다른 글
클린 아키텍처 유지보수를 망치는 습관 3 가지 (1) | 2024.12.01 |
---|---|
헥사고날 아키텍처 구조 잡기, adapter-port 구조 (2) | 2024.11.19 |
클린 아키텍처 설계 1단계 - 단일 책임 원칙, 의존성 역전 원칙 적용하기 (1) | 2024.11.17 |
클린 아키텍처란 무엇인가, 계층형 아키텍처의 문제점과 함정 (0) | 2024.11.13 |