- 集約は「クラスの集まり」ではない
- なぜモデルを「まとめる」必要があるのか
- 不変条件は「同時性」の問題でもある
- 集約ルートが持つ責務
- 集約が大きくなりすぎる理由
- 集約を分けるという判断
- 集約は設計を難しくするための概念ではない
- この章のまとめ
集約は「クラスの集まり」ではない
集約(Aggregate)という言葉を聞いたとき、多くの人は次のようなイメージを持ちます。
- EntityとValue Objectを束ねたもの
- 1対多の関連をまとめた構造
- ルートEntityを持つオブジェクトグラフ
これらはすべて、集約の“形”を説明してはいますが、集約の本質を説明してはいません。
集約は、構造の話ではありません。集約とは、判断とルールを守るための単位です。どの範囲までを一つの判断として扱い、どこから先は別の判断として切り離すのか。その線引きこそが、集約を設計するという行為です。
なぜモデルを「まとめる」必要があるのか
第3章では、モデルが判断とルールを守る主体であることを説明しました。しかし、実際のシステムでは、判断は一つのモデルだけで完結しないことがほとんどです。
- 注文は、顧客と商品と支払いに関係する
- 予約は、日時と空き状況と制約条件に依存する
これらをすべて単一のモデルに押し込めると、モデルはすぐに破綻します。逆に、完全に分離してしまうと、「同時に守るべきルール」を保証できなくなります。
集約は、このジレンマに対する答えです。同時に守るべき不変条件を、一つの境界に閉じ込める。それが集約の役割です。
不変条件は「同時性」の問題でもある
集約を理解するうえで、重要なのは「同時性」という視点です。
- この操作とあの操作は、同時に行われてよいのか
- 状態が途中で食い違っても許されるのか
- 一貫性はどこまで保証されるべきか
これらは、ビジネスルールであると同時に、トランザクションの問題でもあります。
集約の境界とは、強い一貫性を保証する範囲です。この範囲の中では、不変条件が必ず守られなければなりません。一方で、境界の外側とは、最終的に整合すればよい、という設計も選択できます。
集約ルートが持つ責務
集約には、必ず外部との窓口となる存在があります。それが集約ルートです。
集約ルートの責務は単純です。
- 集約内部の不変条件を守る
- 外部からの操作を一元的に受け付ける
重要なのは、「内部のオブジェクトを直接操作させない」ことです。もし外部から内部のEntityやValue Objectを自由に変更できると、不変条件は簡単に破られてしまいます。
集約ルートは、門番のような存在です。正しい手続きを踏んだ操作だけを通し、それ以外はそもそも表現できないようにします。
集約が大きくなりすぎる理由
集約設計でよくある失敗は、「安全そうだから」という理由で、あらゆるものを一つの集約に詰め込んでしまうことです。
確かに、大きな集約は不変条件を守りやすく見えます。しかし、その代償として次の問題が発生します。
- 更新のたびに多くのデータを読み込む必要がある
- ロック範囲が広がり、並行性が下がる
- 変更の影響範囲が大きくなる
集約を小さくするとは、責任を放棄することではありません。どの一貫性を本当に守る必要があるのかを見極めることです。
集約を分けるという判断
集約を分けるときは、次のような判断基準で考えます。
- 同時に変更される必要があるか
- 不整合が一瞬でも許されないか
- 一つの操作として扱うべきか
これらの問いに「はい」と答えられる範囲が、一つの集約になります。
それ以外の関係は、IDによる参照やイベントによる連携で十分な場合がほとんどです。
集約は設計を難しくするための概念ではない
集約は、DDDの中でも特に難解だと感じられがちな概念です。しかし、その理由の多くは、「正解を探そうとする」姿勢にあります。
集約に唯一の正解はありません。重要なのは、その集約が
- どの不変条件を守っているのか
- なぜその境界なのか
を説明できることです。
この章のまとめ
集約とは、モデルをまとめるための構造ではありません。集約とは、同時に守るべき判断とルールの単位です。
次章では、この集約をどのように取得し、保存し、システムの外側とつなぐのか。そのための仕組みである「Repository」について掘り下げていきます。