集約とは?
トランザクション整合性を保ちながら更新を行うオブジェクトのまとまりです。集約は主に「エンティティ」から構成されます。(IDで識別することが重視されるため)なお、「集約ルート」しか操作してはいけないです。
集約ルートとは?
外部から集約を操作できる。そうすることで集約全体の整合性を担保してデータ更新できます。
集約の例
注文と注文明細のエンティティがあった場合に、外部から更新できるのは集約ルートである「注文エンティティ」からのみ。
集約ルートからしか操作してはいけない例
userというオブジェクトがあったとしたら、セッターで直接変更してはいけないですが、メソッドを通じてなら変更を許すという考え方です。
1 2 3 4 |
const user = new User("太郎"); user.name = "次郎"; // × user.ChangeName = "次郎"; // ○ |
メリット
changeNameとかであれば事前にnullチェックなどを実装してあるはずなので、不正なデータの混入を防ぐことができるためです。
外部から内部のオブジェクトを直接操作せず、それを保持するオブジェクトに依頼することで不変条件を維持できます。これを「デメテルの法則」とも呼びます。
大きな集約
何も意識せずにモデリングした場合は大きな集約が出来上がります。
そうした場合に、複数のユーザーが同時に操作した場合にトランザクションが衝突する可能性が高くなります。また、多くのインスタンスを生成することになるためメモリの負荷も高まります。
小さな集約
大きな集約の問題を回避するために小さな集約に分けます。
大きな集約の方は小さく分割した集約の識別子(ID)のみ参照するようにします。
大きな集約で何も考えて作成するより設計難易度は高くなりますが、性能やスケーラビリティがtか空くなり、エンティティ間の依存関係も減ります。
集約のベストプラクティス
小さな集約を意識する
極力、値オブジェクトから構成する
真の不変条件(ビジネスルール)を整合性の中にモデリングする。
不変条件とは、どのような操作を行おうとしても維持されるビジネスルールです。
他の集約への参照へはその一意な識別子を利用する。
IDで参照する。
なぜか?
二つ理由があります。
集約ルートのみからのみ操作できるという法則(デメテルの法則)を守れるため
そもそも、エンティティのプロパティにインスタンスを持たなければ外部からメソッドを呼び出すこともできません。必然的に疎結合になって改修やテストが楽になります。
メモリの節約になるため
インスタンス 化されるプロパティに関係ないメソッドを呼び出したときは、そもそもインスタンスの生成→破棄のサイクルを回す必要がないです。なので、インスタンス 化してプロパティとして保持しなければそのサイクルが行われることがなくなります。
境界の外部では結果整合性を用いる。
複数の集約にまたがるビジネスルールでは結果整合性を使う。
あえてトランザクションを一つにまとめるパターン
UIの利便性を優先
画面の操作上、複数集約をまとめて作成するシナリオの場合は集約を一括りにして問題ない。
技術基盤の不足
結果整合性を実現するアーキテクチャが存在しない場合(イベントを扱うメッセージング基盤がない)
パフォーマンス
ID経由ではなく他の参照を直接参照した方が良いケース
この記事へのコメントはありません。