ドメイン駆動設計とクロスドメイン相互作用


10

私は比較的DDDの初心者ですが、知識を沸騰させて蒸留するために手に入れることができるあらゆるものを読んでいます。

私はこのDDDの質問に出くわし、その答えの1つに興味をそそられました。

DDDバウンドコンテキストとドメイン?

回答の1つで、ポスターは、製品が少なくとも2つのドメインにあるeコマースシステムの例を示しています。

1)製品カタログ2)在庫管理

わかりました。つまり、eコマースのフロントエンドでは、商品情報の表示に関心があり、在庫管理には関心がありません。

だが。Webページに在庫レベルを表示したり、在庫のエディション番号を表示したりすることができます(在庫が本、雑誌などであるとします)。この情報は、インベントリドメインから取得されます。

それで、これをどのように処理しますか?あなたは

a)製品ドメインと在庫ドメインの両方の集合体をロードしますか?b)在庫数と在庫数の製品ドメインエンティティの一部のプロパティを保持し、在庫エンティティが更新されたときにドメインイベントを使用してこれらを更新しますか?

最後の質問です。私たちはドメインの永続性を忘れ/無視し、ドメインについて考えることを意図していることを知っています。しかし、これをよく考えてみると、上の例では、製品カタログと製品在庫用に2つのDBテーブルが存在する可能性があります。これらは同じ製品なので、同じ識別子を使用しますか?または、データに1つのテーブルと1つのテーブル行を使用して、関連するデータを集計プロパティに単純にマップできますか?

回答:


8

Webページに在庫レベルを表示したり、在庫のエディション番号を表示したりすることができます(在庫が本、雑誌などであるとします)。この情報は、インベントリドメインから取得されます。

この時点で気づく主なことは、ビューについて話しているということです。つまり、古いデータの使用は許容されます。

とはいえ、アグリゲート(変更がビジネスインバリアントに違反しないようにする責任がある)と対話する必要はありませんが、アグリゲートの状態の最新のコピーを表示する必要があります。

したがって、私が通常期待するのは、製品カタログに対して実行されるクエリと、在庫に対して実行されるクエリであり、ビューをサポートするために2つをDTOに構成するものです。

製品ドメインと在庫ドメインの両方の集合体をロードしますか?

これで終わりです。何も変更しないので、アグリゲートをロードする必要はありません。しかし、私たちは彼らの状態を必要としています。それをロードすることができました。そうは言っても、私は通常、2つのドメインが異なるプロセスで実行されていることを期待します。したがって、両方をロードするのではなく、両方を呼び出すことになります。

在庫数と在庫数の製品ドメインエンティティのプロパティをいくつか保持し、在庫エンティティが更新されたときにドメインイベントを使用してこれらを更新しますか?

「小川を渡らないでください。それは悪いことです。」

イベントを使用してドメインコンテキスト全体で情報を調整する:素晴らしいアイデアです。あるドメインに属している概念を別のドメインにプッシュすること:それ以上のことを除いて、素晴らしいアイデアの反対。

ドメインをクリーンに保ちたい。アプリケーション相互作用ドメインと、それはそれほど重要ではありません。したがって、たとえば、Inventoryアプリケーションが製品アプリケーションのサービスを呼び出して、ビューに追加する製品固有の概念を照会することは妥当です。またはその逆。

単一のアプリケーションを単一のドメインに制限する必要がある理由はわかりません。真実の情報源が1つである限り、トランザクションを好きなように配布できます。

しかし、これをよく考えてみると、上の例では、製品カタログと製品在庫用に2つのDBテーブルが存在する可能性があります。これらは同じ製品なので、同じ識別子を使用しますか?

それは簡単な方法でしょう。大まかに言うと、実世界のエンティティは同じなので、同じ識別子を使用します。2つの異なる境界コンテキストはそのエンティティを異なる方法でモデル化しますが、モデルは実際のエンティティではありません。

それが機能しない場合、ギャップを埋めるために使用するクエリが必要になります。これの最も一般的なバリエーションは、新しいエンティティが古いエンティティのIDを保持することです。これは、単一のBC内でも確認できます。申請者は、承認されるとクライアントになります。それは別の集計です(クライアントに関連付けられた状態は、申請者の状態とは異なる不変条件の対象となります)。そのため、永続化レイヤーがイベントストリームを使用している場合、新しい集約のストリームには別の識別子が必要になります。したがって、「この申請者はこのクライアントになった」と言う状態がどこかにあるでしょう。

または、データに1つのテーブルと1つのテーブル行を使用して、関連するデータを集計プロパティに単純にマップできますか?

うわぁ! いいえ、それをしないでください。ビジネス上の理由なくトランザクションの競合を追加している。


私はこれを答えとしてチェックしました。ビューに表示するデータを読み取るには集計をロードする必要がないことも指摘した以下の@guillaumeにも感謝します。このような長く詳細な回答をありがとう。「伝統的な」データモデルの最初のアプローチから来て、永続層を忘れてドメイン言語に集中することを自分に強いることは難しいことに気づきました。理解できたと思ったときに、理解を混乱させる別の記事を読みました。
PendorPaul 2016

ドメインイベントを使用してコンテキスト間で一部のデータを複製する詳細については、この記事msdn.microsoft.com/en-us/magazine/dn802601.aspxを読んだだけです。カスタマーサービスと注文処理システムの間で顧客リストを共有する例。これは注文システムで顧客データを複製し、イベントを使用してデータを同期しています。これは、私たちがここで回答したことに直面して飛びます。確かにリンクされたサンプルでは、​​注文コンテキストはcustomerIDを必要とし、それは顧客サービスコンテキストにアクセスできるアプリケーションから入力できます。
PendorPaul 2016

あなたはここであなたの考えを非常に正確にしたいと思うでしょう。システム間でのデータのコピーは、ドメインモデル間でのデータのコピーとは異なります。「read only [mumble]」が表示された場合は常に、データがそのドメインに属していないことが大きなヒントになります(アプリケーションがまだそれを気にしている場合でも)。
VoiceOfUnreason 2016

はい、私もそう思いました。水を濁らせる記事を「専門家」が公開しない限り、思考プロセスの変化は十分に困難です。私は今日、私のドメインを実際に分析して、私のBCとAggregate Rootsがどこにあるのかを十分に理解するために費やしました。私はほとんどそこにいますが、モデルを改良してリファクタリングできることもわかっています。私は何日も分析の地獄に巻き込まれており、頭の中にDDDがないのではないかと恐れて、コードを書き始めようと心配しています。私はクラックして、私のコードに質問し続け、モデルが正しいかどうかを確認するのが最善だと思います。そこに着きます。ありがとう
PendorPaul 2016

多分私は誤解しているかもしれませんが、私があなたが話していると私が信じている慣習はイベントキャリーステート転送(イベントキャリーステート転送)と呼ばれ、特にデータをフィルタリングしてページングする必要があるダッシュボード/テーブルビューにとって非常に強力なモデルになる可能性がありますサービス全体。ドメインイベントから「プロジェクション」(基本的にはビュー)を作成して、これらのダッシュボードを駆動できます。以前はかなりうまく使いました。これは、適切なシナリオでは非常に強力なツールになる可能性があります。ここで重要なのは、これらの予測はドメインモデルを表すものではなく、ビジネスロジックを含むべきではないことを理解していることです。
ジョーダン

3

あなたの質問では、2つの直交するオプションのセットが本当に必要だと思います-

  • 2つのオブジェクトをロードしてそれらのデータを一緒に表示しますか、それとも必要なすべてを含む1つのオブジェクトをロードしますか?

  • 集合体を使って何かを表示していますか?

CQRSのアプローチを信じている場合、集計は読み取りに最適ではない可能性があることがわかります。アグリゲートをロードするたびに、そのデータを表示するか変更するかに関係なく、システムに同時実行性と競合を追加します。また、アグリゲートは、表示用に調整されたアドホックな読み取りモデルを使用する場合よりも、かさばってロードが遅くなる可能性があります。

解決策a)Qから、これらの多くの落とし穴の影響を受けるようです。オプションb)は有効ですがInventoryManagementProduct集約を変更するときに不変条件を適用するためにBC からのデータが必要な場合にのみ使用します。アグリゲートには、変更時にビジネスルールをチェックするために必要なすべてのデータが含まれている方が良いですが、読み取り側ではどこにでも置くことができます。

データに関して、一般的な推奨事項は、バインドされたコンテキストに独自のデータベースを提供することです(展開性とSoCの理由から)。2つのBC間で製品を一致させる場合は、おそらく同じ識別子を使用する必要があります。

BC間の相互作用については、https://stackoverflow.com/questions/16713041/communicating-between-two-bounded-contexts-in-dddもご覧ください。


1
OK、それが役立ちます。本質的には、アグリゲートルートとBCを使用して不変条件の一貫性を確保し、データが有効であり、実行する操作がアグリゲートまたはBC内にラップされます。そのデータの読み取りと表示に関しては、すべてのアグリゲート/ BCをハイドレートすることなく、個別に軽量に処理できます。結局のところ、データをレポートまたは画面に表示するだけのときに、Aggregateを読み込む必要があるのはなぜですか。これは完全に理にかなっています。ありがとう。
PendorPaul 2016

これは、CQRSが本当に優れている点です。SQLクエリを実行してテーブルを結合し、特定のビューに合わせたクエリを返すだけです。また、クエリメソッドの混乱からリポジトリをクリアします。また、ElasticSearchなどのサービスでデータを複製し、それに対してクエリを実行することもできます。
doesnotmatter

1

DDDは、ビジネスロジックが複雑なアプリケーション向けです。「何かを印刷する」ことは、複雑なビジネスロジックではありません。実際にはビジネスロジックではありません。

1つのコンテキストのビジネスロジックが、いくつかのユースケースを適切に処理するために何らかの情報を必要とする場合、その情報はそのコンテキストの一部です。したがって、1つの境界コンテキストが、異なる境界コンテキストで利用可能な情報を必要とするかもしれないという考えは、意味がありません。境界コンテキストには必要なすべての情報があるからです。


それでは、Amazonのようなものを取り上げてください。これは、複雑なビジネスロジックを備えた複雑なシステムです。彼らはカタログ管理と在庫管理を持っています。彼らはカタログを管理するために在庫の合計を必要としません。つまり、製品名、説明、タイプ、状態などを意味します。しかし、彼らは彼らのストアのフロントページに在庫数を示しています。商品カタログ管理ドメインと商品在庫ドメインを分離したいが、商品ページに在庫に関する情報を表示する必要があるシナリオでは、どのように行いますか?
PendorPaul 2016

私が言っているのは、製品カタログドメインには、製品カタログを管理するために必要なすべての情報があるということです。インベントリドメインには、インベントリを管理するために必要なすべての情報があります。ただし、ユーザーにいくつかの情報を表示したい場合、そのデータは2つのドメインから取得されます。UIに両方のドメインをロードして、表示するプロパティをバインドするだけですか?または、UIに必要なデータを含む匿名タイプまたはDTOを返すレポート/読み取りメカニズムがありますか?
PendorPaul 2016

11か月前の私の古いコメントを振り返ってみると、それはコミカルですが、生涯のように思えます。私が取り組んでいるアプリケーションは、理解が進むにつれてかなり進化しました。私は現在、Jimmy Bogards Mediatrを通じてCQRSメソッドを使用しています。Aggregatesとやり取りするコマンドを用意し、クエリとクエリハンドラーを使用して表示に必要なものをすべて戻すという非常に高い柔軟性は信じられないほどです。それらを、それらのQueryHandlerを呼び出すビューにラップします。これにより、デカップリングがうまくいきます。ありがとう
PendorPaul 2016

@PendorPaul、私はあなたが11(現在は13)か月前だった場所だと思います。今どこにいるのですか?
グレッグベル

1
@GregBellマインドセットの変更を強制する必要があります。「データベースの設計、データ層の構築、ビジネスロジックの構築など」というアプローチに行き詰まりました。そして、私はすべての包含エンティティを作成することに集中しました。つまり、価格、説明、在庫、在庫場所などすべてを処理するeコマースサイトの「製品」ですが、それは非常に複雑になります。境界コンテキストアプローチとは、在庫コンテキストでは、「製品」には在庫管理の情報と動作のみが含まれることを意味します。説明と画像はコンテンツコンテキストで管理され、価格設定は価格設定コンテキストで行われます。
PendorPaul 2017年

1

私の見解では、「製品」にはさまざまな定義があります。すべての境界コンテキストには、「製品」ドメインの独自の定義がありません。

  • Content-Management-Bounding-Contextでは、製品には画像と説明テキストがあります。
  • Inventory-Bounding-Contextでは、製品には在庫数量、製品販売者、製品が入手可能になる時期の予測があります。
  • Price-Caculation-Bounding-Contextには、製品が数量ごとにいくらかかるかというルールがあります。

これらの上に、独自の製品定義(他の境界コンテキストの製品ドメインの関連する組み合わせ)を持つ追加のショップ境界コンテキストを追加します。

Shop-Productには、「在庫」からのコンテンツと在庫状況からの「画像と説明テキスト」がありますが、在庫からの「製品販売者」はありません。

この追加のShop-Bounding-Contextは、Bounding-Context-sのコンテンツ、在庫、価格によって異なります


では、そのShop-Product BCをどのように作成していますか?そのコンテキスト内でProductとInventory BCへの参照があり、Store-Product BCをロードするときに永続ストアからそれらをハイドレートし、StoreProductプロパティを通じてこれらのBCから必要なプロパティを提供していますか?私が実際に考えていた、BCイベントを横断するこの記事に沿ったこの記事を見つけましたが、上記の@ guillaume13は、表示の目的でBCを回避し、自分のビューに必要なデータを取り戻すことができることを指摘しました。msdn.microsoft.com/en-us/magazine/dn802601.aspx
PendorPaul 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.