エリックエヴァンスのドメイン駆動設計を読んでいる(第2部 第6章-1)
ドメインオブジェクトのライフサイクル
全てのオブジェクトにはライフサイクルがあり、また他のオブジェクトとの関連もある。
あるオブジェクトが消えるときは他のオブジェクトも同時に消えなくてはいけなかったり、あるオブジェクトが作成されたタイミングで必ず作成されなくてはならないオブジェクトもある。
これらのトランザクションの整合性を保つために、明確にその領域を区別する必要があるということらしい。
そしてその領域をそれぞれアグリゲートと呼びます。
アグリゲートごとにオブジェクト群を作成するやつをファクトリと呼び、オブジェクト群に対する操作を提供するやつをリポジトリと呼びます。
一言でいうと、アグリゲートで区切るスコープによって不変条件が維持されなければならない範囲が示され、ファクトリとリポジトリはアグリゲートごとに存在してオブジェクトの生成や操作を提供ということ。
アグリゲート(集約)
例えば複数のクライアントで同時に同一オブジェクトにアクセスするようなシステムを考えてみる。
同時に編集されたりした場合に備えてトランザクションを保つ必要のある範囲で排他処理を行うことは一般的だと思うが、 この排他処理の範囲が広すぎた場合、いたるところでロックが発生してしまい、とても使いにくいシステムになることが容易に想像がつく。
ではどの範囲で区切るか?という設計を行うのがアグリゲート。 簡単に言うと、関連するオブジェクトの集まりであり、データを変更するための単位として扱われるものがアグリゲート。
これはビジネス領域の知識がとても大切。 今の現場にいるDDD師匠的な人はDDDはアグリゲートだというようなことを言っていた気がする。 真意はまだわからないですが、わかる日が来るのかな。
各アグリゲートにはルートと境界がある。
ルートはアグリゲートに1つだけ存在し、エンティティである。 アグリゲートのメンバの中で、外部のオブジェクトが参照していいのはルートだけ。
あるアグリゲートへのアクセスの口を1つに制限したいためこのような制約が必要になる。
アグリゲートに関わる約束事
集約のルートエンティティはグローバルな同一性を持ち、不変条件をチェックする責務を負う ルートエンティティは集約外から見て一意じゃなくてはいけないとかそういうことだと思われます。
集約の外にあるオブジェクトは集約のルートエンティティのみを参照可能。ルートエンティティは内部のエンティティへの参照を他のオブジェクトに渡せるが、受け取ったオブジェクトはそれを一時的に扱うだけ。参照を保持してはならない。バリューオブジェクトの場合はどうでもいい。
集約内部のオブジェクトは他の集約のルートエンティティへの参照を保持することができる
削除の操作は境界内部に存在するあらゆるものを一度に削除しなければならない。 これはあれですね。トランザクションの範囲が集約なのでなんとなくイメージどおりの話かと。
集約内部に存在するオブジェクトに対する変更がコミットされるときには集約全体の不変条件がすべて満たされてなければならない。 変更をコミットするタイミングで不変条件を満たすチェックを行う必要があるということか?だとするとルールの一番上にあるように、ルートエンティティがそれをチェックする責務を負う形になりそう