考える場所

ココロとカラダ、思考する全部

CQRSの小さな演習(last) CQRS

前回まではコマンド側のクラス構成を中心に見てきました。今回はクエリ側も含めてデータ取り扱い方を俯瞰して考えてみたいと思います。

クエリ

クエリは画面表示上の都合のためにあります。クエリ側のオブジェクト(以降、DTO)とコマンド側のオブジェクト(以降、ドメインオブジェクト)を別々に考えるのは、単純な話、画面表示させたい情報がドメインオブジェクトではないからです。たとえばページ番号やソート情報などはドメインオブジェクトとしては不要だったり、内部的なステートはDTOとしては不要だったりします。

The fundamental difference is that in CQRS objects are split into two objects, one containing the Commands one containing the Queries.
-- CQRS Documents by Greg Young

CQRSはCQSに対して、クエリをもつオブジェクトとコマンドをもつオブジェクトを別ける、というところに違いがあるようです。(CQSはクエリであるメソッド呼び出しに副作用があってはいけないということを言っている??)

演習では、DTOを取得するためのインタフェースを(伝統的な)DAOという名称にしました。ドメインオブジェクトを取得するためのリポジトリとは別のインタフェースです。画面表示させたい情報が非正規化したものであるときは、非正規化した型のDTOを設けてDAOから取得できるようにします。ドメインオブジェクトだけでこれをすべてやろうとするのは複雑過ぎです。

イベントソーシング

さて、コマンド側ではイベントを起すことまでしか考えませんでした。イベントは追加のみで不変なので、トランザクションがシンプルになります。また、イベントをすべて残すことができまた追うことができれば、完全な履歴を残すことと同時に結果整合性を保てるメリットがあります。何が起こったかというイベントがあるのですから、すべてを足し算すれば今どうなっているかというステートを得ることができる訳です。イベントソーシングは、イベントを追加し続けて、必要なときにイベントを追ってステートを組み立てることができるようにするものです。

f:id:fukuchiharuki:20160814175037p:plain

CQRS

ここまでのお話にいろんなモデルが登場しました。まずはドメインオブジェクトです。ドメインオブジェクトはコマンドを受けてイベントを起こします。画面表示のためのDTOはイベントから組み立てるステートです。しかし、画面表示のためにいつもイベントからステートを組み立てるのは非効率ですから、リードモデルを設けてイベントをステートとして射影しておきます。従って、DTOはシンプルにリードモデルを取得したものになります。

f:id:fukuchiharuki:20160625105727p:plain

演習ではイベントソーシングをやってみたかったわけではないので、ドメインオブジェクトがイベントを起こすようにモデルを設計したものの、イベントをすぐさま射影してステートを永続化するようにしました。永続化の仕組みをイベントソーシングにしたとしても、リポジトリとDAOの実装がそのようになるだけで、ドメインオブジェクトやDTO周りの設計はそのままになるはずです。

おわりに

7回に渡って、CQRSの自分なりの理解を整理してみました。実際にコードや記事を書いて、こういう理解で大丈夫なんだっけ?と考えてみることは何より自分のためになったなと思います。マイクロサービスという言葉も話題になっていますし、シンプルな設計は複雑化するシステム開発を背景にますます注目されていくことと思います。

次のスライドでこの記事を参考として挙げてもらっています。ありがとうございます。

最初

blog.fukuchiharuki.me