データモデル設計ガイド

DDD と非 DDD のデータ設計 — 何が違うのか

集約・整合性境界・FK の張り方・トランザクションの単位。データ設計の観点で DDD と非 DDD を中立に比較する入口ページ。

DDD と非 DDD のデータ設計 — 何が違うのか eyecatch

このシリーズで扱うこと

このシリーズでは、同じ業務要件を「伝統的な正規化中心の設計(非 DDD)」と「DDD の集約中心の設計」でそれぞれ組んだらどう違うかを、EC の「カート」「注文」を題材に並べて見ていきます。どちらが正解という話ではなく、何がトレードオフになっているかを可視化するのが目的です。

  • カートで比較 — カート集約の中に明細をまとめるか、カートと明細を対等なテーブルとして扱うか
  • 注文で比較 — 注文・明細・配送先・支払をひとつの整合性単位にするか、複数の集約に分けるか
  • 在庫で比較 — 引当・在庫数・入出庫履歴を 1 トランザクションでまとめるか、集約と履歴を分けるか
  • 選択指針 — チーム規模・業務複雑度・読み書き比率・マイクロサービス化で見る判断軸

※ DDD(ドメイン駆動設計)は本来アプリケーション設計論ですが、ここでは「データ設計に落ちる部分」だけに絞って扱います。ユビキタス言語・レイヤードアーキテクチャ・ドメインサービスなどアプリ層の話は扱いません。

データ設計における「集約」とは

DDD でいう集約 (Aggregate) は、データ設計の観点では次の 3 つがセットになった「かたまり」を指します。

  • 整合性の単位 — 集約の内部不変条件(例: 「注文明細の合計 = 注文の合計額」)は、1 トランザクションで満たす
  • アクセスの単位 — 集約の外側からは 集約ルート(例: order)経由でのみアクセスし、明細テーブルを直接触らない(アプリ側の規約)
  • 参照の単位 — 集約をまたぐ関係はID 参照で表現し、FK 制約を張らない(または、実務では張ることもあるが「論理的には切れている」扱い)

非 DDD の正規化中心設計は、これらを区別せず、業務に関係するテーブルをすべて FK でネットワーク状につなぎます。データ整合性は主に FK 制約とトランザクションで DB 側が担保する、という発想です。

つまり、DDD は「どこからどこまでを 1 トランザクションで守るか」という線引きを最初に決めてからテーブルに落とす設計手順です。非 DDD は「正規化したあとで、どこまで FK を張れるか」を積み上げる設計手順。出発点が逆と言ってもいいくらい違います。

比較軸 — 6 つの観点で並べる

以降のページで繰り返し出てくる比較軸を先に整理しておきます。

観点非 DDD(正規化中心)DDD(集約中心)
整合性の単位スキーマ全体。FK 制約で DB が保証集約内で保証。集約間は結果整合性 or アプリ保証
FK の張り方関係があるところ全部に張る集約内は張る/集約間は ID 参照(FK を張らないこともある)
トランザクション境界業務の流れに合わせて広く取りがち集約単位で短く保つ
読み取りJOIN で素直に一覧化できる集約をまたぐ読み取りは別途設計(読み取り専用クエリ/ビュー/CQRS)
変更の波及スキーマ変更が複数画面・複数バッチに波及しやすい集約内に閉じれば、集約外への影響は少ない
マイクロサービス化FK が絡んで境界が切りにくい集約境界=サービス境界にしやすい

どちらの列も「良い/悪い」ではなく特性です。小規模なモノリス・読み取り中心の業務システムでは左列のほうが生産的なこともあれば、ドメインが複雑で書き込み整合性が重要な業務では右列が事故を減らすこともあります。選択指針 のページで具体的な判断軸を見ていきます。

よくある誤解 — 「DDD = FK を張らない」ではない

DDD のテキストを誤読すると「集約間には FK を張ってはいけない」と受け取りがちですが、これは論理モデルと物理モデルを混同した読み方です。

  • 論理モデル上: 集約間は ID 参照。集約外のデータ整合性を DB に頼らない、という意思表示
  • 物理モデル上: それでも FK 制約を張るか否かは運用判断。データクレンジングや障害時の整合性担保として FK を張るのは合理的

重要なのは、「集約をまたぐ書き込みを 1 トランザクションでまとめようとしない」「集約外のデータが即座に整合することを前提に設計しない」というアプリ側の規律です。FK の有無はその帰結にすぎません。本シリーズでも、DDD 側の DDL 例に FK を書くケース・書かないケースの両方が登場します。