DDD全然知らないくせに集約についてのスライドを見たまとめ

集約の設計と実装 // Speaker Deck

DDDに関する知識はほぼ無だけどノリでいけるっしょの精神で読んだ。コードもノリで読んでいる。
ちょこちょこ嬉しみポイントがあったので理解用まとめ。間違いもあるだろうと思う。
(嬉しみ = 普段悩んでいることに対して道がひらけた感があった) 書き終わって見返すと、「境界という概念(現実ままでなくて良い)」と「表明プログラミング」が嬉しみ高かったように思う

■ 集約とは
  • 関連するオブジェクトをひとかたまりとし、データを変更する単位(集約)として扱う
  • 集約は変更の一貫性、整合性を保証する
  • 集約が持つデータの範囲/集約の責務の及ぶ範囲の定義が大事
    • (この範囲を境界と言っているはず)

■ ルートエンティティ

  • 集約は、ルートエンティティを1つ持つ
  • 集約への変更はルートエンティティを通す
  • 集約の中のある子エンティティXを見つけたい時もルートエンティティを通す

■ エンティティXの同一性の管理

  • 集約の同一性を見たい場合は、ルートエンティティを比べれば見れる(はず)
  • 子エンティティXは同一性を気にしなくて良い。 なぜならば、
  • 子エンティティはルートエンティティから辿れるはず
  • すべての同一性を保とうとすると整合性管理が大変(だから、集約がある)

■ 集約の範囲(境界)の決め方

  • 小さく作る
  • 他の子エンティティと整合性を保つ必要があるものだけで集約を分ける
  • ただし 現実世界とは分けて考える。 ユースケースを無視しないで作る
    • 車にエンジンが付いているからといって、2つを同じ集約にしていいわけではない
    • 車とエンジンを切り離して「同一性を管理したい/変更を追跡したい」という要件があるのならば集約を分けるべき

■ ルートエンティティ/子エンティティ 詳しく

  • 一貫性/整合性の担保を実際におこなうのはルートエンティティ
  • なので、集約への変更は全てルートエンティティを通して行わなければならない
  • 子エンティティに変更を加える時もルートエンティティを通す
  • 子エンティティに別集約の参照を持たせたい場合、ルートエンティティを間接的に持たせるに留める
    • 「集約Aに変更を加えたら集約Bも変更された...」とかを避けるため
    • 参照を持たせないことで、別の集約の変更を行えないことを保証する
    • 「集約Aと集約Bは同時に変更されるものである」という要件ならば、集約Uを別で定義する
    • 集約Uはさすがにポインタで別の集約をもつっぽい
    • ChildEntity#doSomething() に引数で渡して 一時的な使用は可能

■ 契約による設計

  • 正しさ の書き方は「"状態P"の時に"処理A"を行なうと、必ず"状態Q"になる」という書き方が良い

    • それを実装でやるのが契約による設計(DbC)
    • ただしこれは制御構造ではない
      • (状態Pじゃないと処理Aをしない、ということではない?)
    • 仕様の明確化である
  • Modelが状態Qにならなかった場合、疑う対象は2つ

    • Modelへ指示した側(= 状態Pじゃないのに処理Aを依頼した)
    • Model(= 状態Pの時なのに状態Qにならなかった)