////
Search

7장 - 도메인 서비스

Created
2023/01/16 02:16
Tags

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

도메인 영역의 코드를 작성하다 보면, 한 애그리거트로 기능을 구현한 수 없을 때가 있다.
대표적인 예사 결제 금액 계산 로직
상품 애그리거트
구매하는 상품의 가격이 필요하고 상품에 따라 배송비가 추가되기도 함
주문 애그리거트
상품별로 구매 개수가 필요
할인 쿠폰 애그리거트
쿠폰별 할인 금액이나 비율에 따라 주문 총 금액을 할인
회원 애그리거트
회원 등급에 따라 추가 할인이 가능
이 상황에서 실제 결제 금액을 계산해야 하는 주체는 어떤 애그리거트?
총 주문 금액을 계산하는건 주문 애그리거트가 할 수 있지만 실제 결제 금액은 할인 규칙을 가지고 있으니 이야기가 다름
거기다 할인 쿠폰이 두개 적용 가능하다면 단일 할인 쿠폰 애그리거트로는 계산할 수 없음
생각해 볼 수 있는 방법은 주문 애그리거트가 필요한 데이터를 모두 가지도록 한 뒤 할인 금액 계산 책을을 주문 애그리거트에 할당하는 것
여기서 실제 금액 계산 로직이 주문 애그리거트의 책임이 맞을까? 예를 들어 특별 감사 세일로 전 품목에 대해 한 달간 2% 추가 할인을 한다고 해보자.
이 할인 정책은 주문 애그리거트가 갖고 있는 구성요소와는 관련이 없음에도 결제 금액 계산 책임이 주문 애그리거트에 있다는 이유로 주문 애그리거트 코드를 수정해야 함
때문에 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안됨
억지로 구현하면 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고, 외부에 대한 의존이 높아지게 되며 코드를 복자한게 만들어 수정이 어렵게 만드는 요인이 됨
이런 문제를 해소하는 가장 쉬운 방법은 도메인 기능을 별도 서비스로 구현하는 것

7.2 도메인 서비스

도메인 서비스는 도메인 영역에 위치한 도메인 로직을 표현할 때 사용
계산 로직 : 여러 애그리거트가 필요한 계산 로직/한 애그리거트에 넣기엔 다소 복잡한 계산 로직
외부 시스템 연동이 필요한 도메인 로직 : 구현하기 위해 사용해야 하는 도메인 로직

7.2.1 계산 로직과 도메인 서비스

할인 금액 규칙 계산처럼 한 애그리거트에 넣기 애매한 도메인 개념을 구현하려면 애그리거트에 억지로 넣기보다는 도메인 서비스를 이용해서 도메인 개념을 명시적으로 드러내면 된다.
도메인 영역의 애그리거트나 밸류와 같은 구성요소와 도메인 서비스를 비교할 때 다른 점은 도메인 서비스는 상태 없이 로직만 구현한다는 점
도메인 서비스 객체를 애그리거트에 주입하지 않기
애그리거트의 메서드를 실행할 때 도메인 서비스 객체를 파라미터로 전달한다는 것은 애그리거트가 도메인 서비스에 의존한다는 것을 의미
일부 기능을 위해 굳이 도메인 서비스 객체를 애그리거트에 의존 주입할 이유는 없다.
이는 프레임워크의 기능을 사용하고 싶은 개발자의 욕심이다!
애그리거트 메서드를 실행할 때 도메인 서비스를 인자로 전달하지 않고 반대로 도메인 서비스의 기능을 실행할 때 애그리거트를 전달하기도 함
→ 이런식으로 동작하는 것 중 하나가 계좌 이체 기능
public class TransferService { public void transfer(Account fromAcc, Account toAcc, Money amounts) { fromAcc.withdraw(amouts); toAcc.credit(amounts); } ...
Java
복사

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

외부 시스템이나 타 도메인과의 연동 기능도 도메인 서비스가 될 수 있다.
예를 들어 설문 조사 사슽메과 사용자 역할 관리 시스템이 분리되어 있다면, 설문 조사 시스템은 설문 조사를 생성할 때 사용자가 생성 권한을 가진 역할인지 확인하기 위해 역할 관리 시스템과 연동해야 한다.

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

도메인 서비스는 도메인 로직을 표현하므로 도메인 서비스의 위치는 다른 도메인 구성 요소와 동일한 패키지에 위치한다.
도메인 서비스의 개수가 많아 다른 구성 요소와 명시적으로 구분하고 싶다면 domain 패키지 맡에 domain.model, domain.service, domain.repository와 같은 하위 패키지를 구분하여 위치시켜도 됨

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

도메인 서비스의 로직이 고정되어 있지 않은 경우 도메인 서비스 자체를 인터페이스로 구현하고 이를 구현한 클래스를 둘 수도 있다.
특히 도메인 로직을 외부 시스템이나 별도 엔진을 이용해서 구현할 때 인터페이스와 클래스를 분리하게 된다.
도메인 서비스의 구현이 특정 구현 기술에 의존하거나 외부 시스템의 API를 실행한다면 도메인 영역의 도메인 서비스는 인터페이스로 추상화 해야한다.
이를 통해 도메인 영역이 특정 구현에 종속되는 것을 방지할 수 있고 도메인 영역에 대한 테스트가 쉬워진다.