LESSON 40分

ストーリー

佐藤CTO
DDDの概念は分かった。次は実際のシステムで境界を引いてみよう
佐藤CTO
Bounded Context の特定は、ドメインエキスパートとの対話から始まる。コードだけ見ていては正しい境界は見えないぞ

Bounded Context とは

Bounded Context は、特定のドメインモデルが適用される明示的な境界です。

graph TD
    subgraph EC["EC ドメイン"]
        CAT["カタログ Context<br/>・商品<br/>・カテゴリ<br/>・レビュー"]
        ORD["注文 Context<br/>・注文<br/>・注文明細<br/>・決済"]
        SHP["配送 Context<br/>・出荷<br/>・配送先<br/>・追跡"]
        CUS["顧客管理 Context"]
        INV["在庫 Context"]
        MKT["マーケ Context"]
    end

    classDef ctx fill:#e8f4fd,stroke:#2196f3,color:#333
    class CAT,ORD,SHP,CUS,INV,MKT ctx

境界の見つけ方

シグナル説明
言語の違い同じ用語が異なる意味を持つ「商品」の定義がチームで異なる
ビジネスプロセスの境界業務フローの切れ目注文確定と配送手配の間
データの所有権誰がそのデータの正本を持つか在庫数は在庫チームが所有
変更の速度異なるペースで変更されるカタログは毎日、決済は月1回
チーム構造既存のチーム境界逆コンウェイ戦略に活用

Context Mapping パターン

7つの主要パターン

graph LR
    subgraph 協調的
        P["Partnership"]
        CS["Customer/<br/>Supplier"]
    end
    subgraph 中間
        SK["Shared Kernel"]
        CF["Conformist"]
        OHS["Open Host<br/>Service"]
        PL["Published<br/>Language"]
    end
    subgraph 防御的
        ACL["ACL"]
        SW["Separate Ways"]
    end

    P --- SK --- ACL
    CS --- CF --- SW
    SK --- OHS
    OHS --- PL

    classDef coop fill:#d4edda,stroke:#28a745,color:#333
    classDef mid fill:#fff3cd,stroke:#f0ad4e,color:#333
    classDef def fill:#f8d7da,stroke:#dc3545,color:#333
    class P,CS coop
    class SK,CF,OHS,PL mid
    class ACL,SW def
パターン関係性使用場面
Partnership対等・協調2チームが密に連携して開発
Shared Kernel共有モデル小さなモデルを複数コンテキストで共有
Customer/Supplier上流/下流下流が上流に要求を出せる
Conformist従属下流が上流のモデルに合わせる
Anti-Corruption Layer防御的翻訳外部モデルから自ドメインを保護
Open Host Service公開API汎用的なプロトコルを提供
Published Language共通言語標準化されたデータフォーマット

ACL(Anti-Corruption Layer)の実装例

// 外部の決済サービスのモデル
interface StripePaymentIntent {
  id: string;
  amount: number;        // セント単位
  currency: string;
  status: 'succeeded' | 'pending' | 'failed';
  metadata: Record<string, string>;
}

// 自ドメインのモデル
class Payment {
  constructor(
    readonly id: PaymentId,
    readonly amount: Money,
    readonly status: PaymentStatus,
    readonly orderId: OrderId
  ) {}
}

// ACL: 外部モデル → 自ドメインモデルへの変換
class StripePaymentAdapter {
  toDomain(intent: StripePaymentIntent): Payment {
    return new Payment(
      new PaymentId(intent.id),
      new Money(intent.amount / 100, intent.currency as Currency),
      this.mapStatus(intent.status),
      new OrderId(intent.metadata.orderId)
    );
  }

  private mapStatus(status: string): PaymentStatus {
    const mapping: Record<string, PaymentStatus> = {
      succeeded: PaymentStatus.COMPLETED,
      pending: PaymentStatus.PROCESSING,
      failed: PaymentStatus.FAILED,
    };
    return mapping[status] ?? PaymentStatus.UNKNOWN;
  }
}

ECプラットフォームのコンテキストマップ

graph TD
    CAT["カタログ Context"] <-->|Partnership| INV["在庫 Context"]
    CAT -->|OHS/PL| ORD["注文 Context"]
    INV -->|Customer/Supplier| ORD
    ORD <-->|Partnership| SHP["配送 Context"]
    ORD -->|ACL| PAY["決済 Context<br/>← 外部サービス(Stripe)との<br/>間にACLを配置"]

    classDef ctx fill:#e8f4fd,stroke:#2196f3,color:#333
    classDef ext fill:#fff3cd,stroke:#f0ad4e,color:#333
    class CAT,INV,ORD,SHP ctx
    class PAY ext

Event Storming によるコンテキスト発見

Event Storming は、ドメインエキスパートと開発者が共同でドメインイベントを洗い出し、Bounded Context を発見する手法です。

進め方

  1. ドメインイベント(オレンジ付箋)を時系列に並べる
  2. コマンド(青付箋)を特定する
  3. 集約(黄色付箋)をグルーピングする
  4. 境界線を引いて Context を分ける
graph LR
    subgraph Catalog["カタログ"]
        E1["商品登録された"]
    end
    subgraph Stock["在庫"]
        E2["在庫設定された"]
    end
    E1 --> E2 --> E3["商品公開された"]

    subgraph Cart["カート"]
        E4["カートに追加された"]
    end
    subgraph Order["注文"]
        E5["注文確定された"]
    end
    subgraph Payment["決済"]
        E6["決済処理された"]
    end
    subgraph Shipping["配送"]
        E7["出荷指示された"]
    end
    E4 --> E5 --> E6 --> E7

    style Catalog fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style Stock fill:#d1fae5,stroke:#059669,color:#065f46
    style Cart fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style Order fill:#fef3c7,stroke:#d97706,color:#92400e
    style Payment fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style Shipping fill:#d1fae5,stroke:#059669,color:#065f46
    style E1 fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E2 fill:#d1fae5,stroke:#059669,color:#065f46
    style E3 fill:#f3f4f6,stroke:#9ca3af,color:#374151
    style E4 fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style E5 fill:#fef3c7,stroke:#d97706,color:#92400e
    style E6 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style E7 fill:#d1fae5,stroke:#059669,color:#065f46

まとめ

ポイント内容
Bounded Contextドメインモデルの適用境界
Context MappingContext 間の関係性を定義
ACL外部モデルから自ドメインを保護
Event StormingContext 発見のワークショップ手法

チェックリスト

  • Bounded Context の境界を特定する方法を理解した
  • 7つの Context Mapping パターンを説明できる
  • ACL の役割と実装方法を理解した
  • Event Storming の進め方を説明できる

次のステップへ

次はサービス分割戦略と段階的移行アプローチを学びます。


推定読了時間: 40分