CTS-KB

開発手法ガイド:DDD 編 — AI に「何を作るか」を正確に伝える力

⏱ 約 10 分で読めます
#開発手法 #DDD #ドメイン駆動設計 #AI駆動開発 #Bounded Context #集約

🤖 AI 駆動開発で DDD が必要な理由

AI コーディングツールが強力になるほど、 「何を作るか」を曖昧に伝えたときのダメージが大きくなる 。品質の低いコードが一瞬で 100 行生成されるため、レビューするだけで人間の帯域が尽きる。

DDD(ドメイン駆動設計)は、 業務ドメインの言葉と構造をそのままコードに反映させる設計手法 。エンジニアが業務担当者と「ユビキタス言語」で会話し、その言葉でクラス名・メソッド名・モジュール名を付ける。このとき AI 駆動開発に 3 つの恩恵がある。

AI 駆動開発での効用DDD がもたらす状態
指示が短く正確になるOrder 集約に割引を追加して」で意図が通る
レビュー範囲が絞れる集約・リポジトリの境界で影響範囲が閉じる
新機能の追加点が予測できるドメインイベント・Bounded Context の境界が明確

本記事は開発手法ガイド:概要のシリーズ 4 本目。AI 駆動開発の前提となる設計原則として、DDD の要点を体系化します。

🧭 DDD の全体像 — 戦略と戦術の 2 層

DDD は大きく 2 層に分かれる。戦術だけ真似て戦略を欠くと「DDD 風 CRUD」になる。

扱うこと主要概念
戦略的設計システムをどう分割するかBounded Context / コンテキストマップ / ユビキタス言語
戦術的設計コンテキスト内でどう実装するかエンティティ / 値オブジェクト / 集約 / リポジトリ / ドメインサービス / ドメインイベント

AI 駆動開発で効果が高いのは 戦略側から整えること 。戦術だけ真似ても、Bounded Context が切れていない状態では「どの用語がどの意味で使われているか」が曖昧になり、AI に指示しても想定外の場所を触られる。

🗣️ ユビキタス言語 — AI への最強の指示手段

ユビキタス言語とは、 業務担当者・エンジニア・ドキュメント・コードで同じ語彙を使うこと 。これが AI 駆動開発で決定的に効く。

なぜ効くのか

状態AI への指示結果
ユビキタス言語なし「注文処理に割引機能を追加して」AI が勝手に DiscountProcessor クラスを作る/既存の Order.applyCampaign() と重複
ユビキタス言語ありOrder 集約の applyCampaign に期間限定割引を追加して」既存メソッドに沿って拡張され、不要な抽象が生まれない

ユビキタス言語を AI 駆動開発に組み込む方法

  • CLAUDE.md / AGENTS.md に用語集を置く — 「Order は受注全体を表す集約ルート。明細は OrderLine。決済は別 Bounded Context」のように定義
  • glossary を Bounded Context 別に分割 — 同じ「顧客」でも販売コンテキストと配送コンテキストで意味が違うことを明示
  • コードレビューで「用語ゆれ」を検知 — AI 生成コードで新語が勝手に出てきたら即座に質問する

🗺️ Bounded Context — AI に渡すコンテキストの境界

Bounded Context は「この境界内では用語が一意に解釈される」範囲。DDD の戦略的設計の中核であり、 AI 駆動開発における「コンテキストウィンドウに何を入れるか」の設計図 そのもの。

典型的な境界の切り方

EC ドメインであれば:

Catalog Context      — 商品・カテゴリ・バリエーション
Inventory Context    — 在庫数・引当・ロケーション
Sales Context        — 注文・決済・キャンセル
Fulfillment Context  — 配送・ピッキング
Identity Context     — 顧客・認証・権限

同じ「商品」でも、Catalog では「展示する情報」、Inventory では「在庫単位(SKU)」、Sales では「注文明細の一項目」と扱いが違う。

AI 駆動開発との接点

  • コンテキストを混ぜると AI が破綻 — 「商品情報の検索と、商品の出庫処理を 1 ファイルに書いて」と指示すると、境界をまたぐ不明瞭なモジュールが生まれやすい
  • 1 指示 = 1 コンテキスト — タスクが複数コンテキストに跨るなら、明示的に分割してから AI に渡す
  • コンテキストマップを参照先に — 各コンテキストの責務・関係(上流 / 下流 / 共有カーネル)を図で残し、AI に参照させる

🧱 戦術的設計の主要パターン

Bounded Context を切ったら、その中でどう実装するか。戦術パターンは 6 つ覚えれば十分。

パターン役割AI 駆動開発での効用
エンティティ同一性(ID)で区別される、ライフサイクルを持つオブジェクトAI が「どの Order か」を取り違えない
値オブジェクト値そのもので等価判定する、不変の小さな型(Money, Emailバリデーションを型で保証し、AI 生成コードの穴を減らす
集約強い不変条件で結ばれたエンティティ群と、その境界トランザクション境界が明確 → AI 生成コードの影響範囲が閉じる
リポジトリ集約を永続化から切り離して扱う抽象テスト差し替え可能 → AI が生成したロジックを高速テスト
ドメインサービスエンティティ・値オブジェクトに置きにくいドメインロジック「どこに書くか迷う処理」の行き先が明確
ドメインイベント「ドメインで起きた出来事」を一級のオブジェクトとして表現新機能の追加点が予測可能になる

集約設計の 5 原則

集約は DDD で最も誤解されやすい概念。AI に指示するとき、ここを押さえておくと生成コードが構造的に安定する。

原則説明
小さく保つ1 トランザクションで更新する範囲を最小化
ルート経由でしか触らない集約内エンティティへの直接参照を禁止
集約間は ID で参照別集約のオブジェクトを保持せず、ID だけ持つ
不変条件はルートが守るバリデーションを集約ルートに集約
1 トランザクション = 1 集約複数集約の同時更新は結果整合性で繋ぐ

🎯 AI への指示とレビューに DDD を活かす

指示テンプレート

AI に実装を依頼するときの型:

コンテキスト: {Bounded Context 名}
対象集約: {集約ルート名}
タスク: {ユビキタス言語で書かれた業務要件}
制約: {集約境界・不変条件・副作用の有無}

例:

コンテキスト: Sales Context
対象集約: Order(集約ルート)
タスク: 確定済み Order に対して「キャンセル」できるようにする。
        キャンセル時は OrderCancelled イベントを発行し、支払い済みなら
        決済返金は別コンテキストの Saga に委譲する。
制約: Order 集約の内側で完結。Inventory / Payment 集約は直接更新しない。

この程度の情報があれば、AI は集約境界を超えた改変をしない。

レビューチェックリスト

AI 生成コードが DDD の観点で健全か確認するポイント:

  • 集約ルート外のエンティティを外部から直接参照していないか
  • 集約間でオブジェクト参照していないか(ID 参照か)
  • バリデーションが集約ルートに集まっているか
  • 1 トランザクションで複数集約を更新していないか
  • ユビキタス言語にない新語(DiscountProcessor 等)が紛れ込んでいないか
  • ドメインイベントを発行すべき場所で発行しているか
  • インフラ層の型(ORM アノテーション等)がドメインに漏れていないか

🤔 AI が判断に迷うときの 2 つの問い

AI は「動くコード」を素早く出しますが、 境界線の判断(このロジックをどこに置くか、既存集約を拡張すべきか新規に分けるべきか等)では迷う ことがあります。そんなとき、 次の 2 つの問いを AI に投げ返す と、判断が一気に明確になります。

問い 1: 「責務が同じか、違うか?」

「このロジックを既存の Order クラスに追加すべきか、別クラスを作るべきか?」と AI が迷ったら、次の質問に変換させます。

「これは Order同じ責務 か、 違う責務 か?」

判定基準は 変更理由

状況判定行き先
同じ理由で同時に変わる同じ責務既存集約のメソッドとして追加
違う理由で別タイミングに変わる違う責務別クラス・別集約として切り出す

例:「Order に税金計算を追加するか?」 → 税率は税法改正で変わる、注文ロジックは業務ルール変更で変わる → 違う責務 → TaxCalculator ドメインサービスへ

問い 2: 「この Bounded Context においてベストプラクティスか?」

「一般的にはこう書く」が、その Context では適切でないケースがあります。AI が一般論で迷ったら、次に立ち返らせます。

「この Bounded Context の ユビキタス言語と集約境界 に照らして、ベストか?」

例:

Context「注文」の扱い集約ルート
Sales Context受注の意思決定単位Order
Fulfillment Context出荷の単位Shipment(Order ID で参照)
Accounting Context売上計上の単位Invoice(Order ID で参照)

同じ「注文」でも Context によって責務も集約ルートも違う。 「一般的な DDD の書き方」より「この Context のユビキタス言語でどう表現されるか」 が常に優先されます。

「AI が迷う」=「人間が決めていない」のシグナル

AI が判断に迷うのは、 人間側の指示が曖昧 か、 Bounded Context / 責務の切り方が未定義 だからです。AI を責めるのではなく、 自分が何を決めていないかを問い直すチャンス として使ってください。

AI: 「このロジックは Order に追加すべきですか?別クラスに切り出すべきですか?」

× 「適当に判断して」 — 構造が壊れる
○ 「Order と責務が同じか違うかで判断して」 — 判断基準を渡す
○ 「Sales Context のユビキタス言語に照らして」 — Context を渡す

このやりとりが定着すると、 AI が迷うこと自体が早期警告システム として機能し、設計の曖昧な箇所を発見する助けになります。

⚠️ DDD を採用したのに効かない失敗パターン

AI 駆動開発で特に発生しやすい失敗パターン。

1. アネミックドメインモデル

エンティティが getter/setter だけを持ち、ビジネスロジックが Service 層に吸い出される。AI は「この業務ルールをどこに書くか」の判断が苦手なので、指示なく任せるとこちらに流れやすい。

是正: Order.applyCampaign() のように、ドメインルールは集約メソッドに書く。AI への指示でも「Order エンティティのメソッドとして実装して」と明示する。

2. DDD 風 CRUD

用語だけ DDD(Aggregate, Repository など)を使っているが、中身は単なる CRUD。戦略的設計を省いたときに陥る。

是正: Bounded Context を切る前に戦術パターンを使わない。小規模であれば最初から CRUD と割り切る方が健全。

3. 集約肥大化

「関連するものは全部同じ集約」にしてしまい、楽観ロックの競合が多発・パフォーマンス低下。

是正: 不変条件を見直し、「本当に同時更新する必要があるか」で切り分ける。AI に集約設計を提案させるなら、「この業務で同時に守るべき不変条件は何か」をまず言語化させる。

4. ユビキタス言語の更新漏れ

業務担当者の言葉は時間とともに変わる。コードだけ古い用語のまま残ると、AI が新しい指示に古いコードを対応付けられない。

是正: 用語変更は CLAUDE.md の用語集に即時反映。リファクタリングは AI と一緒に進める(rename-symbol のような操作を AI に任せやすい領域)。

📐 戦略と戦術の積み上げ順序

ゼロから DDD を始めるなら、以下の順で積み上げる。

1. ドメインを粗く理解する
   └→ 業務担当者へヒアリング・イベントストーミング

2. Bounded Context を切る
   └→ 境界で用語がどう変わるかを確認

3. ユビキタス言語を決める
   └→ Context 別に glossary を作成

4. 集約を発見する
   └→ 強い不変条件で結ばれる単位を見つける

5. リポジトリ・ドメインサービスを整える
   └→ ここで初めてコードを書き始める

6. ドメインイベントを発行し始める
   └→ Context 間連携を明示的にする

段階 1–4 を飛ばすと、AI 駆動開発では 5–6 だけが高速化し、結局「速く壊れたアーキテクチャ」ができあがる。

📚 まとめ

  • DDD は AI に「何を作るか」を正確に伝える最強のフレームワーク 。ユビキタス言語・Bounded Context・集約の 3 点が揃うと、AI への指示が短く正確になる
  • 戦略的設計が 7 割 。戦術だけ真似ると DDD 風 CRUD になる
  • 集約境界が明確だと AI 生成コードの影響範囲が予測可能 。レビュー帯域の節約に直結する
  • ユビキタス言語は CLAUDE.md や glossary に書き下し、 AI が参照できる状態に保つ
  • AI が判断に迷ったら、 「責務が同じか違うか」「この Bounded Context においてベストか」 の 2 つの問いに立ち返らせる
  • AI の迷い = 人間側が決めていない シグナル。設計の曖昧さを発見する早期警告システムとして使う
  • アネミックドメイン・DDD 風 CRUD・集約肥大化・用語の陳腐化が代表的な失敗。レビュー時のチェックリストで検知する

🔗 関連記事

📖 関連用語