TODOアプリケーションを設計しているため、Task
という集約ルートがあるとします。企業は、時間の経過に伴うタスクの変化の履歴を提供するTaskLogEvent
のリストを保持する必要があります。 Task
には数百のこれらのイベントが含まれる可能性があるため、このTaskLogEvent
を個別の集約ルートとしてモデル化します(これらの要素を毎回ロードする必要はなく、遅延ロードメカニズムも使用していません) )。
ここで、task.complete()
またはTask
を変更するその他の操作を実行したいときはいつでも、新しいTaskLogEvent
を作成します。私にはこれらのオプションがあります:
Task
にすべての変更を加えるドメインサービスを設計し、イベントを作成します。 Task
とのすべての通信は、このサービスを通過する必要があります。TaskLogEventRepository
をTask
の任意のメソッドに渡し、Task
自体がイベントを作成してリポジトリに保存できるようにします。この状況に対する理想的な解決策は何でしょうか?私の思考プロセスのどこでミスをしましたか?
TaskLog
を別個の集約として作成するというあなたの推論は正しく、理にかなっています。
イベントを発生させる責任はビジネスロジックにあるため、一応オプション1が最良の選択です。とにかく、DDDに従って、タスクアプリケーションサービス、タスク集約、およびタスクリポジトリを使用すると、このコード構造に近づきます。
しかし、これは出発点です。TaskLogRepository
Task
集計の一部として:
TaskUpdatedEvent
の作成/変更操作が正常に完了した後、タスクアグリゲートからDomain Event
(たとえば、Task
)としてイベントをバブルアップする必要があります。TaskLogRepository
までイベントを永続化することになります)。さらに一歩:規範的なイベント
これらのイベントをメカニズムとして使用して、タスク集計に変更を加えることができます。説明させてください。
タスク集計の変更に影響を与え、トランザクションの後にイベントを生成すると、イベントは記述イベントになり、何が起こったのかに関する情報が含まれます。記述的イベントでは、各変更の2つの表現があるため、それらは異なる可能性があります。
代わりに、規範イベントは、タスクの変更を有効にするためにトリガーするイベントです。トランザクションの一部としてのみイベントを生成し、サブスクライバーはタスク集約を変更する必要があります。この場合の表現は1つだけであり、保存されたイベントと影響を受けた変更の間の同期は良好です。
参考文献:
さらに一歩:Event Sourcing
イベントソーシングメカニズムを使用して、イベントからリアルタイムでTask
集計を作成できます。このアプローチでは、タスクの変更履歴とタスクの現在の表現との間で100%の同期が取れます。
メカニズムとしてのイベントソーシング自体は、ある程度の理解と実験を必要とするため、情報に基づいた呼び出しを行う必要があります。それについて読んでください。しかし、それが実際に必要であることがわからない限り、実装しないでください。
参考文献:
システムとその目標をより包括的に理解しないと、「理想的な」ソリューションがどのように見えるかを正確に推測することは困難ですが、上記のいずれについても論じません。
十分な考慮を払わずに、最も単純なオプション(インターリーブの量が最も少ないオプション)を除外した可能性があります。
単一のTask
集合体を保持することは、TaskLogEvent
が構築されるたびに、過去のすべてのTask
を必ずしもロードする必要はありません。たとえば、Task
をロード、変更、保存するたびに、新しく作成されたイベントのみを記録して永続化できます。これにより、ドメインイベント/ハンドラーを接続するために必要な要件を追加するよりもはるかシンプルなシステムになります(これはis完全に実行可能なオプションです)。
さらに、TaskLogEvent
はエンティティにとって非常に良い候補ではない(変更できるか?)と主張しますが、これは個別の議論であり、当面の質問に完全に関連しているわけではありません。
作成パターンはweird
この使用例では、twoを変更していることに注意してください。 Task
集計自体、およびTaskLogEvents
のコレクション/リポジトリ/ストリーム。
20年前、「the」データベースが一部のRDBMSを意味していたとき、これらは両方とも同じデータベーストランザクションの一部として記述されていました。トランザクション自体を管理するのはアプリケーション層の責任です。 Task
からTaskLogEvent
にデータをコピーするロジックは、集計に含まれます。そのデータは単にTaskLogEvent
コンストラクターを呼び出すか、ファクトリーを使用する場合があります。アプリケーション層は、イベントの集約を照会し、それらを「リポジトリー」に保管する責任があります。
たとえば、Udi Dahan 分散トランザクションなしの信頼性のあるメッセージング 、またはPat Helland 外部のデータと内部のデータを参照してください。
集計とイベントがdifferentの場所に書き込まれている場合、状況はさらに複雑になります。まず、アプリケーションサービスが管理する2つのトランザクションがあり、最初のトランザクションがコミットされた後の障害の影響について心配する必要があります。それ以外の点では、最初のケースとそれほど変わりません。すべてが簡単なユニバースで機能するメモリ内ドメインモデルと、ドメインモデルの指導の下でストレージプロトコルを調整するアプリケーションがあります。
テストによって導かれる成長するオブジェクト指向ソフトウェアを調べたなら、この分離はおなじみのものであるはずです。それを行う方法を知っている依存関係の束と話し合うことを知っているメモリ内の脳。
リストされている3つの選択肢の中で、Cは時間をかけて作業するのがはるかに簡単です。パーツをより明確に分離できるからです。ドメインモデルは、「トランザクション」の概念が存在しない、I/Oの副作用がモデルコードを通過しないなど、他の環境(テストなど)に簡単に引き上げることができます。
しかし、記憶の中ですべてを行うことができ、粘り強さを後から考えることができるという幻想ほど、魅惑的ではありません。