読者です 読者をやめる 読者になる 読者になる

たなかこういちの開発ノート

システム開発に携わる筆者が、あれこれアウトプットするブログ

参照系と更新系の非対称性について、追補

以前の記事を補足、あるいは主張を一部修正するものです。
 
〜・〜
 
 
ある要求仕様のセットがあったとき、そこに仕様変更のライフサイクルに違いのあるサブセットが認められるならば、それらは、同一のデータ資源(=オブジェクト)に関わることであっても、別々の“モデル”として捉えよう、というのがサブジェクト指向の一つの意図です。例えば、「受注」という同じデータ(≒管理対象)に関わることでも、「注文受付オペレーター」観点の“モデル”と「販売管理担当」観点の“モデル”とでは、要求仕様のセットが異なるし、その後の仕様変更の発生タイミングや頻度も異なるでしょう。そういった状況においては、「受注」サブドメインに関わる全ての要求を一つの集約やエンティティに全て載せてしまうと、いわゆるファット・モデルとなり、当初段階はなんとかやり遂げたとしても、その後の仕様変更の度に、当初開発段階に近い苦労を都度強いられることになってしまいます。サブジェクト指向では、データセットとしては同一実体なのだとしても、要求仕様の発生源が異なるのであれば、それぞれドメインモデルとしては異なるものとしてデザインしよう、と考えます。
 
参照系と更新系の要求発生源が異なる × サブジェクト指向 → 参照系主体のモデル + 更新系主体のモデル
 
“Web系”に代表される、フロントエンド・アプリとバックエンド・サービスに分離され、その組み合わせでデザインされるシステムにおいては、一般に参照系要求はフロントエンドが多く発生源に、更新系要求はバックエンドが主な発生源となっています。また、両者は独立した仕様変更ライフサイクルを持つので、前節サブジェクト指向の方針に基づき、同一のデータ資源に関するものでも、「フロントエンド・マターな要求に基づくモデル」と「バックエンド・マターな要求に基づくモデル」は、サブジェクトの異なるモデルだと捉えます。結果的に、一つのデータ資源について、参照系主体なモデルと更新系主体なモデルという、二つのドメインモデルが形作られることとなります。
 
非対称なのはモデルに対する要求発生源であり、フロントエンドでは参照系主体モデルのみ扱い、バックエンドでは更新系主体モデルのみ扱う、という話ではない
 
本記事や以前の記事で主張している参照系と更新系の非対称性とは、自分自身やや取り違えていたのですが、「フロントエンド・サブシステムではバックエンド・マターな更新系主体なモデルは使用しない」といった話ではありません。フロントエンド-バックエンドというアーキテクチャーは、リッチクライアントをインターネット越しに運用する場合のサブシステム分割を表します。参照系機能も更新系機能も、フロントエンドとバックエンドが協調して動作しない限り実現されません。
 
本記事や以前の記事で主張している参照系と更新系の非対称性とは、あくまで要求発生源が非対称である、ということです。フロントエンドであっても更新系に関わる機能を、バックエンドであっても参照系に関わる機能を、それぞれ装備はしなければなりません。
 
要求発生源とモデル“所有者”が一致するように、サブシステム境界は非対称とする
 
ただ、プレゼンテーション層〜データアクセス/永続化層までのアプリケーションスタックにおいて、どこからどこまでの層をフロントエンド側に、あるいはバックエンド側に装備させるか、という線引きにおいて、参照系と更新系とで差異が出るだろうという話はしました。この線引きは、モデルのいわば“所有者”が実際の要求発生源に添うように設計的にアレンジするものです。それでも、モデルの使用においては、双方とも相手先が所有者たるモデルを使用する必要はあります。
 
このフロントエンド-バックエンドの線引き問題は、モデリング上の特性を踏まえてはいますが、モデリング(仕様設計)そのものではなく、サブシステム分割という実装方式の問題です。(※一方、サブジェクトを捉えるところはモデリングそのもの(仕様設計)に関する問題です。)
 
"Query-side-Model-less" Architecture
 
そのフロントエンド-バックエンドの線引き問題に対する提案を改めて説明します。下図は、プレゼンテーション層〜ビジネスロジック層〜データアクセス層の図です。ただし、参照系側と更新系側の業務ロジックは分離されています。赤の点線は、フロントエンド・サブシステムとバックエンド・サブシステムの境界で、Web APIを差し込むラインです。この線引きに工夫をします。参照系側では業務ロジックの“所有者”をフロントエンドとします。更新系側では業務ロジックの所有者をバックエンドとします。バックエンドが提供するWeb APIは、よって、更新系はSOAライクに機能の提供、参照系はROA(※REST)ライクに“裸のリソースの提供”を行うものに仕立てます。
 

f:id:tanakakoichi9230:20160610021207p:image

 
参照系側モデルは無いわけではありません。フロントエンド側の実装として存在します。しかし、もはやバックエンド側が管理する対象では無い、とします。バックエンド側は、最低限のアクセス制御だけを行い、あとは汎用問い合わせに応えられるようにのみします。このようなアーキテクチャーを、バックエンド側が管理しないという意味において、"Query-side-Model-less"アーキテクチャと名付けてみます。
 
<補足>二種類の参照オペレーション
 
細かい話をしておきますが、「バックエンド・マターな更新系主体モデル」に関して、参照オペレーションが全くない、というわけではありません。「後に更新するために、現在状態を取得する」というかたちでの参照オペレーションが存在します。この参照オペレーションは、基本主キー指定で対象エントリーを“1件分”だけ取得するようなもの(が中心)です。このときの参照用のモデルは更新オペレーションにて使用するモデルと基本同一です。モデルには、「後の更新」に必要となる、その主キーの値、楽観排他制御のためのバージョン値、が含まれます。「後の更新のための参照」とは、更新するためのプロトコルを構成していると云えるもので、大きくは更新系処理の一部を為すものと捉えることができます。
 
それに対してフロントエンド・マターの参照系主体なモデルでの参照オペレーションは、filter条件を指定して該当するエントリーの一覧を取得するようなものが中心です。ユースケースによっては主キー値が含まれない場合もあります。なによりも楽観排他制御のためのバージョン値が含まれません。
 
<訂正>CQRSとの関係について
 
本ブログの今までの記事でもCQRSに触れることがありましたが、訂正が必要なようです。
 

 
杉本氏(@sugimoto_kei)や増田氏(@masuda220)の以上のツイートがあって、下記記事を読みました。
 

 

私が本記事や以前の記事で参照系と更新系の分離を云うとき、その動機は「要求発生源が異なるのであれば、サブジェクト指向の考えに則って、ドメインモデルも分離しよう」というところから出ています。
 
CQRSの第一の動機はパフォーマンスにあるようです。一般に参照系の方がパフォーマンス要求が厳しいので、参照系と更新系とでサブシステム(?)を切り離して、それぞれに適した異なるシステム・アーキテクチャーを採用できるようにしよう、というものです。CQRSの原典としては、内部アーキテクチャーに関心があり、QueryとCommandでモデルを変えることは必定では無いということです。CQRSの原典としては、Query系とCommand系でドメインモデルはむしろ一般にはシェアするということです。
 
少し抽象して理解するならば、サブジェクト指向の話は、要求発生源の違いで、つまるところ機能要求の違いで、それに伴って分離アーキテクチャーを採用しようという話であるのに対して、CQRSの「パフォーマンス理由」と云うのは、非機能要求の違いでシステム・アーキテクチャーを分離しようという話なのだと理解する事もできます。
 
◆以上
 

関連記事

参照系と更新系の非対称性について - たなかこういちの開発ノート

業務プロセス、業務ロジックの理解と、フロントエンド−バックエンド間I/Fの詳細 - たなかこういちの開発ノート