私は DDD の初心者であり、適切なドメイン層の恩恵を受けるレガシー プロジェクトを持っています。複数のアプリケーションおよび UI レイヤーをサポートするには、アプリケーションを変更する必要があります。ドメイン ロジックは、現時点ではトランザクション スクリプト パターンを使用して実装されています。基本的に、変更が許可されていない DB 構造を継承しました。新しいアプリケーションは、古いアプリケーションの代わりにドロップインする必要があります。
ドメインのごく一部で興味深いモデリングの問題を見つけました。これは、経験豊富な DDD 実践者にとって興味深いものであると確信しています。問題についてあまり具体的に説明することはできないので、私の問題とほぼ一致する問題について説明します。
問題の説明
製品のコレクションを管理する必要があるとしましょう。製品は ID で識別され、説明が含まれており、すべての製品にはいくつかの画像が関連付けられています。ここがトリッキーな部分です。画像とそのコンテンツは DB に物理的に格納されるため、データの巨大なチャンクです。(DBに画像を保存することの良し悪しは無視しましょう。これは単なる例です)。製品を追加/編集/削除する際に強制する必要のある不変条件がいくつかあります。
商品を追加する
- 商品は、画像が関連付けられている場合にのみ有効です。画像を追加せずに新しい商品を入力することはできません。
- すべての商品は、正確に 5 つの画像に関連付けられている必要があります。
- 商品に関連付けられた画像の順序を維持する必要があります
商品の編集
- 既存の製品の画像は置き換えることができますが、関連する画像の数と順序は維持する必要があります
商品の削除
- 商品を削除する場合、関連するすべての画像も削除する必要があります
考慮された解決策
解決策 1:
これらの概念をモデル化する最も簡単な方法は次のとおりです。商品はARです。製品に関連付けられた画像は、製品を通じてアクセスおよび変更できるため、製品は 5 つの画像ルールを実施する責任があります。このアプローチの利点は、無効な製品を作成または編集して無効にすることができず、製品が削除されたときに画像が残らないことです。したがって、集計はトランザクション境界の周りに形成されます。このアプローチの問題点は、ほとんどの場合、UI は製品のリストを表示するだけでよく、場合によっては製品の説明を変更する必要があることです。UI は、製品に関連付けられた画像を表示または変更する必要はほとんどありません。そのため、95% のケースで大量の不要なデータがメモリにロードされます。
遅延読み込み?ドメイン モデルは、遅延読み込みをサポートする ORM ツールを持たない言語で実装する必要があります。独自の遅延読み込みメカニズムを実装しますか? ドメイン オブジェクトは、永続化されている方法や、永続化されているかどうかをまったく認識しないようにする必要があります。代わりに、ソリューション 2 が Vaughn Vernon によって推奨されています。
解決策 2:
クエリのパフォーマンスの問題は、小さな集計を優先し、アイデンティティ ルールによる他の集計の参照に従うことで、このアプローチで解決できます。Vaughn Vernon は、これを達成する方法を説明するすばらしい一連の記事を書いています。
集合体は、Product と ImageSet の 2 つの部分に分割されます。どちらも ProductId を値オブジェクトとして参照しています。Product は no product without Images ルールを適用し、ImageSet は no ImageSet without 5 images ルールを適用します。クエリはもはや問題ではありません。ImageSet は、サービスで必要な場合にのみ取得されます。ただし、この問題は、Vernon が彼の記事 (0...N 関連付け) で説明したものよりもはるかに複雑です。問題は、Product の作成が 2 つの集計の変更または作成につながり、トランザクションの境界に沿って集計をモデル化する目的がなくなることです。新しい製品を追加するサービスは、トランザクション管理を担当します。
解決策 3:
最終的な解決策は、境界付けられたコンテキストを使用することです。簡単にするために、BC1 と BC2 と名前を付けます。BC1 では、Product には ProductDetails のみが含まれます。製品の詳細を照会し、おそらくそれらを変更することに関心のあるサービスは、BC1 を使用します (BC1 の ProductRepository は製品の追加または削除を許可せず、既存の製品の照会/変更のみを許可します)。BC2 では、製品には ProductDetails とそれに関連付けられた画像が含まれます。そのため、製品の追加/削除、および画像の変更/取得に関心のあるサービスは BC2 を使用します。共通の値のオブジェクトとエンティティは、これら 2 つの BC 間で共有されます。
このソリューションは、すべてのトランザクションの一貫性とクエリのパフォーマンスの問題を解決します。しかし、彼らの定義に基づいて、この種の問題に対応するために BC を作成する必要があるかどうかはわかりません。
長い質問で申し訳ありませんが、私がすでに検討した解決策の種類を指摘する必要があると思います。リンクされた画像で申し訳ありませんが、画像のアップロードはまだ許可されていません。