7장. 도메인 서비스
도메인 서비스 ?
도메인 단위로 나눠서 개발을 하다 보면 비즈니스 기능을 구현하는데 여러 애그리거트가 필요한 경우가 생김
ex) 결제 금액 계산 로직
결제 금액을 계산할 때 결제 애그리거트 와 함께 하는 애그리거트 예
- 상품 애그리거트
- 구매하는 상품의 가격
- 배송비
- 주문 애그리거트
- 상품 별 주문한 개수
- 할인 쿠폰 애그리거트
- 쿠폰 별 금액 할인
- 회원 애그리거트
- 회원 등급에 따른 추가 할인
지불 금액 = 총 비용 - 쿠폰 할인 - 회원 추가 할인
Solution 1. 주문 애그리거트에 로직 넣기 ❌
주문 애그리거트에 상품, 할인 쿠폰, 회원 등을 넣고, 결제 금액을 계산하는 메서드를 만들면 구현할 수 있다.
- 위의 구현으로 인해 주문 애그리거트는 외부에 대한 의존이 높아졌는데, 과연 결제 금액 계산 로직이 주문 애그리거트의 책임이 맞는가?
- 모르겠다.. 복잡도는 엄청 증가한 것 같다
- 단일 책임 원칙 위반 아닌가?
- 그렇지
- 근데 왜 주문 애그리거트에 넣었나?
- 그럼 어디에 넣냐?
- 결제 금액을 계산하는 클래스로 새로 만들어라!
- 그럼 어디에 넣냐?
Solution 2. 별도의 클래스 (도메인 서비스) 만들기 ✔️
자. 지금 도메인 서비스를 만들거다
응용 서비스는 응용 로직을 다루고, 도메인 서비스는 도메인 로직을 다룬다
다만, 도메인 서비스는 해당 로직이 여러 애그리거트를 필요로 할 때 사용되며, 상태가 없다는 것을 기억해야 함.
엔티티
,VO
는 상태를 가진다도메인 서비스
는 상태가 없다.
public class DiscountCalculationService {
public Money calculateDiscountAmounts ( List<OrderLine> orderLines, List<Coupon> coupons, MemberGrade grade) {
Money couponDiscount = coupons.stream()
.map(coupon -> calculateDiscount(coupon))
.reduce(Money(0), (v1, v2) -> v1.add(v2));
Money membershipDiscount = calculateDiscount(grade);
return couponDiscount.add(menbershipDiscount);
}
}
private Money calculateDiscount(Coupon coupon) { ... }
private Money calculateDiscount(MemberGrade grade) { ... }
}
p206 오타같음. 위 코드는 오탈자 수정한 것
How to USE
자, 클래스 만들었다. 이거 어디서 필요한거야? 누가 필요해서 메시지를 전달한거야?
특정 기능이 응용 서비스인지, 도메인 서비스인지 헷갈려요~
-> 해당 기능이 도메인 로직 (애그리거트를 변경하거나 값을 계산하는 로직) 이면서 한 애그리거트에 넣기 적합하지 않은 경우는 도메인 서비스다.
-> 결국 도메인 서비스에는 도메인 로직이 온다는 말임. 응용서비스에는 도메인 로직이 없음
TODOTODO :: 루트 애그리거트는 도메인 서비스를 몰라도된다!! 에 대해서 고민
주의) 도메인 서비스 클래스를 DI 하지 않기
DI 한다는 것은 객체를 ApplicationContext에 등록시키는 것이다. 사용하고 싶을 때는 필드로 만들고, 주입받아서 쓴다.
하지만 루트 애그리거트에서 위처럼 주입받아서 쓰면 ..
DiscountCalculationService 필드는 DB로 저장하는 필드가 아님. 또한 모든 메서드에서 DiscountCalculationService 필드를 필요로 하진 않음
패키지 위치
- src
- order
- domain
- Order.java
- OrderRepository.java
- DiscountCalculationService.java (도메인 서비스)
- application
- OrderService.java
- domain
- order
도메인 서비스가 외부 시스템에 의존한다면 ?
도메인 서비스의 로직이 고정되어 있지 않고 여러개일 경우에는 인터페이스로 추상화시키고 구현체를 여러개 만들면 됨
- 특정 구현 기술에 의존적이거나 외부 시스템의 API를 실행한다면?
- 도메인 영역의 도메인 서비스는 인터페이스로 추상화!
- 인터페이스 : domain 영역
- 구현체 : infra 영역
Q1. Order에서 DI 해서 쓰지 말고 그럼… 서비스단에서 받아서 쓰나..? 자기가 new 해서 쓰나..?
서비스단에서 주입받아서 쓴다. 도메인 서비스는 상태를 가지지 않으므로 서비스에서 상태도 파라미터로 함께 제공 해주어야 함
Q2. DiscountCalculationService를 왜 OrderService에서 쓰는게 아니라 왜 Order가 호출하지? p207
..
- 범위 : DDD START! 6~7 장
- 일시 : 190901 (15:30 ~ 18:00)
- 장소 : 역삼 할리스
- 인원 : 2