計算された値と単純な読み取り-ドメイン主導の設計の悩​​みの種!


9

私が絶えず直面している問題は、データストアに対して効率的に機能しながら、ドメインロジックによって駆動される計算値を処理する方法です。

例:

リポジトリからサービスを介して製品のリストを返しています。このリストは、クライアントが送信したリクエストDTOからのページネーション情報によって制限されます。さらに、DTOはソートパラメータ(クライアントフレンドリーな列挙型)を指定します。

単純なシナリオでは、すべてがうまく機能します。サービスはページングとソートの式をリポジトリに送信し、リポジトリは効率的なクエリをDBに発行します。

ただし、ドメインモデルからメモリに生成された値を並べ替える必要がある場合は、すべてが機能しなくなります。たとえば、Productクラスには、ビジネスロジックに基づいてブール値を返すIsExpired()メソッドがあります。今、私はレポレベルでソートおよびページングすることはできません-それはすべてメモリ内で行われ(非効率的)であり、私のサービスはこれらのパラメーターをレポに発行するタイミングとソート/ページングを実行するタイミングの複雑さを知る必要があります自体。

私にとって意味があると思われる唯一のパターンは、エンティティの状態をdbに格納することです(IsExpired()を読み取り専用フィールドにして、保存する前にドメインロジックを介して更新します)。このロジックを別の「読み取りモデル/ dto」と「レポート」リポジトリに分離すると、モデルが必要以上に貧弱になります。

ところで、このような計算で私が見たすべての例は、実際にはインメモリ処理に頼っており、長期的には効率がはるかに低いという事実を無視しているようです。多分私は時期尚早に最適化していますが、それはちょうど私と一緒に座っていません。

DDDを含むほぼすべてのプロジェクトで一般的であると確信しているので、他の人がこれをどのように処理したかを聞いてみたいです。

回答:


3

同じデータモデルの2つの異なるドメインモデルがあると、ドメインが貧弱になるとは思いません。貧弱なドメインモデルとは、頻繁に変更されるビジネスロジックが、サービスレイヤー内のドメイン(さらにはUIレイヤー内)から隠されているモデルです。

コマンドとクエリのドメインモデルの分離は頻繁に使用され、CQRS(コマンドクエリの責任の分離)でグーグルできる優れた頭字語があります。

ドメインモデルパターンを採用するUdi Dahan

以前は、コマンドとクエリの両方を処理する単一の永続オブジェクトモデルを作成することに「成功」​​していましたが、システムの各部分が異なる方向にモデルを引っ張っていたため、スケーリングが非常に困難であることがよくありました。

多くの場合、開発者はビジネスが実際に必要とするよりも厳しい要件を引き受けます。ユーザーに情報を表示するためにドメインモデルエンティティを使用する決定は、そのような例にすぎません。

[...]

覚えるのに十分古いもののために、COM +の使用に関するベストプラクティスは、読み取り専用と読み取り/書き込みロジック用に別々のコンポーネントを作成することをガイドしました。ここに、10年後、Entity Frameworkのような新しいテクノロジーがありますが、同じ原則が引き続き適用されます。

Akkaアクターと機能ドメインモデルを使用したCQRS、Debasish Ghosh

グレッグ・ヤングは、DDDとCQRSに関するいくつかの素晴らしいセッションを提供しました。2008年に彼は、「単一のモデルがレポート、検索、およびトランザクションの動作に適切であってはなりません」と述べました。少なくとも2つのモデルがあります。1つはコマンドを処理し、ユーザークエリとレポートを提供する別のモデルに変更をフィードします。アプリケーションのトランザクション動作は、集約とリポジトリのリッチドメインモデルを通じて実行されますが、クエリは非正規化データモデルから直接提供されます。

CQRS、Martin Fowler

CQRSが導入する変更は、更新と表示のためにその概念モデルを個別のモデルに分割することです。これは、それぞれCommandQuerySeparationの語彙に従ってCommandとQueryと呼ばれます。理論的根拠は、多くの問題、特により複雑なドメインでは、コマンドとクエリに同じ概念モデルを使用すると、どちらもうまく機能しないより複雑なモデルになることです。

つまり、コマンドモデルに有効期限を処理させてデータベースに渡すというアイデアは、まったく問題ありません。上記の最初の記事を読むと、似ていますがより複雑なシナリオが表示されます。


2

仕様

あなたはすでに回答を受け入れましたが、DDDについて尋ねましたが、これと完全に一致するのがEvansが「仕様」と呼んでいるものです:
直接Google Booksリンク
このリンクが機能しない場合は、これらの結果で本を確認してください
本をお持ちの場合は226ページです。

227ページには、仕様の3つの使用方法があります。検証、選択、新しい特別なオブジェクトの作成です。あなたのものは「選択」です-IsExpired。

'specificaiton'コンセプトのもう1つは、効率のために、メモリ内オブジェクトを操作するためのコードの1つのバージョンと、最初に取得することなくリポジトリを効率的にクエリするためのコードの別のバージョンが必要になることを認めていることです。すべてのオブジェクトをメモリに。

単純な世界では、これはSQLバージョンをリポジトリに置き、オブジェクトバージョンをモデルに入れることを意味しますが、もちろん欠点があります。ロジックは2つの場所にあり(悪い、誰かがそれらの場所の更新を忘れる)、リポジトリにドメインロジックがあります。

したがって、答えは両方のロジックセットを仕様に含めることです。インメモリバージョンですが、リポジトリバージョンもです。たとえばn-hibernateを使用している場合は、リポジトリバージョンにその組み込みクエリ言語を使用できます。

それ以外の場合は、仕様オブジェクトから使用されるこの仕様用の特別なリポジトリメソッドを作成する必要があります。仕様に一致するオブジェクトのコレクションの呼び出しは、リポジトリではなく仕様を通過します。そして少なくともコードは将来のメンテナに「私は2か所にいるので、忘れないでください」と叫びます。非常によく似た問題を解決するための231-232ページに素晴らしい例があります。

仕様は、DDDの「純度」の「許容」漏れ/ずれです。それでも、さまざまな目的のニーズに対応できない場合があります。たとえば、ORMは不正なSQLを生成する可能性があります。余分なコーディングが多すぎる可能性があります。そのため、仕様にSQLを置くのとほとんど同じように、リポジトリメソッドを呼び出さなければならない場合があります。もちろん悪いことです。しかし、忘れないでください。プログラムは妥当な速度で動作する必要があります。DDDピュアプライズを獲得する必要はありません。したがって、データストアを切り替えるという現実は、プログラム全体で昔ながらの外科手術を意味する場合があります。また悪いことです。しかし、遅い(別名SUCKing)プログラムほど悪くはありません。さまざまなDBですぐに実行できることが現実である場合、明らかに、各仕様の各データストアのビジネスルールを複製することになります。少なくともあなたは問題にあなたの指を持っています、そしてあなたがリポジトリを交換するときあなたは戦略パターンを利用することができます。ただし、特定のDBを使用している場合は、YAGNI。

CQRSについて:上記のpdrによるFowlerの引用は、ここでも当てはまります。「コマンドとクエリに同じ概念モデルを使用すると、どちらもうまく機能しないより複雑なモデルにつながる」 ...そして、CQRSなどを使用する必要がある場合があります。しかし、それは開発と保守の観点からははるかに高価です。あなたが他の人と競争しているパッケージベンダーであるなら、それは支払うかもしれません。1人の顧客向けにカスタムLOBアプリを作成している場合、完璧を狙って撮影することはお勧めできません完全に、またはほぼ二重のモデルを持つことの価値が、追加の努力に値するかどうかを判断する必要があります。仕様これは、1つのモデルの(開発)速度とシンプルさで、必要なプログラムのほんの一部でこの分離を行うことができるため、適切な妥協案です。幸運を!


それは完全に理にかなっています。私は弾丸をかじってエヴァンスの本を読む必要があると思います:-)これらの概念を浅く理解することであなたは本当にあなたを麻痺させることができるようになりました!
drogon

0

isExpiredがtrueであるかどうかを決定するビジネスロジックは何か疑問に思うでしょう。このロジックは、データモデルが存在するときにクエリによって実行できますか?もしそうなら、特定の方法で製品を要求するときに「isExpired」ロジックを使用するのに十分にインテリジェントなリポジトリを作成できますか?そうでない場合は、おそらくデータモデルを再検討する必要があります。

DDDは、リポジトリが愚かである必要があることを意味するのではなく、ドメインがリポジトリと対話する方法を知る必要があることを意味します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.