3강 45분

도메인 주도 설계로 서비스 분리하기

DDD(Domain-Driven Design)의 핵심 개념인 Bounded Context를 이용해 마이크로서비스를 효과적으로 분리하는 방법을 배웁니다.

도메인 주도 설계로 서비스 분리하기

학습 목표

  • DDD의 핵심 개념 이해
  • Bounded Context를 이용한 서비스 경계 설정
  • Aggregate를 통한 데이터 일관성 관리
  • 실전 이커머스 예제로 서비스 분리 실습

도메인 주도 설계(DDD)란?

Eric Evans가 제안한 소프트웨어 설계 방법론으로, 비즈니스 도메인을 중심으로 시스템을 설계합니다.

핵심 개념

  1. Ubiquitous Language: 개발자와 도메인 전문가가 사용하는 공통 언어
  2. Bounded Context: 특정 모델이 적용되는 경계
  3. Aggregate: 데이터 일관성을 유지하는 단위
  4. Domain Event: 도메인에서 발생하는 중요한 이벤트

Bounded Context로 서비스 분리

예제: 이커머스 시스템

잘못된 분리:

❌ User Service
❌ Product Service
❌ Order Service

문제점: 기술 중심 분리로 비즈니스 로직이 여러 서비스에 분산

올바른 분리 (Bounded Context 기반):

✅ Catalog Context (카탈로그)
   - 상품 검색
   - 상품 정보 관리

✅ Shopping Context (쇼핑)
   - 장바구니
   - 주문 생성

✅ Fulfillment Context (주문 처리)
   - 결제 처리
   - 배송 관리

✅ Customer Context (고객)
   - 회원 정보
   - 고객 등급

Bounded Context 식별 방법

1. 이벤트 스토밍

팀 전체가 모여 비즈니스 이벤트를 포스트잇에 적습니다:

[고객이 상품을 검색함] → [상품을 장바구니에 추가함]
→ [주문을 생성함] → [결제가 완료됨] → [상품이 배송됨]

2. 이벤트 그룹핑

관련된 이벤트들을 묶어 Bounded Context를 식별:

Catalog Context:
- 상품 검색됨
- 상품 정보 조회됨

Shopping Context:
- 장바구니에 추가됨
- 주문 생성됨

Fulfillment Context:
- 결제 완료됨
- 상품 배송됨

3. 컨텍스트 맵 그리기

graph TD
    Customer["Customer Context<br/>회원 정보, 고객 등급"]
    Catalog["Catalog Context<br/>상품 검색, 상품 정보"]
    Shopping["Shopping Context<br/>장바구니, 주문 생성"]
    Fulfillment["Fulfillment Context<br/>결제, 배송"]

    Customer --> Catalog
    Customer --> Shopping
    Shopping --> Fulfillment
    Catalog -.상품 정보 조회.-> Shopping

    style Customer fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    style Catalog fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    style Shopping fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
    style Fulfillment fill:#fff3e0,stroke:#e65100,stroke-width:2px

Aggregate 설계

Aggregate란?

관련된 객체들의 묶음으로, 일관성 경계를 정의합니다.

예제: 주문 Aggregate

// 주문 Aggregate Root
class Order {
  private id: OrderId;
  private customerId: CustomerId;
  private items: OrderItem[];
  private status: OrderStatus;
  private totalAmount: Money;

  addItem(product: Product, quantity: number) {
    // 비즈니스 규칙: 재고 확인
    if (product.stock < quantity) {
      throw new InsufficientStockError();
    }

    const item = new OrderItem(product, quantity);
    this.items.push(item);
    this.recalculateTotal();
  }

  complete() {
    // 비즈니스 규칙: 최소 금액 확인
    if (this.totalAmount.isLessThan(MIN_ORDER_AMOUNT)) {
      throw new MinimumAmountError();
    }

    this.status = OrderStatus.COMPLETED;

    // Domain Event 발행
    this.addDomainEvent(new OrderCompleted(this.id));
  }
}

Aggregate 설계 원칙

  1. 작게 유지: 진짜 일관성이 필요한 것만 포함
  2. ID로 참조: 다른 Aggregate는 ID로만 참조
  3. 트랜잭션 경계: 하나의 Aggregate = 하나의 트랜잭션

Context 간 통신

1. REST API (동기)

// Shopping Context → Catalog Context
const product = await catalogService.getProduct(productId);

2. 메시지/이벤트 (비동기)

// Shopping Context가 이벤트 발행
eventBus.publish('order.created', {
  orderId: '123',
  items: [...],
});

// Fulfillment Context가 구독
eventBus.subscribe('order.created', async (event) => {
  await processPayment(event.orderId);
});

실습: 이커머스 서비스 분리

요구사항

온라인 서점 시스템을 마이크로서비스로 분리하세요:

기능:

  • 도서 검색 및 조회
  • 장바구니 관리
  • 주문 및 결제
  • 배송 추적
  • 회원 관리

해답 예시

1. Catalog Service
   - 도서 검색
   - 도서 정보 관리
   - 재고 조회

2. Shopping Service
   - 장바구니 CRUD
   - 주문 생성
   - 주문 내역 조회

3. Payment Service
   - 결제 처리
   - 결제 내역

4. Delivery Service
   - 배송 상태 관리
   - 배송 추적

5. Customer Service
   - 회원 가입/로그인
   - 프로필 관리

다음 강의

다음 강의에서는 API Gateway와 서비스 간 통신 패턴을 배웁니다.

핵심 정리

  • DDD는 비즈니스 도메인 중심 설계 방법론
  • Bounded Context로 서비스 경계를 명확히 설정
  • Aggregate는 데이터 일관성의 단위
  • 이벤트 스토밍으로 도메인 이해도 향상
  • 서비스는 ID로 참조하고 이벤트로 통신