ユーザーの概念があるとしましょう。実際には非常に基本的な構造です。たとえば、ソフトウェアのアスペクトが関連するすべての「投稿」を表示する必要があるとビジネスが要求する場合、それをどのようにモデル化する必要がありますか?
シナリオ1を回避するためのより良いアプローチがどれであるかわかりません。
これには2つの部分があります。
データを変更しないユースケースの場合、アグリゲート全体をメモリにロードする必要はありません。そのため、ログインにはユーザーの1つの読み取り専用ビューを使用し、投稿を表示するには別の読み取り専用ビューを使用できます。
これは、リポジトリのさまざまなメソッドに対してどのように見えるかであり、それぞれが目的に合った読み取り専用ビューを返します。
modifyのユースケースでは、不変条件を維持するために必要なすべての状態が必要です。ただし、集計を表示するためのユースケースはそうではありません。
これはエバンスの本では説明されていません。それはそれ以来、より人気のあるテクニックです。
これの2番目の部分はモデリングの質問です-投稿のコレクションはユーザーに関連付けられていますか、それともそれ自体の集合ですか?これは、維持しようとしている不変条件に本当に依存します。
通常、1つのアグリゲートの状態に別のアグリゲートのidentifierが含まれるアグリゲート間に関係があることは許容されます。
ドメイン主導の設計コンセプト、API設計、実装アプローチの間には混乱があるようです。
最初に、EvanのDDDリファレンスブックのいくつかの定義:
Aggregate:データ変更の目的で1つの単位として扱われる関連オブジェクトのクラスター。外部参照は、ルートとして指定された集約の1つのメンバーに制限されます。
Entity:基本的には属性ではなく、連続性と同一性のスレッドによって定義されるオブジェクト。
また、これはドメインに関するものであることを覚えておいてください。ここでは、オブジェクト間の関係がどのように実装されるかは関係ありません。したがって、あなたが言うことから:
User
および関連するPosts
は同じ集合体に属し、User
はそのルートエンティティです。これは、Post
を参照したいときはいつでも、それが実装されていても、User
を介してアクセスする必要があることを示しています。Post
がエンティティであるか値オブジェクトであるかは明確ではありません。違いはアイデンティティのセマンティクスに関するものです。更新された投稿(タイプミスの修正など)は同じ投稿ですか、それとも別の投稿と見なされますか?個人的にはエンティティを選択しますが、ドメインに最適なものを確認するのはあなた次第です。ドメインモデルは、特定の実装から独立しています。しかし、それを実装するには、以下を定義する必要があります。
ドメインモデルは、パフォーマンスを阻害することを盲目的に行うように強制する刑務所ではなく、ソフトウェアをより適切に構成するためのガイドです。
特定のケースでは、たとえば lazy loading を使用できます。APIは、すべてがUser
で一度に読み込まれるような印象を与える可能性がありますが、実際にはposts
は、誰かがUser
を介してアクセスしようとするまで読み込まれません(カプセル化のおかげです)。
ただし、集計内のエンティティに直接アクセスできるように見えるAPIを定義することもできますが、Post
へのアクセスを強制してUser
を経由するため、保護する機会があります関連オブジェクトの整合性。
また、ご自分の言うとおり、アプリケーションに異なる種類のUser
オブジェクトを作成して、何をロードし、何を変更できるかを判断することもできます。しかし、それは実装モデルであり、もはや概念的なドメインモデルではありません。
(1)については、私は仕方がないと言います!特に他のデータベースオブジェクトが必ずしも必要ではないことを考えると、ユーザーをフェッチするたびに一連のデータベースオブジェクトを読み取る必要はありません。方法(1)は、多くのパフォーマンス問題の根本的な原因です。私の理解では、Hibernateは方法(1)を選択するのが非常に簡単であること、そしてそれがSQLクエリを手動で書くことを好む理由の1つです。
私のアプローチは(2)です。同じ基本オブジェクトに対して、さまざまな不変の「ビュー」(データベースビューではない!)を作成します。ベースデータベーステーブルを他のさまざまなテーブルに結合するビューは3〜5個まで存在できます。これらのビューオブジェクトは変更されません。すべてのデータベース変更は、ベースオブジェクトを介して行われます。
私は通常、アプリケーション自体にすべてのロジックを保持しようとするため、これらのアプリケーションレベルのビューがあっても、実際にCREATE VIEW
SQLコマンドを使用することはありません。率直に言って、データベースレベルのビューの目的がわかりません。彼らはアプリケーションで行われるべき何かを行います。
使用するプログラミング言語がJavaの場合、クラスUser
と内部クラスUser.WithPosts
を使用できます。内部クラスは非常に簡単なので、内部クラスとして持つことは理にかなっています。また、内部クラスにする習慣に従うと、関連するビューの場所を簡単に見つけることができます。私はこれらの内部クラスをstatic
にするので、User
なしでUser.WithPosts
を使用できます。