| [Glossary] DDD 완벽 정리 | Domain-Driven Design을 쉽게 이해하는 법 |
한 줄 요약: DDD(Domain-Driven Design)란, 소프트웨어 설계를 비즈니스 도메인 전문가와 개발자가 공유하는 모델 중심으로 구성하고, 복잡한 비즈니스 로직을 도메인 계층에 명확히 표현하는 소프트웨어 설계 방법론이다.
1. DDD란 무엇인가?
병원 소프트웨어를 만든다고 상상해 보세요. 개발자는 “Patient 객체”라고 부르고, 의사는 “환자 차트”라고 부르고, 행정직은 “내원 기록”이라고 부릅니다. 같은 것을 다르게 부르면 소통이 어렵고 코드가 비즈니스 현실과 멀어집니다.
Eric Evans가 2003년 저서 “Domain-Driven Design: Tackling Complexity in the Heart of Software”에서 제시한 DDD는 이 문제를 해결합니다. 비즈니스 전문가와 개발자가 같은 언어(유비쿼터스 언어)를 사용하고, 이 언어가 코드에 직접 반영됩니다.
2. 핵심 개념 이해하기
DDD 핵심 패턴
| 패턴 | 설명 | 예시 |
|---|---|---|
| 유비쿼터스 언어 | 팀 전체가 공유하는 통일된 용어 | “주문”은 Order 클래스로 직접 표현 |
| 바운디드 컨텍스트 | 도메인 모델이 적용되는 명확한 경계 | 주문 컨텍스트 vs 배송 컨텍스트 |
| 애그리게이트 | 함께 변경되는 객체 묶음 | 주문(Order) + 주문항목(OrderItem) |
| 엔티티 | 고유 식별자를 가진 객체 | Order#1234 |
| 값 객체 | 식별자 없는 불변 값 | 금액(Amount), 주소(Address) |
| 도메인 이벤트 | 도메인에서 발생한 중요 사건 | OrderPlaced, PaymentCompleted |
계층 아키텍처
┌──────────────────────────────────┐
│ Presentation Layer │ ← REST API, GraphQL
├──────────────────────────────────┤
│ Application Layer │ ← Use Cases, Commands
├──────────────────────────────────┤
│ Domain Layer │ ← 비즈니스 규칙, 엔티티 ← 핵심!
├──────────────────────────────────┤
│ Infrastructure Layer │ ← DB, 외부 API
└──────────────────────────────────┘
3. 실무 적용 예시
전자상거래 주문 도메인을 DDD로 구현한 예시입니다.
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import List
import uuid
# 값 객체 (불변)
@dataclass(frozen=True)
class Money:
amount: int
currency: str = "KRW"
def add(self, other: "Money") -> "Money":
assert self.currency == other.currency
return Money(self.amount + other.amount, self.currency)
# 엔티티
@dataclass
class OrderItem:
id: str = field(default_factory=lambda: str(uuid.uuid4()))
product_id: str = ""
product_name: str = ""
price: Money = field(default_factory=lambda: Money(0))
quantity: int = 1
def subtotal(self) -> Money:
return Money(self.price.amount * self.quantity)
# 애그리게이트 루트
class OrderStatus(Enum):
PENDING = "pending"
CONFIRMED = "confirmed"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
class Order:
def __init__(self, customer_id: str):
self.id = str(uuid.uuid4())
self.customer_id = customer_id
self.items: List[OrderItem] = []
self.status = OrderStatus.PENDING
self.created_at = datetime.now()
self._events = [] # 도메인 이벤트
def add_item(self, item: OrderItem):
if self.status != OrderStatus.PENDING:
raise ValueError("확정된 주문에는 상품을 추가할 수 없습니다")
self.items.append(item)
def confirm(self):
if not self.items:
raise ValueError("주문 항목이 없습니다")
self.status = OrderStatus.CONFIRMED
# 도메인 이벤트 발행
self._events.append({
"type": "OrderConfirmed",
"order_id": self.id,
"at": datetime.now().isoformat()
})
def cancel(self, reason: str):
if self.status == OrderStatus.DELIVERED:
raise ValueError("배달 완료된 주문은 취소 불가합니다")
self.status = OrderStatus.CANCELLED
self._events.append({
"type": "OrderCancelled",
"order_id": self.id,
"reason": reason
})
def total(self) -> Money:
result = Money(0)
for item in self.items:
result = result.add(item.subtotal())
return result
def pop_events(self):
events = self._events.copy()
self._events.clear()
return events
# 사용 예시
order = Order(customer_id="customer-001")
order.add_item(OrderItem(
product_id="prod-1",
product_name="파이썬 교재",
price=Money(35000),
quantity=2
))
order.confirm()
print(f"주문 총액: {order.total().amount}원")
print(f"도메인 이벤트: {order.pop_events()}")
4. DDD vs 유사 개념 비교
| 구분 | DDD | 절차적 설계 | 데이터 중심 설계 |
|---|---|---|---|
| 중심 | 비즈니스 도메인 | 프로세스 흐름 | 데이터 구조 |
| 언어 | 유비쿼터스 언어 | 기술 용어 | DB 스키마 |
| 복잡도 처리 | ✅ 도메인 모델로 표현 | 어려움 | 어려움 |
| 팀 소통 | ✅ 도메인 전문가 참여 | 개발자 중심 | 개발자 중심 |
| 적합한 상황 | 복잡한 비즈니스 로직 | 단순 CRUD | 데이터 집약적 |
5. 마치며
DDD는 소프트웨어가 비즈니스의 복잡성을 충실히 반영하도록 하는 설계 철학입니다. AI 에이전트 시스템에서도 DDD 원칙을 적용하면 도메인 전문 에이전트(바운디드 컨텍스트)를 명확히 정의하고 에이전트 간 통신(컨텍스트 맵)을 체계화할 수 있습니다.
참고 자료
- Eric Evans: Domain-Driven Design — DDD 창시자의 공식 사이트
- DDD Reference — DDD 핵심 패턴 빠른 참조
함께 읽으면 좋은 용어
이 개념과 함께 알아두면 이해가 깊어지는 관련 용어들입니다.
댓글 남기기