web-dev-qa-db-ja.com

DDD-別のアグリゲートを作成する1つのアグリゲートに対する操作

TODOアプリケーションを設計しているため、Taskという集約ルートがあるとします。企業は、時間の経過に伴うタスクの変化の履歴を提供するTaskLogEventのリストを保持する必要があります。 Taskには数百のこれらのイベントが含まれる可能性があるため、このTaskLogEventを個別の集約ルートとしてモデル化します(これらの要素を毎回ロードする必要はなく、遅延ロードメカニズムも使用していません) )。

ここで、task.complete()またはTaskを変更するその他の操作を実行したいときはいつでも、新しいTaskLogEventを作成します。私にはこれらのオプションがあります:

  1. Taskにすべての変更を加えるドメインサービスを設計し、イベントを作成します。 Taskとのすべての通信は、このサービスを通過する必要があります。
  2. TaskLogEventRepositoryTaskの任意のメソッドに渡し、Task自体がイベントを作成してリポジトリに保存できるようにします。
  3. アプリケーションサービスでこれを処理します。それは良い考えではないと思います。

この状況に対する理想的な解決策は何でしょうか?私の思考プロセスのどこでミスをしましたか?

2
Juraj Mlich

TaskLogを別個の集約として作成するというあなたの推論は正しく、理にかなっています。

イベントを発生させる責任はビジネスロジックにあるため、一応オプション1が最良の選択です。とにかく、DDDに従って、タスクアプリケーションサービス、タスク集約、およびタスクリポジトリを使用すると、このコード構造に近づきます。

しかし、これは出発点です。TaskLogRepositoryTask集計の一部として:

  • TaskUpdatedEventの作成/変更操作が正常に完了した後、タスクアグリゲートからDomain Event(たとえば、Task)としてイベントをバブルアップする必要があります。
  • 通常、イベントには包括的なペイロードが含まれているため、サブスクライバーはタスク集約を再度照会する必要がありません。
  • サブスクライバは反対側にいて、このイベントを待っています。イベントが発生すると、サブスクライバーはイベントを取得して、関連するアプリケーションサービスを起動します。次に、サービスはイベントペイロードを処理し、必要な処理を行います(この場合、タスクはTaskLogRepositoryまでイベントを永続化することになります)。
  • これらのイベントを処理する必要があるアプリケーションの他の部分がある場合、それらもこのイベントにサブスクライブしているはずです。ドメインイベントのpub-subメカニズムがブロードキャストと取得を処理します。

さらに一歩:規範的なイベント

これらのイベントをメカニズムとして使用して、タスク集計に変更を加えることができます。説明させてください。

タスク集計の変更に影響を与え、トランザクションの後にイベントを生成すると、イベントは記述イベントになり、何が起こったのかに関する情報が含まれます。記述的イベントでは、各変更の2つの表現があるため、それらは異なる可能性があります。

代わりに、規範イベントは、タスクの変更を有効にするためにトリガーするイベントです。トランザクションの一部としてのみイベントを生成し、サブスクライバーはタスク集約を変更する必要があります。この場合の表現は1つだけであり、保存されたイベントと影響を受けた変更の間の同期は良好です。

参考文献:


さらに一歩:Event Sourcing

イベントソーシングメカニズムを使用して、イベントからリアルタイムでTask集計を作成できます。このアプローチでは、タスクの変更履歴とタスクの現在の表現との間で100%の同期が取れます。

メカニズムとしてのイベントソーシング自体は、ある程度の理解と実験を必要とするため、情報に基づいた呼び出しを行う必要があります。それについて読んでください。しかし、それが実際に必要であることがわからない限り、実装しないでください。

参考文献:

1
Subhash Bhushan

システムとその目標をより包括的に理解しないと、「理想的な」ソリューションがどのように見えるかを正確に推測することは困難ですが、上記のいずれについても論じません。

十分な考慮を払わずに、最も単純なオプション(インターリーブの量が最も少ないオプション)を除外した可能性があります。

単一のTask集合体を保持することは、TaskLogEventが構築されるたびに、過去のすべてのTaskを必ずしもロードする必要はありません。たとえば、Taskをロード、変更、保存するたびに、新しく作成されたイベントのみを記録して永続化できます。これにより、ドメインイベント/ハンドラーを接続するために必要な要件を追加するよりもはるかシンプルなシステムになります(これはis完全に実行可能なオプションです)。

さらに、TaskLogEventはエンティティにとって非常に良い候補ではない(変更できるか?)と主張しますが、これは個別の議論であり、当面の質問に完全に関連しているわけではありません。

2
king-side-slide

作成パターンはweird

この使用例では、twoを変更していることに注意してください。 Task集計自体、およびTaskLogEventsのコレクション/リポジトリ/ストリーム。

20年前、「the」データベースが一部のRDBMSを意味していたとき、これらは両方とも同じデータベーストランザクションの一部として記述されていました。トランザクション自体を管理するのはアプリケーション層の責任です。 TaskからTaskLogEventにデータをコピーするロジックは、集計に含まれます。そのデータは単にTaskLogEventコンストラクターを呼び出すか、ファクトリーを使用する場合があります。アプリケーション層は、イベントの集約を照会し、それらを「リポジトリー」に保管する責任があります。

たとえば、Udi Dahan 分散トランザクションなしの信頼性のあるメッセージング 、またはPat Helland 外部のデータと内部のデータを参照してください。

集計とイベントがdifferentの場所に書き込まれている場合、状況はさらに複雑になります。まず、アプリケーションサービスが管理する2つのトランザクションがあり、最初のトランザクションがコミットされた後の障害の影響について心配する必要があります。それ以外の点では、最初のケースとそれほど変わりません。すべてが簡単なユニバースで機能するメモリ内ドメインモデルと、ドメインモデルの指導の下でストレージプロトコルを調整するアプリケーションがあります。

テストによって導かれる成長するオブジェクト指向ソフトウェアを調べたなら、この分離はおなじみのものであるはずです。それを行う方法を知っている依存関係の束と話し合うことを知っているメモリ内の脳。

リストされている3つの選択肢の中で、Cは時間をかけて作業するのがはるかに簡単です。パーツをより明確に分離できるからです。ドメインモデルは、「トランザクション」の概念が存在しない、I/Oの副作用がモデルコードを通過しないなど、他の環境(テストなど)に簡単に引き上げることができます。

しかし、記憶の中ですべてを行うことができ、粘り強さを後から考えることができるという幻想ほど、魅惑的ではありません。

2
VoiceOfUnreason