본문은 [도메인 주도 개발 시작하기: DDD 핵심 개념 정리부터 구현까지]를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
7.1 여러 애그리거트가 필요한 기능
- 한 애그리거트에 넣기 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안 된다
- 억지로 구현하면 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고 외부에 대한 의존이 높아지게 되며 코드를 복잡하게 만들어 수정을 어렵게 만드는 요인이 된다
- 게다가 애그리거트의 범위를 넘어서는 도메인 개념이 애그리거트에 숨어들어 명시적으로 드러나지 않게 된다
- 도메인 기능을 별도 서비스로 구현함으로써 이런 문제를 해결할 수 있다
7.2 도메인 서비스
- 도메인 서비스는 도메인 영역에 위치한 도메인 로직을 표현할 때 사용한다
- 주로 다음 상황에서 도메인 서비스를 이용한다
- 계산 로직: 여러 애그리거트가 필요한 계산 로직이나, 한 애그리거트에 넣기에는 다소 복잡한 계산 로직
- 외부 시스템 연동이 필요한 도메인 로직: 구현하기 위해 타 시스템을 사용해야 하는 도메인 로직
1) 계산 로직과 도메인 서비스
- 한 애그리거트에 넣기 애매한 도메인 개념을 구현할 때 도메인 서비스를 이용하면 도메인 개념이 보다 명시적으로 드러나게 된다
- 응용 영역의 서비스가 응용 로직을 다룬다면 도메인 서비스는 도메인 로직을 다룬다
- 도메인 서비스는 상태 없이 로직만 구현하며, 도메인 서비스를 구현하는 데 필요한 상태는 다른 방법으로 전달받는다
- 도메인 서비스는 도메인의 의미가 드러나는 용어를 타입과 메서드 이름으로 짓는다
- 예를 들어 할인 금액 계산 로직을 위한 도메인 서비스명은 DiscountCalculationService로 지을 수 있다
- 도메인 서비스를 사용하는 주체는 애그리거트가 될 수도 있고 응용 서비스가 될 수도 있다
- 이때, 애그리거트 객체에 도메인 서비스를 전달하는 것은 응용 서비스 책임이다
- 도메인 서비스를 애그리거트가 사용할 때 도메인 서비스 객체를 애그리거트에 주입하지 않도록 주의해야 한다
- 도메인 모델의 데이터를 담는 필드는 모델에서 중요한 구성요소지만, 도메인 서비스 타입의 필드는 데이터 자체와는 관련이 없으며 DB의 저장 대상도 아니다
- 또 애그리거트는 일부 기능에 한해서만 도메인 서비스를 필요로 한다
- 따라서 프레임워크가 제공하는 의존성 주입(@Autowired 등)을 이용해서 의존성을 해결하기 보다는 해당 도메인 서비스 객체를 메서드의 파라미터로 전달하고, 응용 서비스에서 이를 전달받을 수 있도록 코드를 작성하자
2) 외부 시스템 연동과 도메인 서비스
- 외부 시스템이나 타 도메인과의 연동 기능도 도메인 서비스가 될 수 있다
- 시스템 간 연동은 특정 기술에 의존하지만, 도메인 입장에서는 해당 연동 기능을 도메인 로직으로 볼 수 있다
- 도메인 로직은 아래와 같이 도메인 서비스로 표현할 수 있다
- 중요한 점은 도메인 로직 관점에서 인터페이스를 작성했다는 것이다
- 외부 시스템과 연동한다는 관점으로 인터페이스를 작성하지 안핬다
// 사용자가 설문 조사 생성권한을 가진 역할인지 확인하는 도메인 서비스
public interface SurveyPermissionChecker {
boolean hasUserCreationPermission(String userId);
}
- 응용 서비스는 이 도메인 서비스를 이용해서 생성 권한을 검사하고, 인터페이스를 구현한 클래스는 인프라스트럭처에 영역에 위치한다
3) 도메인 서비스의 패키지 위치

- 도메인 서비스는 도메인 로직을 표현하므로 다른 도메인 구성요소와 동일한 패키지에 위치한다
- 도메인 서비스의 개수가 많거나 엔티티나 밸류와 같은 다른 구성요소와 명시적으로 구분하고 싶다면 domain 패키지 밑에 domain.model, domain.service, domain.repository와 같이 하위 패키지를 구분하여 위치시켜도 된다
4) 도메인 서비스의 인터페이스와 클래스
- 도메인 서비스의 로직이 고정되어 있지 않은 경우 도메인 서비스 자체를 인터페이스로 구현하고 이를 구현한 클래스를 둘 수도 있다
- 특히 도메인 로직을 외부 시스템이나 별도 엔진을 이용해서 구현할 때 인터페이스와 클래스를 분리하게 된다

- [그림 7.2]와 같이 도메인 서비스의 구현이 특정 구현 기술에 의존하거나 외부 시스템의 API를 실행한다면 도메인 영역의 도메인 서비스는 인터페이스로 추상화해야 한다
- 이를 통해 도메인 영역이 특정 구현에 종속되는 것을 방지할 수 있고 도메인 영역에 대한 테스트가 쉬워진다
'책 > 도메인 주도 개발 시작하기: DDD 핵심 개념 정리부터 구현까지' 카테고리의 다른 글
[도메인 주도 개발 시작하기] 9장: 도메인 모델과 바운디드 컨텍스트 (1) | 2022.10.28 |
---|---|
[도메인 주도 개발 시작하기] 8장: 애그리거트 트랜잭션 관리 (0) | 2022.10.24 |
[도메인 주도 개발 시작하기] 6장: 응용 서비스와 표현 영역 (0) | 2022.10.14 |
[도메인 주도 개발 시작하기] 5장: 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2022.10.07 |
[도메인 주도 개발 시작하기] 4장: 리포지터리와 모델 구현 (0) | 2022.10.03 |
본문은 [도메인 주도 개발 시작하기: DDD 핵심 개념 정리부터 구현까지]를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
7.1 여러 애그리거트가 필요한 기능
- 한 애그리거트에 넣기 애매한 도메인 기능을 억지로 특정 애그리거트에 구현하면 안 된다
- 억지로 구현하면 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고 외부에 대한 의존이 높아지게 되며 코드를 복잡하게 만들어 수정을 어렵게 만드는 요인이 된다
- 게다가 애그리거트의 범위를 넘어서는 도메인 개념이 애그리거트에 숨어들어 명시적으로 드러나지 않게 된다
- 도메인 기능을 별도 서비스로 구현함으로써 이런 문제를 해결할 수 있다
7.2 도메인 서비스
- 도메인 서비스는 도메인 영역에 위치한 도메인 로직을 표현할 때 사용한다
- 주로 다음 상황에서 도메인 서비스를 이용한다
- 계산 로직: 여러 애그리거트가 필요한 계산 로직이나, 한 애그리거트에 넣기에는 다소 복잡한 계산 로직
- 외부 시스템 연동이 필요한 도메인 로직: 구현하기 위해 타 시스템을 사용해야 하는 도메인 로직
1) 계산 로직과 도메인 서비스
- 한 애그리거트에 넣기 애매한 도메인 개념을 구현할 때 도메인 서비스를 이용하면 도메인 개념이 보다 명시적으로 드러나게 된다
- 응용 영역의 서비스가 응용 로직을 다룬다면 도메인 서비스는 도메인 로직을 다룬다
- 도메인 서비스는 상태 없이 로직만 구현하며, 도메인 서비스를 구현하는 데 필요한 상태는 다른 방법으로 전달받는다
- 도메인 서비스는 도메인의 의미가 드러나는 용어를 타입과 메서드 이름으로 짓는다
- 예를 들어 할인 금액 계산 로직을 위한 도메인 서비스명은 DiscountCalculationService로 지을 수 있다
- 도메인 서비스를 사용하는 주체는 애그리거트가 될 수도 있고 응용 서비스가 될 수도 있다
- 이때, 애그리거트 객체에 도메인 서비스를 전달하는 것은 응용 서비스 책임이다
- 도메인 서비스를 애그리거트가 사용할 때 도메인 서비스 객체를 애그리거트에 주입하지 않도록 주의해야 한다
- 도메인 모델의 데이터를 담는 필드는 모델에서 중요한 구성요소지만, 도메인 서비스 타입의 필드는 데이터 자체와는 관련이 없으며 DB의 저장 대상도 아니다
- 또 애그리거트는 일부 기능에 한해서만 도메인 서비스를 필요로 한다
- 따라서 프레임워크가 제공하는 의존성 주입(@Autowired 등)을 이용해서 의존성을 해결하기 보다는 해당 도메인 서비스 객체를 메서드의 파라미터로 전달하고, 응용 서비스에서 이를 전달받을 수 있도록 코드를 작성하자
2) 외부 시스템 연동과 도메인 서비스
- 외부 시스템이나 타 도메인과의 연동 기능도 도메인 서비스가 될 수 있다
- 시스템 간 연동은 특정 기술에 의존하지만, 도메인 입장에서는 해당 연동 기능을 도메인 로직으로 볼 수 있다
- 도메인 로직은 아래와 같이 도메인 서비스로 표현할 수 있다
- 중요한 점은 도메인 로직 관점에서 인터페이스를 작성했다는 것이다
- 외부 시스템과 연동한다는 관점으로 인터페이스를 작성하지 안핬다
// 사용자가 설문 조사 생성권한을 가진 역할인지 확인하는 도메인 서비스
public interface SurveyPermissionChecker {
boolean hasUserCreationPermission(String userId);
}
- 응용 서비스는 이 도메인 서비스를 이용해서 생성 권한을 검사하고, 인터페이스를 구현한 클래스는 인프라스트럭처에 영역에 위치한다
3) 도메인 서비스의 패키지 위치

- 도메인 서비스는 도메인 로직을 표현하므로 다른 도메인 구성요소와 동일한 패키지에 위치한다
- 도메인 서비스의 개수가 많거나 엔티티나 밸류와 같은 다른 구성요소와 명시적으로 구분하고 싶다면 domain 패키지 밑에 domain.model, domain.service, domain.repository와 같이 하위 패키지를 구분하여 위치시켜도 된다
4) 도메인 서비스의 인터페이스와 클래스
- 도메인 서비스의 로직이 고정되어 있지 않은 경우 도메인 서비스 자체를 인터페이스로 구현하고 이를 구현한 클래스를 둘 수도 있다
- 특히 도메인 로직을 외부 시스템이나 별도 엔진을 이용해서 구현할 때 인터페이스와 클래스를 분리하게 된다

- [그림 7.2]와 같이 도메인 서비스의 구현이 특정 구현 기술에 의존하거나 외부 시스템의 API를 실행한다면 도메인 영역의 도메인 서비스는 인터페이스로 추상화해야 한다
- 이를 통해 도메인 영역이 특정 구현에 종속되는 것을 방지할 수 있고 도메인 영역에 대한 테스트가 쉬워진다
'책 > 도메인 주도 개발 시작하기: DDD 핵심 개념 정리부터 구현까지' 카테고리의 다른 글
[도메인 주도 개발 시작하기] 9장: 도메인 모델과 바운디드 컨텍스트 (1) | 2022.10.28 |
---|---|
[도메인 주도 개발 시작하기] 8장: 애그리거트 트랜잭션 관리 (0) | 2022.10.24 |
[도메인 주도 개발 시작하기] 6장: 응용 서비스와 표현 영역 (0) | 2022.10.14 |
[도메인 주도 개발 시작하기] 5장: 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2022.10.07 |
[도메인 주도 개발 시작하기] 4장: 리포지터리와 모델 구현 (0) | 2022.10.03 |