본문 바로가기
DDD&MSA

[DDD] Domain 영역의 구성 요소 맛보기(with 애플리케이션 아키텍처)

by 덩라 2023. 5. 29.

본 포스팅은 DDD 를 공부하면서 정리하기 위한 포스팅입니다.

출처 : 도메인 주도 개발 시작하기 - DDD 핵심 개념 정리부터 구현까지 (저자. 최범균)

1. 계층 구조 아키텍처 

애플리케이션 아키텍처를 설계할 때, 가장 기본적으로 많이 사용하는 구조는 아래와 같습니다.

각 계층의 특징은 아래와 같습니다.

표현(Presentation) 클라이언트(사용자, 외부시스템 같은 요청을 보내는 주체)의 요청을 처리하고, 처리된 결과를 응답해주는 계층
웹 애플리케이션에서 사용하는 Controller 가 이 계층에 속한다.
응용(Application) 표현 계층에서 가공된 요청값을 받아 로직을 실행해서 결과를 표현 계층에 전달하는 계층
웹 애플리케이션에서 사용하는 Service 가 이 계층에 속한다. DDD 관점에서는 해당 계층에 비지니스 로직을 구현하지 않고, 도메인 계층의 기능을 조합하여 처리하도록 한다.
도메인(Domain) 구현하고자 하는 도메인의 규칙을 토대로 기능을 정의하는 계층
웹 애플리케이션에서 사용하는 Repository 가 이 계층에 속한다. DDD 관점에서는 해당 계층에 기능을 구현한다.
인프라(Infra Structure) 애플리케이션 내 로직을 처리하는데 필요한 외부 시스템에 연동을 처리하는 계층
인프라 계층은 특정 외부 시스템에 종속된 기술을 구현한다.
(예시. DB 와 연동하여 데이터를 처리, Kafka 같은 메세징 큐에 메세지를 전달하는 기능을 구현)

해당 구조의 아키텍처를 구성하면, 상위 계층은 하위 계층 만 의존하고, 역방향으로의 의존을 허용하지 않는 것이 좋습니다.

(이 때, 바로 하위 계층을 의존하는 것이 바람직하지만 다른 하위 계층을 의존하는 것도 필요하다면 괜찮습니다. )

 

2. 요청 처리 흐름

DDD 관점에서 위 계층을 적용했을 때 실제 요청에 대한 흐름을 정리해보면 아래와 같습니다.

 

위 흐름에서 중요하게 봐야할 부분은 바로 2. 도메인 조회 ~ 5. 도메인 로직 실행 구간입니다.

DDD 는 도메인에 기능을 정의하고 상위 계층에서 도메인의 기능을 호출만 하도록 하기 때문에, 실질직으로 비지니스 로직 실행을 도메인 계층에서 한다는 점이 중요한 점입니다.

 

3. 도메인 영역 내 구성요소

앞서 설명한 애플리케이션 아키텍처에서 실제로 비지니스 로직을 처리하는 영역을 도메인(Domain)영역 입니다.

이처럼 도메인 영역에서 비지니스 로직을 구현하기 위해 사용되는 구성요소들은 무엇이 있는지 알아보겠습니다.

 

3-1. 엔티티(Entity) & 밸류(Value)

엔티티와 밸류는 도메인 모델을 표현하기 위한 객체로써 사용됩니다. 해당 내용들은 앞 전 포스팅에서 설명한 바 있기 때문에 아래 링크를 참고해주시면 됩니다.

https://byunsw4.tistory.com/13(DDD - 엔티티(Entity)와 밸류(Value)

 

3-2. 애그리거트(Aggregate)

애그리거트관련된 도메인 객체들의 집합을 의미하며, 코드상에서 표현된다기 보단 개념적인 요소에 가깝습니다.

필자가 구현 중인 쇼핑몰을 대략적으로 도메인 모델로 표현해본다면 아래와 같은 모습으로 표현됩니다.

위 다이어그램에서 연관된 도메인을 영역으로 구분해본다면 아래 처럼 구분 지을 수 있을 것 입니다.

연관된 도메인 객체를 군집화한 다이어그램

위 다이어그램에서 음영 처리된 영역이 연관된 도메인 객체들의 집합이라고 할 수 있는데, 이러한 그룹을 애그리거트 라고 부릅니다.

위 다이어그램에서 음영을 처리한 기준은, 객체들간 생명주기가 동일한지 입니다.
Order 라는 엔티티는 주문 도메인을 의미하며, 주문이 생성되는 시점에서 같은 영역에 표시된 엔티티나 밸류들이 모두 생성되지만,
Product 라는 상품 도메인의 경우, Product 가 생성된다고 해서 Review (상품 리뷰) 나 Qna(상품 문의) 가 생성되는 것이 아니기에
같은 애그리거트로 분류하지 않았습니다.

 

애그리거트가 표현될 때, 관련된 도메인 객체를 대표하는 Root Entity가 존재하는데, 주문 도메인의 경우 Order 가 Root Entity가 됩니다. 특정 애그리거트에 속하는 Entity 혹은 Value 을 생성/변경하는 로직은 Root Entity 내에서 기능으로 구현되며, Root Entity를 사용하는 코드에서는 Root Entity 를 통해, Root Entity 하위에 있는 Entity 나 Value로 간접적으로 접근하여 원하는 로직을 처리하게 됩니다.

 

3-3. 리포지토리(Repository)

리포지토리(Repository) 는 도메인 객체의 지속적인 사용을 위해 객체를 특정 저장소에 관리하는 모델입니다.

(저장소는 DB나 파일시스템 등 지속적인 관리가 가능한 시스템을 의미합니다.)

 

도메인 구성 요소에서 Entity 나 Value 가 요구사항을 통해 도출되는 모델 이라고 하면, 리포지토리는 실제 구현을 통해 도출되는 모델이라고 할 수 있습니다. 예를 들어, Order 도메인을 저장하고 조회하기 위해 아래와 같은 Repository 를 선언할 수 있습니다.

public interface OrderRepository {
    Order findByOrderCode(String orderCode);
    Order save(Order order);
}

 

해당 interface는 Order 라는 도메인 객체를 저장하고 조회하는 기능을 정의합니다. 

interface로 정의한 이유는 앞서 말한 "지속적인 관리가 가능한 시스템" 이 무엇이 될 지 모르기 때문입니다.

저장하고 조회한다는 기능을 모든 저장소에서 동일하게 수행할 수 있지만, 그 저장소가 DB 냐 파일시스템이냐에 따라 실제 구현로직이 다르기 때문에 도메인 영역에서의 Repository 는 interface 를 의미하고, 실제 구현되는 DBRepository, FileRepository 같은 구현체는 애플리케이션 아키텍처 상에서 인프라 영역에 속한다고 할 수 있습니다.

3-4. 도메인 서비스(Domain Service)

도메인 서비스는 어떠한 비지니스 로직이 특정 도메인에 국한되어 있지 않고, 여러 도메인과 관련되어 있는 경우 해당 로직을 구현하는 모델을 말합니다. 

예를 들어, 어떤 주문에 대해 금액을 할인받는 정책이 있다고 한다면 회원등급, 쿠폰 등 다양한 할인 방식이 해당 로직에 필요할 수 있습니다.

이런 경우, 특정 도메인 만으로는 정확한 결과를 도출할 수 없으므로 도메인 서비스에 해당하는 객체를 생성해 로직을 구현할 수 있습니다.

댓글