(※前回からの続きです。)
CQRSはモデリング上の本質的な課題への対応である
CQRS(Command-Query Responsibility Segregation、コマンド・クエリ責務分離)の採用は、現代的なシステムではほぼ全て必然的にそこへ帰結すると考えた方がよいと思います。CQRSという用語は「実践ドメイン駆動設計」を読むまで知りませんでした。というよりも、参照系と更新系を分離して設計しようという話をDDDが言及しているとは知りませんでした。しかし、下記記事で書いたように、要求・要件の分析観点から、参照系業務ロジックと更新系業務ロジックは非対称に構築すべきという点はむしろモデリング上の本質的な課題だとの考えを持っていましたので、CQRSはすんなり理解できました。
<'15/8/3更新>
※CQRSをサブジェクト指向から読み解く説明をしています。こちらも参照してみてください。
リポジトリーは「コレクション指向」か「永続指向」かの選択が重大
古いDDDの教科書の中には、リポジトリーのI/Fはコレクションライクにして、RDBMSなどの基盤層の実装実情を隠蔽化すべき、という点を強調しているものがあったように記憶します。現代においては任意のO/Rマッパーを用いれば自ずとこの要件は満たされるので、実際的にはあまり気にかけずともよい点と思います。
それよりも、「実践ドメイン駆動設計」にて「コレクション指向」、「永続指向」とされているスタイルの違いについて、どちらを選択するかでシステムのアーキテクチャースタイル、プログラミングスタイルが決定的に変わるので、そして後で変更することはほぼ不可能なので、この点をよく判断することに時間をかけた方がいいです。「実践ドメイン駆動設計」では「どちらの選択もあり得る」という点を強調しているように読めました。私は、現代においては「「コレクション指向」を選択すべき積極的な理由が無い限り、「永続指向」を選択すべき」と考えます。
「コレクション指向」を私はインスタンス指向といっています。対して「永続指向」を値指向といっています。両者の違いは次のようにまとめられます。
「コレクション指向」
|
「永続指向」
|
(インスタンス指向のデータストア)
|
(値指向のデータストア)
|
mutableなインスタンスを書き換える
|
DTO的なものの受け取りと引き渡し
|
Embedded OODB
|
RESTful/風APIを取り付け易い
|
集約を構成するエンティティの部分更新が可能
|
常に集約全体の一括更新となる/巨大集約には不向き
|
純粋関数型プログラミングとの相性が悪い
|
純粋関数型プログラミングとの相性が良い
|
インスタンス指向のORMの代表はHibernateです。インスタンス指向では、あるエンティティのエントリー(レコード)のオブジェクトリファレンスを得たら、以降、参照も更新もそのオブジェクトリファレンスの指すインスタンスを用いてのみ可能です。エンティティとして同型のクラスの(ad-hocにnewしたような)別のインスタンスに全く同一のID値を持たせても、オブジェクトとしてインスタンスが異なっているので、それは単にそういう値を持っている一時的なDTO的なものと見なされ、ORMを通しての更新は行えません。アプリケーションのコードから見て、ORMから得られたエンティティのインスタンスは、永続化されているエンティティのインスタンスそのものと認識されます。このインスタンスは"mutable"であることが重要な性質です。つまるところインスタンス指向のORMは、アプリケーション実行環境内にEmbeddedなOODBを再現します。
値指向のORMの代表はS2JDBCです。値指向のORMは、あるエンティティのエントリー(レコード)を、基本的にDTOもしくはバリューオブジェクト同様のもので返します。値指向では、オブジェクトのインスタンスの同一性には関心は払われず、ID値の一致でのみエンティティ内のエントリー(レコード)を識別します。参照時と更新時でオブジェクトのインスタンスが異なっていても構いません、ID値や楽観ロック用のバージョン値が妥当でありさえすれば。
インスタンス指向のORMが実現するEmbedded OODBはなかなかカッコいいです。初期のDDDがそこに未来を見たことは納得できることです。ただ、インスタンス指向の、つまり「コレクション指向」のリポジトリーがその力を発揮できるのは、「Monolithic」なシステムに限られます。
ここで「Monolithic」とは分散サービス構成でない、ということを表現するために言っています。Monolithicでも内部のモジュールやサブドメインがきっちりデザインされ整理されていれば、DDD的に保守上の問題は全くないです。そもそもDDD自体は分散サービス構成にせよと言っている訳ではありません。・・・という意味での「Monolithic」です。
分散サービスなアーキテクチャーを取るならば、 データの存在形態は、HTTPで伝送されているJSONだったり、メッセージングのキューにシリアライズされていたり、アプリケーションのプロセス内ですら、左から右へ加工されながら転送される"immutable"なDTO的なもの、あるいは関数型の代数的データ型、だったりします。つまり、いくらある一つのアプリケーション(サービス)の内部で、インスタンス指向のORMがEmbedded OODBを実現していても、その“インスタンス同一性”が有効に使える実装的なスコープが極端に限定されてしまうのです。
では、「コレクション指向」のリポジトリが有効な場面はどういうところになるのでしょうか。次の条件を満たすような利用ケースで有効でしょう。
- 集約が本質的に巨大である
- 集約の部分的更新が高頻度発生する
- 集約のデータ構造そのものの変更(エンティティの関連の新規出現や消滅)が高頻度発生する
- 以上により、都度の一括更新をすることに、パフォーマンスや設計難度の面でデメリットが出てくるようなデータ構造を扱うアプリケーション
・・・となります。具体的にはCADやDraw系描画アプリなどが該当すると言えそうです。
◆以上
(※次回へ続きます。)