概要
- Java読書会でせっかく勉強したのにつぎつぎと忘れていくので、印象に残ったところを記録していく
5章 マイクロサービスアーキテクチャにおけるビジネスロジックの設計
ビジネスロジックを設計上、どのように構築していくか
Transaction scriptパターン
- もっともシンプルな形態
- ビジネスロジックはサービスクラスに持たせて、エンティティクラスはデータだけ
- エンンティティの方はORマッパーでマッピングする
- 利点
- 設計が簡単
- エンティティ側がデータだけなので、責務について悩むこともない
- ロジックとデータが分離されている
- ビジネスロジックとデータ(データベースのスキーマ)の変更頻度・ライフサイクルは違うので別れている方が良いという考え方もある
- 設計が簡単
- 欠点
- ビジネスロジックの重複
- ビジネスロジック間の共通ロジックについて、共通化がきれいにできない
- ロジックは全部サービス側の責務になってしまっているので、共通化したとしても結構汚くなるでしょう。例えば、AbstractServiceみたいな親クラスを作って、共通ロジックを親クラス持ちにするのもよくあるけど、数あるサブクラスのうち2つの共通化にしかなってないとそれは親クラスの責務なのか?となるでしょう。
- ビジネスロジックの重複
Transaction Scriptについては、利点も協力だけど、この本のスタンスとしては、より柔軟で強力なDomain Modelパターン(とその系譜)の方が複雑なロジックを実現するには適しているとしている。
Domain Modelパターン
- 柔軟かつ強力な形態
- 外部からの要求の受け口となるサービスクラスは入口となるメソッドはもつが、ほとんどのビジネスロジックはモデルクラスが持ち、サービスクラスはモデルのメソッドを呼ぶだけ
- 利点
- (オブジェクト指向的な意味で)設計が分かりやすい
- モデルクラスがデータとそれに関連するビジネスロジックを持つので、オブくジェクト指向的な役割分担がなされる
- 結果的に共通化が促進される(共通ロジックもどのクラスの責務なのかが明確になり各モデルクラスに分散されていく)
- テストがしやすい
- これが真実かどうかは作り方によるが、この本に出てくるモデルクラスはそれなりにテストしやすくなっている
- オブジェクト指向の本来持っている柔軟性が活かしやすい
- GOFのデザインパターンなどが活かしやすい
- (オブジェクト指向的な意味で)設計が分かりやすい
- 欠点
- 設計難易度が高い
- ORマッパーとの使い方に気を使う
- Transaction Scriptならテーブルとのマッピング用なので、クラスからスキーマを作るので、スキーマからクラスを作るのでもどちらでも良かったけど、Domainモデルでは単純にはいかない。
個人的にはDomain Modelパターンは、うまく行けば綺麗だけど、設計が崩れないよう、細心の注意を払わなければいけないので、かならずしも好きではないです
Aggregateパターン
- AggregateはもともとDDDの言葉。
- モデリング後の各エンティティを、従属関係、ライフサイクル、意味論などの観点からグルーピンングし、各グループをAggregateと呼ぶ
- 例
- Orderアグリゲートとは、Order、PaymentInfo、DeliveryInfo、OrderLineItemの集合となる。アグリゲートの中で特に中核となるものをアグリゲートルートとよぶ
- 通常のドメインモデルであっても実際に作ったことのある人ならOrderLineItemはOrderの一部分であり、Orderが削除されるときにはOrderLineItemも削除されるのは感覚的に分かるはず
- 一方で、Orderテーブルの外部キーとして、Restaurantへの参照があったとしも、RestaurantはOrderとは別のライフサイクルを持つことも感覚的に分かるはず
- Aggregateパターンでは、これらを明確にする
- Aggregateパターンでは、Aggregateが整合性の単位となる。
- 例
- OrderLineItemを個別に作成・削除するのではなく、Orderに対する更新処理として表現する
- 実装上はTransactionが使えるなら、一つのTransactionに収まるようにする
アグリゲートとマイクロサービス
- 概ねマイクロサービスとアグリゲートを1対1にすると、それらしい設計になる
- 場合によっては1対多でもいいのかもしれない。
- 単純なDomain Modelだと、Domain Modelのどの部分がどのサービスに担当になるのか不明瞭
- アグリゲートというモデル上の境界を導入することで、サービスへの対応がしやすくなる
- この章の本題であるビジネスロジックは、各アグリゲートが持つようにする
- Domain Modelを強化したようなもの
- 例:OrderサービスとOrderアグリゲート、KitchenサービスとKitchenアグリゲート
- アグリゲートをまたがる参照は、主キーの参照を持つようにする
- サーガによって、サービスを渡り歩く処理をする場合は、1つのアグリゲートごとに1つのトランザクションを作る
Domain Eventパターン
- アグリゲートが生成、更新されたときはイベントを発行するということ
- 単位がアグリゲートなのが大事
- イベントの用途1:ユーザーへの通知
- 例えばOrderの配送開始をユーザーにメールで通知するなど
- Orderの更新処理の一部として、メール通知のロジックも含めることでも実現可能である
- イベント経由にしておいたほうが、関心事が分離されて、拡張性もある。
- 通知手段はいくつでも増やせるなど
- イベントの用途2:別のマイクロサービスへの通知
- 7章のCQRSパターンのように、更新とクエリーが別サービスになっている場合は、クエリー側のサービスは更新側サービスからイベントを拾って、クエリーのためのDBを更新する
- マイクロサービスでは、各サービスごとにDBをもつので、結果的に何らかミラーリングが必要になることも多くなる。そのためにはイベントは欠かせなくなる
感想
- アグリゲートは、マイクロサービスの構成を考える上で、根幹をなす考え方だと思われる
- イベントというのは組み込みでは当たり前のものだけど、ついにWebの世界でもイベントが必要な時代になったかと感じる