ユビキタス言語 — DDDの最重要概念
DDDで最も重要な概念を1つだけ挙げるなら、それはユビキタス言語(Ubiquitous Language)です。 ユビキタス言語とは、ドメインエキスパート(業務の専門家)と開発者が共有する厳密な共通言語のことです。
「ユビキタス(遍在する)」という名前が示すとおり、この言語はコード内のクラス名・メソッド名、ドキュメント、日常の会話、仕様書など、 あらゆる場所で一貫して使用されます。開発者だけが使う技術用語でもなく、ビジネス側だけが使う業務用語でもない、 両者が合意した共通の語彙です。
ユビキタス言語の作り方
ユビキタス言語は一度作って終わりではなく、ドメインの理解が深まるにつれて継続的に進化させるものです。 以下のステップで構築・運用します。
- ドメインエキスパートとの対話: 業務で実際に使われている用語を収集する
- 用語の定義を文書化: 曖昧さを排除し、チーム全体で共有する
- コードに反映: クラス名・メソッド名・変数名をユビキタス言語に合わせる
- 言語の不一致を発見したら修正: ビジネス側の用語が変われば、コードもリファクタリングする
- コンテキストごとに定義を分ける: 同じ言葉でも文脈により異なる意味を持つ場合がある
重要なのは、ユビキタス言語の変化はコードのリファクタリングを引き起こすという点です。 新しい用語が生まれたり、既存の用語の意味が変わったりしたら、それに合わせてコードも変更します。 これは面倒に思えますが、モデルとコードの一致を保つことで、長期的な保守性が大幅に向上します。
境界づけられたコンテキスト — モデルの適用範囲を明確にする
境界づけられたコンテキスト(Bounded Context)は、DDDの戦略的設計におけるもう1つの中核概念です。 大規模システムにおいてドメインモデルの完全な統一は実現不可能であるという認識が出発点です。
たとえば「注文(Order)」という概念を考えてみましょう。 ECサイトでは、「販売」の文脈では注文は商品の一覧と割引情報を含みますが、 「配送」の文脈では注文は配送先住所と重量のみが重要です。 「請求」の文脈では注文は金額と支払い状態が中心です。
graph TB
subgraph sales[販売コンテキスト]
O1[注文\n- 商品リスト\n- 割引\n- 顧客情報]
end
subgraph shipping[配送コンテキスト]
O2[配送指示\n- 配送先住所\n- 重量\n- 配送方法]
end
subgraph billing[請求コンテキスト]
O3[請求\n- 金額\n- 支払い状態\n- 請求先]
end
O1 -->|注文確定イベント| O2
O1 -->|注文確定イベント| O3
style sales fill:#8b5cf6,stroke:#6d28d9,color:#fff
style shipping fill:#3b82f6,stroke:#1d4ed8,color:#fff
style billing fill:#f97316,stroke:#ea580c,color:#fffこれらすべてを1つの巨大な「Order」クラスに詰め込むと、変更のたびに他の文脈に影響が波及し、保守が困難になります。 Bounded Contextは、それぞれの文脈で独立したモデルを定義し、各コンテキスト内でモデルの一貫性を保つための仕組みです。
Bounded Contextの見つけ方
Bounded Contextの境界は、以下の手がかりから発見できます。
- 言語の違い: 同じ用語が異なる意味で使われる箇所が境界の候補
- チームの責任範囲: 異なるチームが担当する領域は自然な境界になる
- イベントストーミング: ドメインイベントのクラスタを分析し、自然な境界を発見する(第7章で詳述)
- ビジネス能力: ビジネスが提供する能力(販売、配送、請求等)ごとに分割する
- コンウェイの法則: 組織のコミュニケーション構造がシステムの構造を規定する
コンテキストマップ — Bounded Context間の関係を定義する
複数のBounded Contextが存在するとき、それらの間には必ず何らかの関係が生まれます。 コンテキストマップ(Context Map)は、これらの関係を可視化し、統合パターンを定義するツールです。
コンテキストマップには9つのパターンがあります。重要な洞察は、これらのパターンは自由に選べるものではなく、 組織構造がパターンを決定するということです。
Partnership(パートナーシップ)
2つのチームが対等な立場で協調開発するパターンです。一方の失敗が両方に影響する密結合な関係で、 共同で計画しインターフェースを管理します。効率的なコミュニケーション基盤が必要です。
Shared Kernel(共有カーネル)
2つのコンテキストが共有する小さなモデル部分です。共有カーネルは最小限に保ち、 変更時は双方の合意が必要です。密接に協力する2チーム間で使用します。
Customer-Supplier(顧客-供給者)
上流(Supplier)と下流(Customer)の明確な依存関係があるパターンです。 下流の優先事項が上流の計画に反映されます。上流チームが下流チームのニーズに応じる責任を持ちます。
Conformist(順応者)
上流が下流をサポートする動機がない場合、下流が上流モデルにそのまま従うパターンです。 翻訳の複雑さを排除する代わりに設計上の制約を受け入れます。外部モジュールをas-isで利用する場合に使用します。
Anticorruption Layer(腐敗防止層 / ACL)
下流が隔離層を作り、上流モデルを自コンテキストの言語に変換するパターンです。 レガシーシステムや外部システムとの連携で最も重要なパターンの1つで、 上流の変更から内部モデルを保護します。
その他のパターン
| パターン | 説明 | 適用場面 |
|---|---|---|
| Open Host Service | 公開プロトコル(API等)でサービスを提供 | 多数の消費者がいるサービス |
| Published Language | 文書化された共有言語(JSON, Protobuf等)で情報交換 | Open Host Serviceと併用 |
| Separate Ways | コンテキスト間に統合を持たない | 統合コストが利益を上回る場合 |
| Big Ball of Mud | モデルが混在し境界が不明確なシステム | 警告パターン。隔離して伝播を防ぐ |
コンテキストマップの全体像
graph LR
subgraph upstream[上流]
A[販売コンテキスト\nOpen Host Service]
end
subgraph downstream1[下流1]
B[配送コンテキスト\nConformist]
end
subgraph downstream2[下流2]
C[請求コンテキスト\nACL]
end
subgraph external[外部]
D[決済サービス\nBig Ball of Mud]
end
subgraph shared[共有]
E[商品カタログ\nShared Kernel]
end
A -->|Published Language| B
A -->|Domain Events| C
C -->|ACL| D
A --- E
B --- E
style upstream fill:#8b5cf6,stroke:#6d28d9,color:#fff
style downstream1 fill:#3b82f6,stroke:#1d4ed8,color:#fff
style downstream2 fill:#3b82f6,stroke:#1d4ed8,color:#fff
style external fill:#ef4444,stroke:#dc2626,color:#fff
style shared fill:#f97316,stroke:#ea580c,color:#fffサブドメインの分類 — コア・サポーティング・ジェネリック
DDDでは、ドメインをサブドメインに分割し、3つのカテゴリに分類します。 この分類は、リソース配分の意思決定に直結します。
| 分類 | 定義 | 設計戦略 | 例(ECサイト) |
|---|---|---|---|
| コアドメイン | ビジネスの差別化要因。最大の競争優位 | DDDフル適用。最も優秀なチームを配置 | レコメンデーションエンジン、価格最適化 |
| サポーティング | コアを支援するがユニーク。外部調達困難 | DDDの戦術的パターンを適用 | 在庫管理、注文管理 |
| ジェネリック | 多くのシステムで共通。外部調達可能 | SaaSやOSSの利用。DDD不要 | 認証、メール送信、決済ゲートウェイ |
コアドメインにこそリソースを集中投下するのがDDDの戦略です。 すべてのサブドメインにDDDを適用する必要はなく、ジェネリックなサブドメインには既存のソリューションを活用するのが合理的です。
理解度チェック
ユビキタス言語について正しい説明はどれですか?
キーボード: 1〜4 で選択、Enter で回答