[2025_10_22]DDD아키텍쳐

2025. 10. 22. 21:33TIL

도메인의 DDD에서의 의미

  • 소프트웨어로 해결하고자 하는 문제의 영역
  • 실세계에서 사건이 발생하는 집합 또는 영역
  • 비즈니스 로직과 규칙을 포함하는 문제 공간
  • 도메인이 무엇인지"보다 "도메인에 포함되는 것이 무엇인가"를 정의하는 것이 더 중요!

쇼핑몰 예시로 이해하기

도메인의 분리

 
쇼핑몰 시스템
├── Order Domain (주문 도메인)
│   └── 손님이 상품을 주문하는 영역
├── Manage Domain (관리 도메인)
│   └── 직원이 상품을 관리하는 영역
└── Payment Domain (결제 도메인)
    └── 결제를 처리하는 영역

도메인 간 상호작용

  • 손님이 상품 주문 → Order Domain
  • 주문 정보 확인 → Manage Domain
  • 결제 처리 → Payment Domain
  • 각 도메인은 독립적이면서도 필요시 상호작용

도메인 vs 객체 - 완벽 비교

예시: "고양이가 사과를 먹는다"

객체 관점 (Object-Oriented)

 
java
// 객체 정의
class Cat {
    String name;
    int age;
    
    void eat(Apple apple) {
        // 먹는 행위
    }
}

class Apple {
    String color;
    int size;
}

// 사용
Cat cat = new Cat();
Apple apple = new Apple();
cat.eat(apple);

특징
- 구체적인 속성과 행위에 집중
- 현실 세계를 그대로 표현
- 명확하게 정의된 구조

도메인 관점 (Domain-Driven)

사용자 관점 A: 애완동물 관리 시스템
├── 도메인 1: 고양이 관리 (Cat Management)
│   ├── 고양이 엔티티
│   ├── 먹이 관리
│   └── 행동 기록
└── 도메인 2: 식품 관리 (Food Management)
    └── 사과 정보

사용자 관점 B: 동물 행동 연구 시스템
└── 도메인 1: 섭식 행동 (Eating Behavior)
    ├── 고양이
    ├── 사과
    └── 먹는 행위
    └── 도메인 이벤트: "고양이가 사과를 먹었다"
```

특징
- 비즈니스 관점에서 바라봄
- 사용자가 누구인지에 따라 달라짐
- 문제 해결에 집중

---

 도메인의 유동성

 도메인은 고정되어 있지 않다!

같은 요소, 다른 도메인

| 관점 | 도메인 구분 |
|------|------------|
| 식당 주인 | "주문 관리", "재고 관리", "직원 관리" |
| 고객 | "메뉴 선택", "주문", "결제" |
| 배달원 | "배달 관리", "경로 최적화" |

사용자에 따라 변하는 도메인

예시: "고양이가 사과를 먹는다"

사용자 A (수의사)
→ 두 개의 도메인으로 분리
   ├── "고양이 건강 관리"
   └── "영양 섭취 관리"

사용자 B (애완동물 앱 개발자)
→ 하나의 도메인으로 통합
   └── "애완동물 행동 기록"

사용자 C (과일 재배 농부)
→ 전혀 다른 관점
   ├── "사과 판매"
   └── 고양이는 관심사 밖



 서브도메인 (Subdomain)

도메인을 더 작은 단위로 나눈 부분

 핵심 서브도메인 (Core Subdomain)
- 비즈니스에서 가장 중요한 부분
- 경쟁 우위를 만드는 영역
- 가장 많은 투자가 필요

예시 (쇼핑몰)
- 추천 알고리즘
- 개인화 서비스
- 차별화된 주문 시스템

  지원 서브도메인 (Supporting Subdomain)
- 핵심 서브도메인을 지원
- 필수적이지만 차별화되지 않음
- 맞춤 개발 필요

예시
- 재고 관리
- 배송 추적
- 고객 문의 관리

  일반 서브도메인 (Generic Subdomain)
- 여러 도메인에서 공통적으로 사용
- 외부 솔루션 사용 가능
- 직접 개발할 필요 없음

예시
- 로그인/인증
- 이메일 발송
- 결제 처리

---

 도메인 모델 (Domain Model)

 정의
도메인 전문가와 개발자가 공유하는 비즈니스 지식을 소프트웨어로 표현한 모델

 구성 요소
Domain Model
├── Entity (엔티티)
│   └── 고유 식별자를 가진 객체
├── Value Object (밸류 오브젝트)
│   └── 식별자 없는 불변 객체
├── Aggregate (애그리게이트)
│   └── 관련 객체들의 집합
├── Domain Service (도메인 서비스)
│   └── 특정 엔티티에 속하지 않는 로직
└── Domain Event (도메인 이벤트)
    └── 도메인 내에서 발생하는 중요한 사건
```

 쇼핑몰 도메인 모델 예시
```
주문 도메인 모델
├── Order (Entity)
│   ├── orderId (식별자)
│   ├── orderDate
│   └── totalAmount
├── OrderItem (Entity)
│   ├── itemId
│   ├── quantity
│   └── price
├── Address (Value Object)
│   ├── street
│   ├── city
│   └── zipCode
├── Money (Value Object)
│   ├── amount
│   └── currency
└── OrderPlaced (Domain Event)
    └── "주문이 완료되었다"
```

---

  도메인 이벤트 (Domain Event)

 정의
도메인 내에서 발생하는 비즈니스적으로 의미 있는 사건

 특징
- 과거형으로 표현 ("~했다", "~되었다")
- 다른 도메인에 알려야 할 중요한 변경사항
- 비동기 처리에 활용

 예시

주문 도메인
├── OrderPlaced (주문됨)
├── OrderCancelled (주문 취소됨)
└── OrderShipped (배송됨)

결제 도메인
├── PaymentCompleted (결제 완료됨)
└── PaymentFailed (결제 실패함)

재고 도메인
└── StockReserved (재고 예약됨)


 도메인 이벤트 흐름

1. 고객이 주문 버튼 클릭
2. Order Domain → OrderPlaced 이벤트 발생
3. Payment Domain이 이벤트 수신 → 결제 처리
4. PaymentCompleted 이벤트 발생
5. Inventory Domain이 이벤트 수신 → 재고 차감
6. StockReserved 이벤트 발생

 도메인 설계 원칙

1. 분리 (Separation)

각 도메인은 철저히 분리되어야 함

잘못된 예

class OrderService {
    void createOrder() {
        // 주문 생성
        // 결제 처리 ❌
        // 재고 관리 ❌
        // 알림 발송 ❌
    }
}

 

올바른 예

class OrderService {
    void createOrder() {
        // 주문 생성만 담당 ✅
        publishEvent(new OrderPlaced());
    }
}

class PaymentService {
    @EventListener
    void handleOrderPlaced(OrderPlaced event) {
        // 결제 처리 ✅
    }
}

2. 높은 응집력 (High Cohesion)

관련된 것들은 함께 배치

3. 낮은 결합도 (Loose Coupling)

도메인 간 의존성 최소화

 

도메인을 정의할 때 고려해야 할 질문

  • 누가 이 시스템을 사용하는가?
  • 무엇을 해결하려고 하는가?
  • 어떤 비즈니스 규칙이 있는가?
  • 어떤 이벤트가 발생하는가?
  • 다른 도메인과 어떻게 상호작용하는가?
  • 핵심 비즈니스는 무엇인가?
  • 변경이 자주 일어나는 부분은?
  • 확장이 필요한 부분은?

 핵심 요약

  1. 도메인은 문제 영역 - 기술이 아닌 비즈니스 관점
  2. 유동적이다 - 사용자와 관점에 따라 변함
  3. 객체보다 넓은 개념 - 비즈니스 로직과 규칙 포함
  4. 분리와 상호작용 - 독립적이면서도 협력
  5. 이벤트 중심 - 도메인 간 통신의 핵심