취미겸생업

[Architecture] 도메인과 DDD, 전략적 설계 본문

IT/Architecture

[Architecture] 도메인과 DDD, 전략적 설계

nohumb 2026. 7. 21. 15:51
SMALL

Domain-Driven Design

Domain

Domain(도메인)이란

도메인의 예시

DDD를 알아보기 전에 우선 도메인에 대한 정의부터 한다. 도메인이란 소프트웨어를 통해 해결하려는 현실 세계의 비즈니스 영역과 그 안의 규칙을 정의한다.

도메인이란, ‘무엇을 만드는가’가 아닌 ‘무슨 문제를 해결하는가’를 나타내는 개념이다. 예시를 통해 직관적으로 이해해보자.

  • 예시
    • 쇼핑몰 : 주문, 결제, 배송, 회원
    • 은행 : 계좌, 송금, 대출
    • 영어 학습 : 단어장, 단어, 뜻, 퀴즈

위의 예시는 DB 테이블에 저장되는 데이터의 단위 위주로 가장 단순하게 생각할 수 있는 도메인들이다.

다만, 도메인 영역은 ERD에 배치된 테이블과 같다고 할 수는 없다. DB에 저장되는 단위는 데이터 저장의 영역일 뿐이며, DB 엔티티와 도메인을 같은 선상에 둘 경우 비즈니스 영역이 데이터 중심으로 흘러가게 되는데, 이는 도메인 영역이 DB 구조에 종속되는 결과를 초래할 수 있다.

따라서, 비즈니스 영역에 따라 단어장/단어/뜻을 모두 같은 도메인으로 둘 수 있고, 주문/결제를 같은 도메인에 둘 수도 있으며, 송금 도메인을 계좌이체/예약이체/자동이체와 같은 서브 도메인으로 나눌 수도 있다.

요점은, 도메인은 도메인 전문가와 개발자가 같은 의미로 사용하는 보편 언어(Ubiquitous Language)의 정의에 따라, 또 비즈니스의 규모영역에 따라 나뉠 수 있는 것이다.


DDD(Domain-Driven Design)

비즈니스 도메인을 중심으로 소프트웨어 모델과 코드를 설계하여, 복잡한 비즈니스 규칙을 유지보수하기 쉽게 만드는 설계 방법론

DDD 원칙

본격적으로 Bounded Context, Aggregate, VO와 같은 핵심 개념을 다루기 전에 개념적인 DDD 원칙을 먼저 알아보자. (원칙에 나오는 개념은 차근차근 설명할 예정)

  • 에릭 에반스(Eric Evans)의 원칙
    • 소프트웨어는 데이터가 아닌 비즈니스 도메인 중심으로 설계해야 한다 (DB 중심 설계 탈피)
    • 모델과 코드가 실제 업무를 반영해야 한다 (보편 언어, Uniquitous Languagee)
    • 복잡한 비즈니스 로직은 도메인 모델 안에 표현되어야 한다 (풍부한 도메인 모델, Rich Domain)
      • 즉, 데이터와 행위를 함께 캡슐화하여 도메인 모델이 스스로 비즈니스 규칙을 표현하도록 한다
    • 모델이 달라지는 곳에서는 Bounded Context를 분리하며, Context마다 공통 언어가 달라질 수 있다
    • Aggregate
      • 관련 객체들을 하나의 영역(Aggregate)로 묶는다
      • 외부에선 오직 대표 객체(Aggregate Root)를 통해서만 내부 객체를 변경한다
      • Repository는 Aggregate 단위로만 사용하며, Aggregate Root에 대한 Repository만 제공해야 한다

위의 원칙은 2003년, DDD를 처음 고안한 에릭 에반스(Eric Evans)에 따른다.

이러한 원칙에 더해 Aggregate에 대한 원칙을 본 버논(Vaughn Vernon)이 구체화하고 보완한 부분이 존재한다. 따라서 아래의 현대화 된 원칙을 추가로 알아보자.

  • 본 버논(Vaughn Vernon)의 Aggregate 설계 원칙
    • Aggregate는 가능한 작게 설계한다
      • 강한 일관성이 필요한 범위만 포함하여 Aggregate를 최소화하여 동시성과 성능 향상
    • Aggregate는 Transaction Boundary이다 (트랜잭션 일관성)
      • 하나의 트랜잭션에선 가능한 하나의 Aggregate만 수정한다
      • 하나의 Aggregate는 가능한 하나의 Lock만 걸리도록 설계한다
      • 즉, Aggregate 간 즉시 일관성이 필요한 규칙만 Aggregate 내부에 둔다
    • Aggregate 간에는 객체 참조 대신 ID를 사용한다
      • 다른 Aggregate의 객체를 직접 갖으면 결합도 증가
    • Aggregate는 비즈니스 불변식(Business Invariant)을 보호하는 일관성 경계이다
      • 즉, 비즈니스 규칙이 항상 만족되도록(일관성) 보장하는 경계로, Aggregate 내부에서 트랜잭션이 완료되면 항상 비즈니스 규칙은 만족되어야 함
    • 특정 Aggregate에 자연스럽게 속하지 않는 도메인 규칙은 Domain Service로 분리한다
      • 여러 Aggregate가 협력하지만 특정 Aggregate 책임으로 보기 어려운 도메인 규칙을 담당
      • ex) ReviewService는 Application Service, RatingCalculator는 Domain Service
    • Aggregate 간 느슨한 결합과 최종 일관성을 위해 Domain Event를 활용한다 (Eventual Consistency)

위에서 알아본 규칙은 전략적(Strategic) 설계와 전술적(Tactical) 설계 요소로 나누어 설명할 수 있다. 이번 포스팅에선 전략적 설계만 우선 설명하고, 전술적 설계(Aggregate, VO, Entity 등)는 다음 포스트에서 다룰 예정이다.


DDD 전략적(Strategic) 설계

"무엇을 만들고, 영역을 어떻게 나눌 것인가?”


전략적 설계는 시스템의 큰 그림을 그리고 비즈니스 경계를 명확히 구분하여 “복잡성을 통제 가능한 크기로 나누는 작업”이다.

도메인 분해 (Subdomain)

서브 도메인 분해

비즈니스 도메인은 비즈니스 가치와 중요도에 따라 여러 서브도메인으로 분리하여 설계할 수 있다.

  • 핵심 서브도메인 (Core)
    • 비즈니스의 핵심, 가장 많은 리소스를 투자해야 하는 부분
    • ex) 배달 앱의 ‘실시간 라이더 매칭 알고리즘’
  • 지원 서브도메인 (Supporting)
    • 비즈니스 운영에 필수적이지만 핵심 경쟁력은 아닌 부분
    • ex) 배달 앱의 ‘메뉴 등록 및 가게 관리 시스템’
  • 일반 서브도메인 (Generic)
    • 비즈니스에 필요하지만, 특별할 것은 없는 부분
    • 상용 솔루션(Saas)이나 외부 라이브러리 도입으로 해결되는 부분
    • ex) PG 결제 연동, SMS 또는 Push 알림 등

보편 언어 (Ubiquitous Language)

개발자, 기획자, 도메인 전문가가 하나의 맥락 속에서 통일하여 사용하는 공통 언어이다.

개발자가 도메인 전문가의 언어를 코드로 번역하고, 반대로 전문가가 개발자의 언어를 기획으로 번역하는 순간, 모델은 파편화되고 소프트웨어는 도메인의 본질에서 이탈한다.

  • 원칙
    • 대화, 설계 문서, 클래스/메서드/DB 스키마 이름 모두 단 하나의 통일된 언어을 사용
    • 모든 도메인에서 보편적으로 사용되는 언어가 아닌, 지정된 Bounded Context 내부에서만 유효
      • ex) User - X, Orderer - O
    • 데이터 속성에 국한되지 않고, 비즈니스 행위와 의도(동사)를 명확히 표현
      • ex) createOrder() - X, placeOrder() - O
    • 고정된 명세가 아니며, 도메인의 확장에 따라 지속적으로 정제하고 수정
      • 용어의 변화는 즉시 리팩토링으로 이어져야 함
  • 주의점
    • 정적인 용어 명세서보다 중요한 것은 실제 코드와 팀원 간 구두 대화의 일치 여부
      • 팀원 간 대화 중 언어가 불필요하게 길거나 어색하다면 언어의 정의가 제대로 되지 않은 것
    • DTO, DAO, List, Flag 등 기술적 용어를 혼용하지 않음
      • OrderList - X, Orders 또는 OrderHistory - O
    • 빈약한 도메인 모델(Anemic Domain Model)을 지양
    • 언어 변경 시 리팩토링 공수는 수용해야 함

Bounded Context

Bounded Context는 비즈니스 영역이 같은 것, 즉 유비쿼터스 언어가 유효한 명확한 경계이다. 도메인 모델은 이 경계 안에서만 완전한 의미를 갖는다. 또한, 주로 하나의 Context 당 하나의 팀이 할당된다.

바운디드 컨텍스트

  • 서브도메인과의 차이
    • 서브도메인은 비즈니스 영역을 위한 단위, 바운디드 컨텍스트는 이러한 비즈니스 문제의 해결을 위한 논리적인 경계
    • 여러 서브도메인이 하나의 바운디드 컨텍스트에 놓일 수 있음
    • 하나의 서브도메인이 하나의 바운디드 컨텍스트일 수 있음
  • 특성
    • 도메인 모델은 컨텍스트 내의 용도에 따라 다르게 취급되어야 함 (모델 정의)
    • 잘 정의된 Bounded Context는 하나의 마이크로서비스 경계로 활용됨
    • 모든 서브 도메인이 참조하는 단일 객체 모델은 지양
    • 타 Bounded Context의 DB를 직접 참조하지 않고 손상 방지 계층을 이용

Context Map

컨텍스트 맵 예시

컨텍스트 맵은 독립적으로 존재하는 바운디드 컨텍스트(Bounded Context) 간의 경계와 관계, 그리고 데이터/모델의 흐름을 시각화한 지도로 정의된다. 조직 관계를 시각화하는 것이 주 목적이다.

Bounded Context 간에는 제공자(Upstream)와 소비자(Downstream)의 관계가 형성되며, 대부분의 Context Mapping Pattern은 이 관계를 기반으로 선택된다.

Context Map 작성에 사용되는 패턴은 9가지가 있는데, 이를 관계 중심 패턴기술 중심 패턴으로 분류해서 정리하면 아래와 같다. 아래의 패턴을 사용해서 Bounded Context의 관계를 시각화한 것이 Context Map이다.

  • Organizational & Relationship 패턴 (관계 중심 패턴)
    • Partnership (파트너쉽) : 두 팀이 동등하게 협력하여 양쪽의 변경 사항을 함께 맞추는 관계
    • Customer-Supplier (고객-공급자) : Upstream(공급자) 팀이 Downstream(고객) 팀의 요구사항을 반영해 주어야 하는 정치적 종속 관계
    • Big Ball of Mud (진흙탕) : 경계와 규칙 없이 얽혀서 조직적인 통제력을 상실한 상태 (레거시)
    • Separate Ways (각자의 길) : 팀 간 협상 및 통합 비용이 너무 커서, 아예 관계를 끊고 각자 개발하기로 결정된 상태, 기술적 통합 없음
  • Technical & Model Integration 패턴 (기술 중심 패턴)
    • Anti-Corruption Layer (ACL, 손상 방지 계층)
      • 타 시스템이 도메인을 오염시키지 않도록 중간 번역 계층을 두는 방식
      • Upstream이 통제 불능이거나 요구사항을 반영해주지 않을 때 사용
    • Conformist (순응자/준수자)
      • Upstream의 모델 변환 없이 그대로 받아들여 사용하는 방식
      • Upstream이 이미 완벽하거나, 요구사항을 반영해주지 않는데 ACL을 구축할 여력이 없을 때 사용
    • Open Host Service (OHS, 공개 호스트 서비스)
      • 다수 소비자를 위해 표준화된 접근 인터페이스(REST API, gRPC 등)를 구축해 제공하는 방식
      • Upstream이 요구사항을 반영해주는 경우 PL과 함께 사용
    • Published Language (PL, 공표된 언어)
      • 통신 시 내부 도메인 모델을 직접 노출하지 않고, 양측이 합의한 공통 데이터 계약표준화된 데이터 포맷(JSON, XML, Protobuf 등)으로 표현하여 사용하는 방식
    • Shared Kernel (공유 커널)
      • 도메인 모델 일부(DB/코드)를 공유하거나 공통 포맷을 합의 하에 함께 관리하는 방식
      • 서로 긴밀한 협력이 가능한 관계에서 주로 사용

컨텍스트 맵은 조직 패턴과 기술 패턴이 함께 복합적으로 표기되어야 한다.

LIST