반응형
DDD는 복잡한 비즈니스 로직을 가진 소프트웨어를 개발할 때,
비즈니스 도메인 전문가의 지식을 중심에 놓고 설계하는 접근 방식입니다.
1. DDD란 무엇인가?
📌 정의와 핵심 목적
도메인 주도 설계(Domain-Driven Design, DDD) 는 소프트웨어의 복잡성을 관리하고 해결하기 위해, 소프트웨어 코드를 비즈니스 도메인(업무 영역)과 밀접하게 일치시키는 것을 목표로 하는 개발 방법론입니다.
- 도메인 (Domain): 소프트웨어가 해결하고자 하는 특정 업무 영역 (예: 금융, 의료, 쇼핑몰의 재고 관리 등).
- 핵심 목적: 복잡한 도메인 지식을 코드로 정확하게 모델링하여, 비즈니스 요구사항 변경에 유연하게 대처하고 코드의 이해도를 높이는 것입니다.
🗣️ 유비쿼터스 언어 (Ubiquitous Language)
DDD의 가장 중요한 개념 중 하나입니다.
- 정의: 개발팀, 마케팅팀, 그리고 도메인 전문가가 모두 동일한 의미로 사용하는 공통된 언어입니다.
- 적용: 이 언어는 대화, 문서, 그리고 코드 자체에 그대로 반영되어야 합니다. 예를 들어, 도메인 전문가가 "주문(Order)"이라고 부르면, 코드에서도 Order 클래스나 order 변수명을 사용해야 합니다.
🗺️ 바운디드 컨텍스트 (Bounded Context)
- 정의: 유비쿼터스 언어가 의미를 갖는 명확한 경계입니다.
- 필요성: 같은 단어라도 시스템의 영역에 따라 의미가 다를 수 있습니다.
- 예시: '고객(Customer)'이라는 단어는 '판매(Sales)' 컨텍스트에서는 "잠재 구매자"를 의미하지만, '배송(Shipping)' 컨텍스트에서는 "배송 주소와 연락처를 가진 사람"을 의미합니다.
- DDD는 복잡한 시스템을 이처럼 독립적인 바운디드 컨텍스트로 나누어 관리합니다.
2. DDD의 핵심 구성 요소
A. 엔티티 (Entity)
- 특징: 고유한 식별자(ID)를 가지며, 시간의 흐름에 따라 상태(속성)가 변해도 동일성(Identity)이 유지되는 객체입니다.
- 역할: 비즈니스 로직과 행위(Behavior)를 담고 있습니다.
- 예시: Order (주문 번호가 ID), Customer (고객 ID).
B. 값 객체 (Value Object)
- 특징: 고유한 식별자가 없으며, 자신의 속성(값)으로 동일성을 판단합니다. 불변성(Immutable)을 가져야 합니다.
- 역할: 특정 값이나 개념을 표현하며, 여러 속성을 묶어 의미를 명확하게 합니다.
- 예시: Address (우편번호, 시/도, 도로명 주소 값이 모두 같으면 동일한 Address), Money (금액, 통화).
C. 애그리게이트 (Aggregate)
- 특징: 엔티티와 값 객체들의 묶음이자 트랜잭션의 경계입니다.
- 역할: 애그리게이트 내부 객체들 간의 일관성을 보장하며, 외부에서는 루트 엔티티(Aggregate Root)를 통해서만 접근해야 합니다.
- 예시: Order 애그리게이트는 Order 엔티티(루트), 여러 개의 LineItem 값 객체, ShippingAddress 값 객체 등으로 구성될 수 있습니다.
D. 도메인 서비스 (Domain Service)
- 특징: 특정 엔티티나 값 객체에 속하기 어려운, 여러 애그리게이트에 걸쳐있는 비즈니스 로직이나 도메인 행위를 처리합니다.
- 예시: 두 계좌(Account 애그리게이트 1, 2) 간의 '금액 이체(Transfer)' 로직.
3. DDD 구현 예시 및 Python 코드
쇼핑몰에서 '주문(Order)' 도메인을 DDD 방식으로 모델링하는 코드를 살펴보겠습니다.
📋 도메인 모델 설계
- 애그리게이트 루트: Order
- 엔티티: Order, Product (외부 시스템 ID 필요)
- 값 객체: Money, LineItem (수량과 제품 정보를 묶음)
🐍 Python 코드 구현 (예시)
1. 값 객체 (Value Object): Money
from dataclasses import dataclass
@dataclass(frozen=True) # frozen=True로 불변성 확보
class Money:
"""값 객체: 금액과 통화 단위를 표현"""
amount: float
currency: str
def add(self, other: 'Money') -> 'Money':
if self.currency != other.currency:
raise ValueError("통화 단위가 다릅니다.")
return Money(self.amount + other.amount, self.currency)
# 사용 예: price = Money(15.99, "USD")
2. 엔티티 (Entity): Product (일부 속성 생략)
class Product:
"""엔티티: 고유한 ID(SKU)를 가지는 상품"""
def __init__(self, sku: str, name: str, price: Money):
if not sku:
raise ValueError("SKU는 필수입니다.")
self.sku = sku # 고유 식별자
self.name = name
self.price = price
3. 애그리게이트 루트 (Aggregate Root): Order
from typing import List
@dataclass(frozen=True)
class LineItem:
"""값 객체: 주문 항목 (상품 정보와 수량을 묶음)"""
product_sku: str
quantity: int
price: Money
class Order:
"""애그리게이트 루트: 주문 전체의 트랜잭션 경계"""
def __init__(self, order_id: str, customer_id: str, items: List[LineItem] = None):
if not order_id:
raise ValueError("주문 ID는 필수입니다.")
self.order_id = order_id # 엔티티의 고유 식별자
self.customer_id = customer_id
self._items = items if items is not None else []
self._status = "PENDING"
# --- 도메인 행위 (Behavior) ---
def add_item(self, item: LineItem):
"""주문 항목 추가 행위 (애그리게이트 내부 일관성 유지)"""
if self._status != "PENDING":
raise PermissionError("이미 처리된 주문에는 항목을 추가할 수 없습니다.")
self._items.append(item)
def calculate_total(self) -> Money:
"""총 주문 금액 계산"""
total = Money(0.0, "USD") # 초기 금액
for item in self._items:
# item.price는 LineItem의 값 객체 Money입니다.
item_total = Money(item.price.amount * item.quantity, item.price.currency)
total = total.add(item_total)
return total
def confirm_order(self):
"""주문 확정 행위"""
if not self._items:
raise ValueError("주문 항목이 없습니다.")
if self._status == "PENDING":
self._status = "CONFIRMED"
else:
raise ValueError(f"현재 상태({self._status})에서는 주문을 확정할 수 없습니다.")
# Getter: 외부에서는 내부 리스트를 직접 수정할 수 없도록 사본을 반환
@property
def items(self) -> List[LineItem]:
return list(self._items)
🎯 DDD의 효과
이 코드는 단순한 데이터 구조(DTO)가 아닌, 도메인의 행위(add_item, confirm_order, calculate_total)를 클래스 내부에 캡슐화하고 있습니다.
- 일관성 보장: 주문 확정(confirm_order) 전에 항목이 있는지(if not self._items) 확인하거나, 이미 확정된 주문에 항목 추가를 막는 등의 비즈니스 규칙이 Order 클래스 안에 명확하게 정의되어, 코드가 비즈니스 요구사항을 정확히 반영합니다.
참고 자료
https://blog.kakaocloud.com/193
<지식 사전> 도메인 주도 설계(Domain Driven Design)란? - 비즈니스 언어로 소프트웨어 만들기
🧑💻 요약 도메인 주도 설계(DDD)가 왜 필요한지, 기존 개발 방식의 문제(소통 단절)를 어떻게 해결하는지 설명합니다. 공통 언어·바운디드 컨텍스트·엔티티/값 객체·애그리게이트 등 DDD 핵
blog.kakaocloud.com
https://tech.kakaopay.com/post/backend-domain-driven-design/
카카오페이 여신코어 DDD(Domain Driven Design, 도메인 주도 설계)로 구축하기 | 카카오페이 기술 블로
카카오페이의 여신업무 내재화 프로젝트를 DDD를 적용하여 구축한 내용을 공유하고자 합니다.
tech.kakaopay.com
반응형
'IT > Architecture' 카테고리의 다른 글
| TDD 도입 및 안착 가이드 (1) | 2026.01.17 |
|---|---|
| 🧪테스트주도개발(TDD) 하기 | 핵심 용어 (0) | 2025.12.26 |
| 🧪테스트주도개발(TDD) 하기 | QA 테스트 검증 프로세스 "제품 개발 라이프사이클을 지배하는 6가지 주요 테스트 단계 - DVT CVT부터 UAT까지" (0) | 2025.12.01 |
| 디자인 패턴(Design Pattern)이란? (0) | 2025.10.29 |
| DIP 의존성 역전 원칙 | SOLID 설계 원칙 (0) | 2025.10.26 |