web-dev-qa-db-ja.com

同じコンセプトに複数の集合体はありますか?

ユーザーの概念があるとしましょう。実際には非常に基本的な構造です。たとえば、ソフトウェアのアスペクトが関連するすべての「投稿」を表示する必要があるとビジネスが要求する場合、それをどのようにモデル化する必要がありますか?

  1. Userエンティティの属性として投稿がある必要があります。つまり、たとえばログインを確認するだけでユーザーが要求されるたびに、その投稿をすべてロードする必要がありますか?
  2. 別の集合体を完全に使用する必要があります。この集合体は何と呼ばれるべきですか? UserWithPosts?関連データの属性がさらにある場合はどうなりますか?
  3. 集約ルートは、LoginUserと呼ばれる単純なEntityを備えたUserインターフェイスと、UserWithPosts、UserWithCommentsなどの追加機能のデコレータである必要があります。

シナリオ1を回避するためのより良いアプローチがどれであるかわかりません。

7
designermonkey

これには2つの部分があります。

データを変更しないユースケースの場合、アグリゲート全体をメモリにロードする必要はありません。そのため、ログインにはユーザーの1つの読み取り専用ビューを使用し、投稿を表示するには別の読み取り専用ビューを使用できます。

これは、リポジトリのさまざまなメソッドに対してどのように見えるかであり、それぞれが目的に合った読み取り専用ビューを返します。

modifyのユースケースでは、不変条件を維持するために必要なすべての状態が必要です。ただし、集計を表示するためのユースケースはそうではありません。

これはエバンスの本では説明されていません。それはそれ以来、より人気のあるテクニックです。

これの2番目の部分はモデリングの質問です-投稿のコレクションはユーザーに関連付けられていますか、それともそれ自体の集合ですか?これは、維持しようとしている不変条件に本当に依存します。

通常、1つのアグリゲートの状態に別のアグリゲートのidentifierが含まれるアグリゲート間に関係があることは許容されます。

4
VoiceOfUnreason

ドメイン主導の設計コンセプト、API設計、実装アプローチの間には混乱があるようです。

ドメイン設計の概念

最初に、EvanのDDDリファレンスブックのいくつかの定義:

  • Aggregate:データ変更の目的で1つの単位として扱われる関連オブジェクトのクラスター。外部参照は、ルートとして指定された集約の1つのメンバーに制限されます。

  • Entity:基本的には属性ではなく、連続性と同一性のスレッドによって定義されるオブジェクト。

また、これはドメインに関するものであることを覚えておいてください。ここでは、オブジェクト間の関係がどのように実装されるかは関係ありません。したがって、あなたが言うことから:

  • Userおよび関連するPostsは同じ集合体に属し、Userはそのルートエンティティです。これは、Postを参照したいときはいつでも、それが実装されていても、Userを介してアクセスする必要があることを示しています。
  • 集約内のPostエンティティであるか値オブジェクトであるかは明確ではありません。違いはアイデンティティのセマンティクスに関するものです。更新された投稿(タイプミスの修正など)は同じ投稿ですか、それとも別の投稿と見なされますか?個人的にはエンティティを選択しますが、ドメインに最適なものを確認するのはあなた次第です。

APIの設計と実装モデル

ドメインモデルは、特定の実装から独立しています。しかし、それを実装するには、以下を定義する必要があります。

  • モデルを使用するアプリケーションレイヤー(コントローラーやビューなど)にドメインを公開する方法を定義するAPI。
  • 実装アプローチ モデルの実装に依存する内部を管理するため。たとえば、永続性を保証するため(オブジェクトリレーショナルマッピングの使用やNOSQLデータベースの使用など)。

ドメインモデルは、パフォーマンスを阻害することを盲目的に行うように強制する刑務所ではなく、ソフトウェアをより適切に構成するためのガイドです。

特定のケースでは、たとえば lazy loading を使用できます。APIは、すべてがUserで一度に読み込まれるような印象を与える可能性がありますが、実際にはpostsは、誰かがUserを介してアクセスしようとするまで読み込まれません(カプセル化のおかげです)。

ただし、集計内のエンティティに直接アクセスできるように見えるAPIを定義することもできますが、Postへのアクセスを強制してUserを経由するため、保護する機会があります関連オブジェクトの整合性。

また、ご自分の言うとおり、アプリケーションに異なる種類のUserオブジェクトを作成して、何をロードし、何を変更できるかを判断することもできます。しかし、それは実装モデルであり、もはや概念的なドメインモデルではありません。

3
Christophe

(1)については、私は仕方がないと言います!特に他のデータベースオブジェクトが必ずしも必要ではないことを考えると、ユーザーをフェッチするたびに一連のデータベースオブジェクトを読み取る必要はありません。方法(1)は、多くのパフォーマンス問題の根本的な原因です。私の理解では、Hibernateは方法(1)を選択するのが非常に簡単であること、そしてそれがSQLクエリを手動で書くことを好む理由の1つです。

私のアプローチは(2)です。同じ基本オブジェクトに対して、さまざまな不変の「ビュー」(データベースビューではない!)を作成します。ベースデータベーステーブルを他のさまざまなテーブルに結合するビューは3〜5個まで存在できます。これらのビューオブジェクトは変更されません。すべてのデータベース変更は、ベースオブジェクトを介して行われます。

私は通常、アプリケーション自体にすべてのロジックを保持しようとするため、これらのアプリケーションレベルのビューがあっても、実際にCREATE VIEW SQLコマンドを使用することはありません。率直に言って、データベースレベルのビューの目的がわかりません。彼らはアプリケーションで行われるべき何かを行います。

使用するプログラミング言語がJavaの場合、クラスUserと内部クラスUser.WithPostsを使用できます。内部クラスは非常に簡単なので、内部クラスとして持つことは理にかなっています。また、内部クラスにする習慣に従うと、関連するビューの場所を簡単に見つけることができます。私はこれらの内部クラスをstaticにするので、UserなしでUser.WithPostsを使用できます。

1
juhist