ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 7장 - 도메인 서비스
    📕 book/도메인 주도 개발 시작하기 2023. 1. 12. 21:04

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


    도메인 영역의 코드를 작성하다 보면, 한 애그리거트로 기능을 구현할 수 없을 때가 존재한다.

    ex) 결제 금액 계산 로직

    • 상품 애그리거트 : 구매하는 상품의 가격
    • 주문 애그리거트 : 상품별 구매 개수
    • 항인 쿠폰 애그리거트 : 쿠폰별로 할인 금액, 비율에 따른 주문 총 금액
    • 회원 애그리거트 : 회원 등급에 따라 추가 할인이 가능하다

     

    여기서 실제 결제 금액을 계산하는 로직의 주체는 어떤 애그리거트인가 ❓

    이렇게 한 애그리거트에 넣기 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안된다.

     

    억지로 구현하게 되면 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하는 것이므로 코드가 길어지고 외부에 대한 의존이 높아지게 되며 코드를 복잡하게 만들어 수정이 어려워진다.

     

    ❗해결하는 가장 쉬운 방법 : 도메인 기능을 별도 서비스로 구현하는 것.

     

    📌 도메인 서비스


    💡 도메인 서비스는 도메인 영역에 위치한 도메인 로직을 표현할 때 사용한다.

    주로 아래 상황에서 도메인 서비스를 사용한다.

    • 계산 로직
    • 외부 시스템 연동이 필요한 도메인 로직 : 구현을 하기 위해 타 시스템을 사용해야 하는 도메인 로직

     

    계산 로직

    한 애그리거트에 넣기 애매한 도메인 개념을 구현하기 위해서는 도메인 서비스를 이용해 도메인 개념을 명시적으로 드러내면 된다.

     

    응용 영역의 서비스가 응용 로직을 다룬다면, 도메인 서비스는 도메인 로직을 다룬다.

     

    📖 도메인 영역 애그리거트, 밸류 vs 도메인 서비스

    • 도메인 서비스는 상태 없이 로직만 구현한다.
    • 도메인 서비스를 구현하는 데 필요한 상태는 다른 방법으로 전달받는다.

     

    할인 금액 계산 로직을 위한 도메인 로직

    • 도메인의 의미가 드러나는 용어를 타입과 메서드 이름으로 갖는다.
    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(orderer.getMember().getGrade());
    
        return couponDiscount.add(memebershipDiscount);
      }
    
      public Money calculateDiscount(Coupon coupon) {
         ...
      }
    
      public Money calculateDiscount(MemberGrade grade) {
         ...
       }
    }
    • 할인 계산 서비스를 사용하는 주체는 애그리거트가 될 수도 있고 응용 서비스가 될 수도 있다.

     

    💡 도메인 서비스 객체를 애그리거트에 주입하지 않기

    • 애그리거트의 메서드를 실행할 때 도메인 서비스 객체를 파라미터로 전달한다는 것은 애그리거트가 도메인 서비스에 의존한다는 것이다.
    • 일부 기능을 위해 굳이 도메인 서비스 객체를 애그리거트에 의존 주입할 이유가 없다.

     

    외부 시스템 연동과 도메인 서비스

    외부 시스템이나 타 도메인과의 연동 기능도 도메인 서비스가 될 수 있다.

     

    도메인 서비스의 패키지 위치

    도메인 서비스는 도메인 로직을 표현한다.

    따라서, 도메인 서비스의 위치는 다른 도메인 구성요소와 동일한 패키지에 위치한다.

    ex) 주문 금액 계산을 위한 도메인 서비스는 주문 애그리거트와 같은 패지키에 위치

     

    도메인 서비스의 인터페이스와 클래스

    도메인 서비스의 로직이 고정되어 있지 않은 경우에는 도메인 서비스 자체를 인터페이스로 구현하고 이를 구현한 클래스를 둘 수 있다.

    특히, 도메인 로직을 외부 시스템이나 별도 엔진을 이용해서 구현할 때 인터페이스와 클래스를 분리하게 된다.

    • 도메인 영역에 도메인 서비스 인터페이스가 위치
    • 실제 구현은 인프라스트럭처 영역에 위치

     

    💡 도메인 서비스의 구현이 특정 구현 기술에 의존하거나 외부 시스템의 API를 실행한다면 도메인 영역의 도메인 서비스는 인터페이스로 추상화해야 한다.

    이를 통해 도메인 영역이 특정 구현에 종속되는 것을 방지할 수 있고 도메인 영역에 대한 테스트가 쉬워진다.

     

    참고자료

    http://www.yes24.com/Product/Goods/108431347

    댓글

Designed by Tistory.