DDD 개요

정의

Domain-Driven Design(DDD)은 도메인의 프로세스와 규칙을 풍부하게 담은 도메인 모델을 프로그래밍하는 데 개발의 중심을 두는 소프트웨어 개발 접근법이다. 2003년 Eric Evans의 책 Domain-Driven Design: Tackling Complexity in the Heart of Software에서 이름이 유래했다.

Evans 본인은 DDD를 세 가지로 요약한다.

  1. Core Domain에 집중한다.
  2. 도메인 전문가와 소프트웨어 전문가의 창의적 협업으로 모델을 탐구한다.
  3. 명시적으로 경계 지어진 컨텍스트 안에서 하나의 보편 언어를 사용한다.

Martin Fowler는 Evans의 기여를 “모델링 표기법 논쟁을 넘어서는 어휘를 만든 것"으로 평가한다. 도메인 모델이 중요하다는 주장 자체는 1980~90년대 데이터 모델링과 객체지향 분석에서도 있었지만, Evans는 그 접근을 이야기할 수 있는 용어 체계(Entity, Value Object, Aggregate, Bounded Context 등)를 정리했다.

DDD는 복잡한 도메인, 즉 지저분한 로직이 많아 정리가 필요한 영역에 특히 적합하다.


핵심 용어

Evans가 DDD Reference에서 정의한 기본 용어다. 이후 모든 패턴이 이 다섯 단어 위에 놓인다.

용어정의
domain지식·영향력·활동의 영역. 사용자가 프로그램을 적용하는 주제 영역
model도메인의 선택된 측면을 기술하고 그 도메인의 문제를 푸는 데 쓸 수 있는 추상화 체계
ubiquitous language도메인 모델을 중심으로 구조화되어, 하나의 bounded context 안에서 팀 전원이 사용하는 언어
context단어나 진술이 등장하여 그 의미를 결정하는 배경. 모델에 대한 진술은 컨텍스트 안에서만 이해된다
bounded context특정 모델이 정의되고 적용되는 경계에 대한 기술. 보통 하위 시스템이나 특정 팀의 작업 범위

전략적 설계와 전술적 설계

DDD의 패턴은 크게 두 축으로 나뉜다. 전략적 설계가 먼저이고 전술적 패턴은 그 안에서만 의미가 있다. Aggregate를 잘 나눠도 Bounded Context가 틀렸으면 전부 다시 해야 하지만, 컨텍스트가 맞으면 Aggregate는 나중에 리팩터링할 수 있다.

구분다루는 질문주요 패턴
전략적(strategic)큰 모델과 큰 팀을 어떻게 나눌 것인가Bounded Context, Ubiquitous Language, Context Map, Core Domain, Generic Subdomain
전술적(tactical)한 컨텍스트 안을 어떻게 짤 것인가Aggregate, Entity, Value Object, Domain Event, Repository, Factory, Service

Evans의 원서는 이 구조를 여섯 부로 나눈다.

I.   Putting the Model to Work      - Bounded Context, Ubiquitous Language, Model-Driven Design
II.  Building Blocks                - Entity, Value Object, Domain Event, Service, Module, Aggregate, Repository, Factory
III. Supple Design                  - Intention-Revealing Interface, Side-Effect-Free Function, Assertion 등
IV.  Context Mapping                - Context Map, Shared Kernel, Customer/Supplier, ACL, Open-host Service 등
V.   Distillation                   - Core Domain, Generic Subdomain, Segregated Core 등
VI.  Large-scale Structure          - Responsibility Layers, Knowledge Level 등

전략적 설계에 해당하는 것이 I·IV·V·VI이고, 전술적 설계가 II·III이다. Fowler는 전략적 설계 부분을 특히 높이 평가하는데, 그 시점까지 “큰 도메인을 어떻게 나눌 것인가"를 설득력 있게 다룬 사례가 없었기 때문이다.


무엇을 해결하는가

큰 시스템에 단일 모델은 성립하지 않는다

DDD의 출발점은 모델이 내부적으로 일관되어야(unified) 효과적이라는 것이다. 그런데 도메인이 커질수록 단일한 통합 모델을 만드는 일은 급격히 어려워진다. 조직의 부서마다 같은 단어를 미묘하게 다른 뜻으로 쓰기 때문이다.

Fowler가 드는 예는 전력회사의 “meter"다. 이 단어는 부서에 따라 전력망과 지점의 연결을 뜻하기도 하고, 전력망과 고객의 연결을 뜻하기도 하며, 고장 나면 교체되는 물리적 계량기 자체를 뜻하기도 한다. 대화에서는 얼버무리고 넘어갈 수 있지만 컴퓨터의 정밀한 세계에서는 그럴 수 없다. “Customer”, “Product” 같은 흔한 단어에서 이 문제가 반복해서 나타난다.

Evans의 결론은 명확하다.

큰 시스템에서 도메인 모델을 완전히 통일하는 것은 실현 가능하지도, 비용 대비 효과적이지도 않다.

그래서 DDD는 큰 시스템을 여러 개의 Bounded Context로 나누고, 각각의 컨텍스트 안에서만 모델이 일관되도록 한다.

규칙이 모델 밖으로 새어나가는 것을 막는다

Evans의 Layered Architecture 패턴이 다루는 문제다. 객체지향 프로그램에서 UI·DB·기타 지원 코드가 비즈니스 객체 안에 직접 작성되고, 반대로 비즈니스 로직이 UI 위젯이나 DB 스크립트에 스며드는 일이 흔하다. 단기적으로는 그게 가장 빨리 동작하는 방법이기 때문이다.

그 결과 도메인 관련 코드가 방대한 다른 코드에 흩어지고, UI를 조금 바꾸면 비즈니스 로직이 바뀌며, 규칙 하나를 고치려면 UI 코드와 DB 코드를 샅샅이 추적해야 한다.

처방은 격리(isolation) 다. 도메인 모델과 비즈니스 로직의 표현을 격리하고, 인프라·UI·비즈니스 로직이 아닌 애플리케이션 로직에 대한 의존을 제거한다. Evans 본인도 Reference에서 “핵심 목표는 격리이며, Hexagonal Architecture 같은 관련 패턴이 그 목적을 더 잘 달성할 수도 있다"고 덧붙인다.


흔한 오해

패키지 구조를 만드는 것이 DDD가 아니다

domain / application / infrastructure 디렉터리를 만드는 것은 DDD의 결과일 수는 있어도 DDD 자체는 아니다. 그 구조를 만들어 놓고 로직이 전부 Service에 있으면 이름만 바뀐 계층형이고, 이것이 Anemic Domain Model 안티패턴이다.

Evans의 Modules 패턴은 이 점을 분명히 한다. 모듈은 기술 아키텍처의 층위나 개발자 업무 분담이 아니라 시스템의 이야기를 들려주고 응집된 개념 집합을 담도록 골라야 하며, 모듈 이름은 보편 언어의 일부가 되어야 한다.

객체지향 전용 기법이 아니다

Evans의 배경이 객체지향 커뮤니티인 것은 사실이지만, Fowler의 지적대로 DDD의 핵심 개념은 개념적인 것이라 어떤 프로그래밍 접근에도 적용된다. 특히 전략적 설계 측면은 패러다임과 무관하다.

모든 프로젝트에 적용할 대상이 아니다

Fowler는 P of EAA에서 도메인 모델이 항상 최선의 도구는 아니라고 정리했다. 도메인 모델은 O/R 매핑 계층 같은 비용을 수반하는데, 그 비용은 복잡한 로직을 객체지향 기법으로 조직할 때만 회수된다. 로직이 단순하면 Transaction Script가 더 낫다.


관련 문서


참고 자료