/////
Search
Duplicate
1️⃣

여러 애그리거트가 필요한 기능

: 도메인 영역의 코드를 작성하다보면 한 애그리거트로 기능을 구현할 수 없을 때가 있다.
: 대표적인 예가 결제 금액 계산 로직으로 다음과 같은 내용이 필요하다.
상품 애그리거트: 구매하는 상품의 가격이 필요하다. 또한 상품에 따라 배송비가 추가되기도 한다.
주문 애그리거트: 상품별로 구매 개수가 필요하다.
할인쿠폰 애그리거트: 쿠폰별로 지정한 할인 금액이나 비율에 따라 주문 총 금액을 할인, 할인 쿠폰을 조건에 따라 중복 사용할 수 있다거나 지정한 카테고리의 상품에만 적용할 수 있다는 제약 조건이 있음
회원 애그리거트: 회원 등급에 따라 추가 할인이 가능하다.
: 이 상황에서 실제 결제 금액을 계산해야하는 주체는 어떤 애그리거트일까? 총 주문 금액을 계산하는 것은 주문 애그리거트가 할 수 있지만 실제 결제 금액은 아니다.
: 총 주문 금액에서 할인 금액을 계산해야 하는데, 이 할인 금액을 구하는 것은 누구의 책임일까
: 생각해볼 수 있는 방법은, 주문 애그리거트가 필요한 데이터를 모두 가지도록 한 뒤, 할인 금액 계산 책임을 주문 애그리거트에 할당하는 것이다.
public class Order { ... private Orderer orderer; private List<OrderLine> orderLines; private List<Coupon> usedCoupons; private Money calcualtePayAmounts() { Money totalAmounts = calculateTotalAmounts(); // 쿠폰별로 할인 금액을 구한다. Money discount = coupons .stream() .map(coupon -> calculateDiscount(coupon)) .reduce(Money(0), (v1,v2) -> v1.add(v2)); // 회원에 따른 추가 할인 금액을 구한다. Money membershipDiscount = calculateDiscount(orderer.getMember().getGrade()); // 실제 결제 금액 계산 return totalAmounts.minus(discount).minus(membershipDiscount); } private Money calcuateDiscount(Coupon coupon) { // orderLines의 각 상품에 대해 쿠폰을 적용해서 할인 금액을 계산하는 로직. // 쿠폰의 적용 조건 등을 확인하는 코드 // 정책에 따라 복잡한 if-else와 계산 코드 ... } private Money calculateDisocunt(MemberGrade grade) { ... // 등급에 따라 할인 금액을 계산 }
TypeScript
복사
: 여기서 결제 금액 계산 로직이 주문 애그리거트의 책임일까? 예를 들어 특별 감사 세일로 전 품목에 대해 한 달간 2% 추가 할인을 하기로 했을 때, 이 할인 정책은 주문 애그리거트가 갖고 있는 구성요소와는 관련이 없음에도 결제 금액 계산 책임이 주문 애그리거트에 있다는 이유로 주문 애그리거트의 코드를 수정해야 한다.
: 이렇게 한 애그리거트에 넣기 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안 된다.
: 이 경우 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고 외부에 대한 의존이 높아지게 된다.
: 이는 코드를 복잡하게 만들어 수정을 어렵게 만드는 요인이 된다. 이런 문제를 해소하는 가장 쉬운 방법이 하나 있는데 그것은 바로 도메인 서비스를 별도로 구현하는 것이다.