여러 애그리거트가 필요한 기능
도메인 영역의 코드를 작성하다 보면, 한 애그리거트로 기능을 구현할 수 없을 때가 있다.
결제 금액 계산 로직을 생각해보자.
우선 구매하려는 상품의 가격이 필요하므로 상품 애그리거트가 필요하다.
또 상품 별로 몇 개를 구매할 것인지 알아야 하므로 주문 애그리거트가 필요하다.
또 할인 금액이나 비율, 제약 조건 등이 필요하므로 할인 애그리거트가 필요하고, 회원 등급에 따라 또 할인 등급이 나뉘어진다면 회원 애그리거트도 필요할 것이다.
해당 상황에서 실제 결제 금액을 계산하는 주체는 누구일까?
주문 애그리거트가 주체라 가정해보자.
그렇다면 의문이 생긴다.
결제 금액 계산 로직이 주문 애그리거트의 책임에 들어갈까?
예를 들어 특별 감사 세일로 전 품목에 대해 한 달간 2% 추가 할인을 한다 가정해보자.
해당 할인 정책은 주문 애그리거트가 가지고 있는 구성 요소와는 관련이 없음에도 불구하고 결제 금액 계산 책임이 주문 애그리거트에 있다는 이유만으로 주문 애그리거트의 코드를 수정해야 한다.
이렇게 한 애그리거트에 넣기 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안된다.
억지로 구현하면 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고 외부에 대한 의존이 높아지게 되며 코드를 복잡하게 만들어 수정이 어렵게 되는 요인이 된다.
이를 해결하기 위해서는 도메인 기능을 별도 서비스로 구현하는 것이 좋다.
도메인 서비스
도메인 서비스는 도메인 영역에 위치한 도메인 로직을 표현할 때 사용한다.
- 계산 로직 : 여러 애그리거트가 필요한 계산 로직이나 한 애그리거트에 넣기에는 다소 복잡한 계산 로직
- 외부 시스템 연동이 필요한 도메인 로직 : 구현하기 위해 타 시스템을 사용해야 하는 도메인 로직
계산 로직과 도메인 서비스
응용 영역의 서비스가 응용 로직을 다룬다면, 도메인 서비스는 도메인 로직을 다룬다.
도메인 영역의 애그리거트나 밸류와 같은 구성요소와 도메인 서비스를 비교할 때 다른 점은
도메인 서비스는 상태 없이 로직만 구현한다는 점이다. 도메인 서비스를 구현하는 데 필요한 상태는 다른 방법으로 전달받는다.
public class DiscountCalculationService {
public Money calculateDiscountAmounts(...) {
...
}
}
public class Order {
public void calculateAmounts(...) {
Money totalAmounts = getTotalAmounts();
Money discountAmounts = disCalculationService.calculateDiscountAmounts(...);
...
}
}
public class OrderService {
private DiscountCalculationService discountCalculationService;
public Order createOrder(...) {
....
order.calculateAmounts(this.discountCalculationService, ..);
return order;
}
}
'책 정리 > 도메인 주도 개발 시작하기' 카테고리의 다른 글
Chapter 9. 도메인 모델과 바운디드 컨텍스트 (1) | 2023.12.21 |
---|---|
Chapter 8. 애그리거트 트랜잭션 관리 (0) | 2023.12.15 |
Chapter 6. 응용 서비스와 표현 영역 (1) | 2023.12.12 |
Chapter 5. 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2023.12.08 |
Chapter 4. 리포지터리와 모델 구현 (0) | 2023.12.05 |