DDDの集約について

今回はDDDの集約という概念についてこちらの本を元に解説したいと思います.僕自身DDDを勉強をする中,集約がいまいちつかめず,実際のコードでどの単位で集約を作ればいいか迷うことが多かったので,この本を読むことで少し理解が進んだのでメモ的にアウトプットしておきます.

集約とは

まず集約の定義について見ていきます.この本では様々なソースの集約の定義を載せてくれています.いくつかを抜粋しますと IDDDによると 集約は、エンティティとバリューオブジェクトをクラスタ化するために慎重に作られた一貫性のある境界です. Wikipediaによると 集約はルートエンティティによって結合されたオブジェクトの集合体です.集約のルートは,外部オブジェクトがそのメンバーへの参照を保持することを禁止することで,集約内で行われる変更の一貫性を保証します.

僕は正直この定義を見た時に何となくわかるが,一貫性って具体的に何?,その境界ってどう考えるの?っと思いました.そこでこの本の例を用いて説明していきます.

実際の例

本書で想定するアプリケーションは,UserがWishを作成してサービス上に登録できるサービスです.このとき以下の2つのケースにおいてUserとWishの間に保つべき一貫性があり,集約としてまとめるべきか 否かを考えていきます. 1. UserがいないとWishを作成することができないケース 2. ケース1の条件に加え,1User3つまでしかWishを作成できないケース

一貫性について考える時,並列で処理を行ったときに一貫性が保たれるか,破られるかを考えるとわかりやすいです. ケース1の場合だとプロセス1とプロセス2が並列で走った場合に以下のようになります.

f:id:harada-777:20200930085814p:plain:w300

ケース1の場合いくら並列で動いても一貫性が破られることがありません.なので集約としてUserとWishをまとめる必要はありません.

ケース2の場合だとプロセス1とプロセス2が並列で走った場合に以下のようになります.

f:id:harada-777:20200930085818p:plain:w300

ケース2だと図のように,プロセス1のWishの作成がコミットされる前に,プロセス2でWishのカウントが走ってプロセス2側から見たWishのカウントが2となってしまい,Wishを作成する場合が発生します.この結果1Userが作成できるWishが3つまでという条件が破られてしまいました.よってこの2つは守るべき一貫性があるのでUserとWishは集約としてまとめるべきです.また1Userが持つWishの数はUserが知るべきなのでルートエンティティはUserになります.

まとめ

集約をどうするかっていつも悩んでいたのですが,並列処理しても一貫性が保たれるかという考え方は1つ良い指標になるなと感じました.実際のコードは以下に上げているのでよかったら見てください. GitHub - Yoshiaki-Harada/aggregate-example