Phase 4레슨 20
Domain-Driven Design (DDD)
Bounded Context, Aggregate, Value Object, Domain Event, Ubiquitous Language
💡ELI5·
User는 누구인가 — Bounded Context
"User" 라는 단어
/ | \
주문 컨텍스트 배송 컨텍스트 마케팅 컨텍스트
구매자 수령인 타겟 고객
(id, 결제수단) (주소, 연락처) (세그먼트, 행동)
각 컨텍스트는 User의 다른 측면만 본다.
하나의 User 테이블이 아니라, 컨텍스트별 모델.💡 비유 — 한 사람이 집에서는 '아빠', 회사에서는 '과장님', 동호회에서는 '회장'. 맥락에 따라 다른 역할과 속성. DDD는 이 맥락(Bounded Context)을 명시적으로 구분한다.
🔬Deep Dive·
Aggregate와 Root
Order (Aggregate Root) ├── id: OrderId ├── customer: CustomerId (참조만, Customer Aggregate 직접 접근 X) ├── status: OrderStatus ├── orderLines: OrderLine[] ← Order 안에서만 유효 │ ├── productId │ ├── quantity │ └── price └── shippingAddress: Address ← Value Object 규칙: - 외부에서 OrderLine에 직접 접근 불가 (Root 경유) - 한 트랜잭션 = 한 Aggregate 변경 - 다른 Aggregate는 ID 참조만
| 규칙 | 이유 |
|---|---|
| Root 경유 접근 | 일관성(불변식) 보장 |
| ID 참조만 (객체 직접 참조 X) | Aggregate 간 결합 최소화 |
| 한 트랜잭션 = 한 Aggregate | 트랜잭션 범위 작게 유지 |
| Cross-Aggregate는 Domain Event | 느슨한 결합, 최종 일관성 |
🔬Deep Dive·
Entity vs Value Object
| 구분 | Entity | Value Object |
|---|---|---|
| 식별 | ID로 식별 | 속성 값으로 식별 |
| 가변성 | 가변 (속성 변경 가능) | 불변 (새 객체 생성) |
| 동등성 | ID 비교 (equals by id) | 속성 비교 (equals by value) |
| 예시 | User, Order, Product | Money, Address, DateRange |
| 생명주기 | 독립적 (추적 가능) | Entity에 속함 (독립 추적 X) |
// Value Object (불변, 속성 비교)
class Money {
constructor(readonly amount: number, readonly currency: string) {}
add(other: Money): Money {
if (this.currency !== other.currency) throw new Error('통화 불일치');
return new Money(this.amount + other.amount, this.currency); // 새 객체
}
equals(other: Money): boolean {
return this.amount === other.amount && this.currency === other.currency;
}
}
// Entity (ID 식별, 가변)
class Order {
constructor(readonly id: OrderId, private status: OrderStatus) {}
cancel() { this.status = OrderStatus.CANCELLED; } // 상태 변경
}🔬Deep Dive·
Domain Event — 컨텍스트 간 통신
Order Context: Order.cancel() → OrderCancelledEvent 발행 Shipping Context (구독): OrderCancelledEvent 수신 → 배송 취소 Marketing Context (구독): OrderCancelledEvent 수신 → 이탈 고객 캠페인 트리거 → Order는 Shipping/Marketing을 모름 (느슨한 결합)
⚖️Trade-off·
DDD의 장단점
| 장점 | 단점 |
|---|---|
| 비즈니스와 코드가 일치 (Ubiquitous Language) | 학습 곡선 가파름 |
| 복잡한 도메인을 명확히 모델링 | 단순 CRUD에 과도함 |
| Bounded Context가 모듈/서비스 경계 | 도메인 전문가와의 긴밀 협업 필요 |
| 테스트 용이 (도메인이 외부에 독립) | 설계 시간 많이 소요 |
DDD는 복잡한 비즈니스 도메인에 투자할 가치가 있다. 단순한 CRUD 블로그에는 Layered Architecture로 충분하다.
❓ 체크포인트 질문
- 1.Bounded Context가 무엇이고 왜 중요한가?
- 2.Aggregate와 Aggregate Root의 역할은?
- 3.Value Object와 Entity의 차이는?
- 4.Ubiquitous Language가 왜 중요한가?
- 5.Domain Event가 시스템 분리에 어떻게 기여하는가?