web-dev-qa-db-ja.com

どちらが最初に来る:イベントまたは変更?

私はEvent Sourcingを調査してきましたが、私が読んだものには2つの哲学が隠されているようです。中心的な違いは、システムのアクターがproactiveであるかどうか、最初に変更を行い、彼らが行ったことに基づいてイベントを発行するか、reactive、イベントを消費し、それらのイベントに基づいてデータを更新します。

ただし、前者は実際にはイベントSourcingではありませんよね?イベントは変更のソースではなく、単なる変更の記録です。これは単なるイベントベースのlogであり、後でデータを再構築するために使用できます。ログを再構築するときは、最初に実行したときとは異なるコードを使用しています。元の実行では、2回目にsendイベントreadを送信します。さらに、実際にこれらの変更をトリガーするコマンドを導入する必要があります。これらの変更は、コンシューマーに直接送信する必要があり、より緊密なバインディングを引き起こします。

一方、「反応型」のスタイルは、これらすべての懸念を覆します。すべての変更はイベントへの反応であるため、「ライブ」システムをチャーンするときに聞くことと、後でリプレイを聞くこととの間に基本的に違いはありません。サービスには何をすべきかが指示されないため、明示的な「コマンド」は必要ありません。むしろ、他の場所で発生したイベントに直面して一貫性を維持し、他の人に自分のイベントを通知する責任があります。これの裏側は、制御の反転です。他のサービス/集約について知るのではなく、それらに何をすべきかを伝えることができます、システムにイベントをブロードキャストして、彼らは彼らのルールに従って応答します。私が見る唯一の比較の欠点は、oldメッセージを再生するときにnewメッセージを明示的に無視する必要があることですが、これは構成/フラグ。

それでも、多くのガイドや製品は積極的なスタイルを推奨しているようです。たとえば、 Event Store は、イベントがtargetに基づいてストリームに分割されることを期待します-つまり、これを単一の指定されたターゲットに送信する(これにより、名誉あるコマンドになります)OR「ターゲット」は、実際には、実行したアクションの記録を作成するソースにすぎないためです。

私の理解にはギャップがあるに違いありませんが、1週間ほど読んだ後、これについて十分にサポートされた説明に出くわしませんでした。私はこれから2つの質問が出てくると思います:

  1. これら2つのアプローチのどちらが本当にイベントソーシングですか?
  2. ここで言及しなかった事後対応型のアプローチに比べて、プロアクティブ型のアプローチにはメリットがありますか?
28
TheRubberDuck

注意:混乱しているのはあなたの責任ではありません。文献sucks

これら2つのアプローチのどちらが本当にイベントソーシングですか?

「イベントソース」とは、イベントストア、Eventideプロジェクトなどで話されているように、状態をイベントの履歴として保存することを意味します。イベントストアは、履歴を記憶するために通常使用するRDBMSを置き換えます。イベントストアで表される履歴は、エンティティが時間の経過とともにどのように変化したかを説明する、追加のみのイベントシーケンスです。

ログを再構築するときは、最初に実行したときとは異なるコードを使用しています。最初の実行では、2回目に読んだイベントを送信します。

リレーショナルの世界で私たちが物事を行う方法とは大きく異なりますが、そうではありません。

O/RMの世界では、自分がどこにいるかをどのように覚えていますか?通常、新しい情報が到着すると、データベースから独自のメモリをロードし、新しい情報を統合して、新しいメモリをデータベースに格納します(古いものを置き換える)。古いメモリがロードされ、新しいメモリが計算されます。新しいメモリを保存し、次に必要になったときにそのメモリがロードされます。

イベントソーシングでは、この基本的なプロトコルは変更されていません。大きな違いは、古いメモリを置き換えるのではなく、新しい変更を追加することです。

Pat Hellandの用語では、イベントソースは約 内部のデータ ;です。過去のドメインモデルが将来の「同じ」ドメインモデルと情報を共有する方法。

「リアクティブ」スタイルはこれらすべての懸念を覆します...サービスは何をすべきかを指示されないので、明示的な「コマンド」の必要はありません

心配する価値のある違いではありません。メッセージが到着し、ドメインモデルが変更され、メッセージが出発します。これらのメッセージにコマンドまたはイベントとしてラベルを付けるかどうかは、それほど重要ではありません

  • handle(Event)はコマンドです
  • CommandReceivedはイベント

権限(コマンド)に向かってファンインするメッセージと、権限(イベント)からファンアウトするメッセージを区別するために意味上の違いを導入できますが、ドメインの観点からは、興味深いビットはメッセージに含まれる情報であり、その情報に応じてドメインモデルがどのように変化するかではなく、どのpatternではなく、メッセージに最も適していると考えます。

これらすべてに役立つ可能性のあるアイデアの1つは、イベントソーシングはドメインモデリングの伝統に由来することを覚えておくことです。つまり、独自のプライベートデータを持つ多くの小さなステートマシンを管理して、現在の状態を追跡しています。彼らが次にあるべき状態を計算するための彼ら自身のドメインロジック。 「教えて、聞かないで」と考えてください。ドメインモデルに新しい情報をフィードし、それによって現在の状態を決定します。

1つのサービスが別のサービスに何をすべきかを伝えますか、それとも最初のサービスは単にそれが何をしたかを通知し、2番目のサービスは反応しますか?

これがここでの主要な混乱です。これはコミュニケーションパターンに関する質問です。これは、データ表現パターンであるイベントソースとは関係ありません。

最も一般的な(または、少なくとも最も一般的に承認されている-別名「ベストプラクティス」)は、サービスが0以上のサブスクライバーと情報を共有することです。つまり、メッセージはファンアウトです。ソースサービスはメッセージを発行し、サブスクライバーはメッセージに反応するかしないかを判断します。

(ここでの主な利点は、ソースサービスの新しいコピーをデプロイせずにサブスクライバーを追加/削除できることです)。

サービス間の情報交換のメカニズムは、情報の配置withinとは別の問題(別の 設計決定 )ですaサービス。

21
VoiceOfUnreason

たぶん axoniq.io/ のアプローチを見ると、いくつかの光が出るでしょうか?私はそれがとても好きで、あなたの定義によればこれはreactiveになると思います。

Axonフレームワークには、CommandHandlersとEventHandlersがあります。

CommandHandler注釈付きメソッドはコマンドを受け取り、集約の不変式(ddd:状態を保持していないオブジェクトを簡略化する)を強制します。したがって、たとえば、同じ投稿を2回好きになれない場合に、コマンドを拒否する可能性がある場所です。ここでは、コマンドを受け入れる場合に適切なイベントも作成します。

一方、EventHandlerアノテーション付きメソッドは、イベントのみを受け取り(イベントを拒否することはできません)、受信時にオブジェクトの状態を変更し、変更を適用します。

個人的には、reactiveアプローチが適切であり、次の理由から私にはより理にかなっているように思われる傾向があります。

  1. 「状態を変更したが、アプリケーションがクラッシュし、イベントを永続化しなかった場合はどうなりますか?」という問題を解決します。アプリケーションの状態はイベントから分岐します。代わりに:最初にイベントを永続化し、次に状態を変更します(正常に保存された後)
  2. コマンドとイベントを別々にすると、イベントを簡単に再生できます。これは、たとえば、受け入れられたコマンドでメールを送信します。アプリケーションの状態を復元してイベントを適用するたびにメールを送信する必要はありません。
1
user3681304

あなたの最初の質問について:私の理解は、イベントソーシングのアイデアは、それをもたらした[関連ドメイン]イベントのシーケンスから状態を再現できるようにすることであるということです。したがって、イベントは、将来の再構築された状態のsourceを形成します。プロアクティブまたはリアクティブスタイルは、そのような定義に関連していないようです。

2つのアプローチの利点について、2番目の質問の見方を共有します。

境界付きコンテキストが通信する方法を少し考えてみましょう。可視性(誰が誰を知っているか)は重要です。ここでは、対照的な意味を持つ2つの一般的な方法を示します。

  1. BC1はBC2を直接呼び出します。

    • BC2はAPIを定義し、その制約を保護しますが、だれがそれを呼び出すかは気にしません。
    • BC1はBC2とそのAPIを知っており、それを実行することができます。
  2. BC1はイベントをブロードキャストします。 BC2とBC3がそのイベントに作用します。

    • BC2とBC3はBC1の知識を持ち、そのイベントに対処するために独自の選択を行います。
    • BC1はイベントを定義し、該当する場合はブロードキャストしますが、誰が関心を持っているかは関係ありません。

上記のそれぞれについて、そのアプローチが最も理にかなった例を思いつくのは非常に簡単です。

プロトコルbetween境界コンテキストに関しては、これらのオプションはかなり確立されていると思います。ただし、概念はドメインモデルにも適用されますwithin。おもしろいことに、これらはあなたが言及しているプロアクティブスタイルとリアクティブスタイルにそれぞれ一致します。

  1. DomainObject1は、DomainObject2でコマンドを呼び出します。

    • DomainObject2はコマンドを定義し、その制約を保護しますが、誰がそれを呼び出すかは気にしません。
    • DomainObject1はDomainObject2の知識を持ち、それを実行することができます。
    • これはproactiveスタイルです。
  2. DomainObject1はイベントをブロードキャストします。 DomainObject2とDomainObject3はそのイベントに作用します。

    • DomainObject2とDomainObject3はDomainObject1の知識を持ち、独自の選択を行ってそのイベントを処理します。
    • DomainObject1はイベントを定義し、該当する場合はブロードキャストしますが、誰が関心を持つかは関係ありません。
    • これはreactiveスタイルです。

どちらのスタイルも完璧な意味がありますね。モデルは次に何が起こるかを気にせずに、何が起こったのかを宣言したい場合があります。他の場合には、モデルは何かをするように指示されることを望み、どの状況がそれを正当化するかを気にしません。この違いは、責任についてであり、モデルにとって意味のある一連のカップリングを持っていることのようです。多くのモデルで、両方が表示されることを期待しています。

まとめとして、投稿のタイトルにある質問に答えてみましょう。

各イベントは何かによって引き起こされました。そのことは、たぶん、イベント自体として説明できます。ただし、通常は関連するドメインイベントのみに関心があります。コマンドをUserClickedButtonEventから発信されたものと見なしても意味がない場合があります。関連性のないイベントを無視して、各イベントを(潜在的にそれを引き起こした以前のイベントを通じて)追跡して、意図の宣言であるコマンドに戻すことができます。その観点から、意図の宣言が最初に来て、イベントが続きました。

0
Timo