7장 - 도메인 서비스

『도메인 주도 개발 시작하기 - DDD 핵심 개념 정리부터 구현까지』를 읽고 정리한 내용입니다.

도메인 서비스

도메인 서비스는 하나의 애그리거트만으로 구현하기 어려운 도메인 로직을 담당하는 객체를 의미한다.

하나의 Entity나 Aggregate에 해당 로직을 넣으면 책임이 과도하게 집중되거나 자연스럽지 않은 경우가 있다. 이때 해당 로직을 도메인 서비스로 분리하여 구현할 수 있다.

사용하는 경우

도메인 서비스는 다음과 같은 경우에 사용할 수 있다.

  • 여러 애그리거트의 정보가 함께 필요한 경우
  • 특정 애그리거트에 포함시키기 애매한 도메인 로직이 있는 경우
  • 외부 시스템과 연동해야 하는 도메인 로직이 있는 경우

NOTE

도메인 서비스는 "어디에도 자연스럽게 속하지 않는 도메인 로직" 을 구현하기 위한 객체이다.

즉, 도메인 서비스는 단순히 여러 객체를 사용하는 기능을 모아두는 곳이 아니라 특정 Entity나 Aggregate에 속시키기 어려운 핵심 비즈니스 규칙을 표현하는 역할을 담당한다.

예시

예를 들어 주문에 대한 할인 금액을 계산한다고 가정한다.

주문(Order)
      │
      ├──────────────┐
      ▼              ▼
회원(Member)      할인 정책(Policy)
                     │
                     ▼
              할인 금액 계산

할인 금액을 계산하기 위해 Order의 주문 금액과 Member의 회원 등급, 그리고 할인 정책이 모두 필요한 상황이다.

이러한 로직은 다음과 같은 이유로 하나의 애그리거트에 넣기 어렵다.

  • Order만으로는 필요한 정보를 모두 가지고 있지 않다.
  • Member만으로도 할인 금액을 계산할 수 없다.
  • 할인 정책 자체도 별도의 도메인 개념이 될 수 있다.

따라서 할인 금액 계산과 같은 로직을 별도의 도메인 서비스로 분리할 수 있다.

DiscountCalculationService

이렇게 하면 할인 계산이라는 비즈니스 규칙을 특정 애그리거트에 억지로 포함시키지 않고 별도의 도메인 서비스로 명확하게 표현할 수 있다.

응용 서비스와 역할 분리

응용 서비스와 도메인 서비스는 모두 서비스라는 이름을 사용하지만 담당하는 책임이 다르다.

Application Service
      │
      ├─ 트랜잭션
      ├─ 흐름 제어
      └─ 도메인 서비스 호출
                │
                ▼
      Domain Service
                │
                ▼
      도메인 로직 수행

응용 서비스

응용 서비스는 유스케이스를 수행하기 위한 전체적인 흐름을 제어하는 역할을 담당한다.

주요 책임은 다음과 같다.

  • 유스케이스를 수행한다.
  • 트랜잭션을 관리한다.
  • 필요한 도메인 객체를 조회한다.
  • 도메인 객체에 기능 수행을 위임한다.
  • 필요한 경우 도메인 서비스를 호출한다.

도메인 서비스

도메인 서비스는 핵심 비즈니스 규칙을 수행하는 역할을 담당한다.

주요 책임은 다음과 같다.

  • 도메인 로직을 수행한다.
  • 여러 애그리거트에 걸친 비즈니스 규칙을 처리한다.
  • 특정 애그리거트에 속시키기 어려운 도메인 로직을 표현한다.
  • 유스케이스의 전체적인 흐름이나 트랜잭션을 관리하지 않는다.

NOTE

로직의 성격에 따라 담당 영역을 구분하는 것이 중요하다.

  • 비즈니스 규칙 → 도메인 영역
  • 유스케이스의 흐름 제어와 트랜잭션 → 응용 서비스

따라서 응용 서비스가 복잡해진다면 비즈니스 규칙이 응용 서비스에 포함되어 있는지 확인할 필요가 있다.

반대로 도메인 서비스에 유스케이스의 흐름이나 트랜잭션 처리 코드가 들어가 있다면 응용 서비스와 도메인 서비스의 책임이 뒤섞인 것으로 볼 수 있다.

패키지 위치

도메인 서비스는 도메인 영역에 위치한다.

예를 들어 다음과 같이 구성할 수 있다.

domain
 ├── member
 ├── order
 ├── product
 └── service
      └── DiscountCalculationService

도메인 서비스는 핵심 비즈니스 로직을 담당하기 때문에 도메인 영역에 위치한다.

필요한 경우 도메인 서비스에서도 Repository나 외부 시스템과의 연동이 필요할 수 있다. 이때도 구체적인 구현 기술에 직접 의존하기보다는 필요한 기능을 인터페이스로 추상화하여 의존성을 관리하는 것이 중요하다.

정리

도메인 서비스는 하나의 애그리거트에 자연스럽게 속시키기 어려운 도메인 로직을 표현하기 위한 객체이다.

특히 여러 애그리거트의 정보가 함께 필요한 비즈니스 규칙이나 특정 애그리거트에 책임을 부여하기 어려운 로직을 도메인 서비스로 분리할 수 있다.

응용 서비스와 도메인 서비스는 역할을 명확하게 구분해야 한다. 응용 서비스는 유스케이스의 흐름과 트랜잭션을 제어하고, 도메인 서비스는 핵심 비즈니스 규칙을 수행한다.

결국 도메인 서비스의 목적은 비즈니스 로직을 무조건 별도의 클래스로 분리하는 것이 아니라, 도메인 모델의 책임을 자연스럽게 배치하고 특정 애그리거트에 과도한 책임이 집중되는 것을 방지하는 것이다.