본문 바로가기

DDD, 도메인 주도 설계의 필요성

@6uiw2025. 10. 24. 23:53

 

학습 목표

1. 도메인 주도 설계의 필요성 이해한다.
2. 도메인 주도 설계의 주요 개념과 설계 방법을 이해한다.

 

 

 

DDD(도메인 주도 설계, Domain-Driven Design)

 

 

DDD는 비즈니스 중심 설계 철학이다.
단순히 코드를 구현하는 것이 아니라, 소프트웨어가 해결할 도메인을 명확히 표현하고, 비즈니스 규칙과 의도를 코드로 드러내는 것이 목표이다.

 

 

 

 

 

📌 도메인이란?

도메인은 소프트웨어로 해결하고자 하는 문제의 영역, 즉 비즈니스 핵심 주제이다.

예를 들어, 상품 주문 서비스에서 다루는 도메인은 다음과 같다.

  • 상품(Product)
  • 주문(Order)
  • 고객(Customer)
  • 결제(Payment)

각 도메인은 시스템이 해결해야 할 비즈니스 문제 단위이다.

 

 

 

 

 

 

📌 바운디드 컨텍스트(Bounded Context)

바운디드 컨텍스트는 도메인 모델이 적용되는 경계이다.

 

한 컨텍스트 안에서는 용어와 규칙이 일관되어야 한다. 즉, “하나의 모델이 하나의 의미를 가지는 범위”이다.

예를 들어, 주문 컨텍스트의 Product는 주문 가능한 상품을 의미하지만, 재고 컨텍스트의 Product는 창고에 있는 실제 물품을 의미한다.

 

이처럼 경계가 애매한 도메인은 변경 주기, 트랜잭션 범위, 책임 단위를 고려하여 컨텍스트를 분리해야 한다.
재고 수량 관리는 재고 컨텍스트에서 담당하고, 주문 컨텍스트는 productId만 참조하도록 설계한다.

 

 

 

 

📌 애그리거트(Aggregate)와 루트(Aggregate Root)

애그리거트는 하나의 도메인 객체 묶음이다.

 

하나의 비즈니스 단위로 묶여 함께 변경되어야 하는 엔티티와 밸류 객체들의 집합이다.
이 묶음의 대표자이자 외부 접근의 유일한 진입점이 애그리거트 루트(Aggregate Root)이다.

 

예: 주문 애그리거트

  • Order (루트)
  • OrderItem, Address, Money (하위 엔티티 및 밸류)

 

Order (루트)
 ├─ OrderItem
 ├─ Address
 └─ Money

 

외부에서 OrderItem을 직접 수정하면 안 되고,
항상 Order를 통해서만 수정해야 한다. 비즈니스 불변성과 일관성은 루트가 책임진다.

다른 애그리거트는 ID 기반 참조만 가능하고, 트랜잭션도 한 루트 단위로 유지해야 한다.

이는 도메인의 불변성과 일관성을 유지하기 위함이다.

 

 

 

<애그리거트 루트의 규칙>

규칙 설명
외부에서는 루트만 접근 가능 하위 엔티티는 루트를 통해서만 수정 가능하다.
루트가 일관성을 보장한다 모든 비즈니스 규칙 검증은 루트가 담당한다.
다른 애그리거트는 ID로만 참조한다 루트끼리만 약한 연결을 맺는다.
루트는 전역 식별자를 가져야 한다 시스템 내 유일 ID를 갖는다.
트랜잭션은 애그리거트 단위로 유지된다 하나의 루트만 수정해야 한다.

 

 

<바운디드 컨텍스트와 애그리거트 개념 비교>

구분 바운디드 컨텍스트 애그리거트
레벨 시스템/모듈 수준 도메인 모델 내부 수준
목적 모델 경계, 언어 일관성 데이터 일관성, 트랜잭션 단위
범위 큰 단위, 여러 모델 포함 가능 하나의 루트 엔티티와 관련 객체 묶음
접근 외부와 통신 가능, API 필요 외부에서는 루트 엔티티를 통해서만 접근
예시 주문관리, 상품관리, 회원관리 Order, ProductInventory, ShoppingCart

 

바운디드 컨텍스트와 애그리거트를 어떻게 구분하고 설계해야 할지 애매한 상황이 존재할 수있다.

상품과 재고를 예를 들면, 보통 음식점과 같은 비즈니스 영역에선 상품과 재고의 의미가 동일시되어 하나의 애그리거트로 볼 수도 있지만,

큰 물류회사에서 창고에서 재고관리를 따로 한다면, 하나의 애그리거트로 보지 않고 분리하여 따로 관리해야할 수도 있다.

따라서 어떻게 설계해야 하는지 하나의 정답이 존재하는 것이 아닌 개발해야 하는 대상의 비즈니스 모델과 요구사항에 따라 다른 설계가 가능하다.

 

 

📌 도메인 간 의존관계

DDD에서 가장 중요한 것은 의존의 방향과 강도이다.
객체 간 단순 연결이 아니라, 비즈니스 결합 정도에 따라 관계를 조정해야 한다.

 

 

✅ 다른 애그리거트 간

  • ID 참조(약한 결합)로만 연결해야 한다.
  • 예: Order가 Customer를 직접 들고 있으면 결합도가 높아지므로
    customerId만 저장하고, 실제 객체 조회는 리포지토리를 통해 수행한다.

 

✅ 여러 애그리거트가 협력해야 할 때

  • 도메인 서비스(Domain Service)를 사용한다.
  • 도메인 서비스는 여러 루트 간의 행위를 조율한다.
  • 예: 결제 시 주문, 고객, 결제 애그리거트가 함께 사용될 때
    PaymentService에서 각 애그리거트를 주입받아 처리한다.

 

 다른 컨텍스트나 시스템에 있는 애그리거트는 외부 통신 필요.

  • REST, gRPC, 메시지 큐 활용
  • 퍼사드(Facade)를 통해 도메인이 외부 구현에 의존하지 않도록 설계

 

 

 

 

 

📌 레이어드 아키텍처에서 DDD 구현

Presentation Layer → Application Layer → Domain Layer → Infrastructure Layer
  • Presentation Layer: 요청 수신, DTO 변환
  • Application Layer: 트랜잭션 관리, 유즈케이스 조율
  • Domain Layer: 비즈니스 로직 핵심
  • Infrastructure Layer: DB, 외부 API 구현

의존 방향은 위에서 아래로만 흐르며, Domain은 기술 세부사항에 의존하지 않는다.
Repository 인터페이스는 Domain, 구현체는 Infrastructure에 둔다.

 

 

 

 

✔️ 의존관계 원칙 

계층 역할 의존 대상 금지 사항
Presentation 요청 수신, DTO 변환 Application Domain 직접 접근 금지
Application 트랜잭션 관리, 도메인 조율 Domain 기술 코드 포함 금지
Domain 비즈니스 로직 핵심 없음 (순수) Spring, JPA 의존 금지
Infrastructure DB, 외부 API 구현 Domain의 인터페이스 비즈니스 로직 포함 금지

 

 

 

 

📌 DDD 핵심 규칙

  • 도메인은 외부 기술에 의존하지 않고, 비즈니스 로직만 포함
  • 의존 방향은 Controller → Service → Domain → Infrastructure
  • Repository 인터페이스는 Domain, 구현체는 Infrastructure
  • 트랜잭션은 한 애그리거트만 수정
  • 도메인 간 협력은 서비스/이벤트를 통해 처리, 직접 참조 금지
  • 코드가 비즈니스 의도를 명확히 드러내도록 설계
  • 경계 결정 시 변경 주기, 트랜잭션 범위, 책임 단위를 고려

 

 

 

 

 

 

 

 

📌 결론

DDD는 단순히 코드를 구조화하는 방법이 아니라 비즈니스 언어를 코드로 표현하는 철학이다.


도메인은 시스템의 중심이고, 애그리거트는 도메인의 경계를 명확히 지킨다.
서로 다른 컨텍스트는 ID 참조 + 퍼사드/외부 통신으로 연결하며,
코드가 도메인의 의도와 규칙을 설명하도록 설계하는 것이 핵심이다.

6uiw
@6uiw :: LOG.INFO("MING's DEVLOG")

개발을 하면서 공부한 기록을 남깁니다

목차