イベントを強調するアーキテクチャのコマンドとイベントの違いは何ですか?私が見ることができる唯一の違いは、コマンドは通常、システム外のアクターによってソース/呼び出されるのに対し、イベントはシステム内のハンドラーやその他のコードによってソースされるように見えることです。しかし、私が見た多くのサンプルアプリケーションでは、それらは異なる(しかし機能的に類似した)インターフェースを持っています。
9 に答える
コマンドは拒否できます。
イベントが発生しました。
これがおそらく最も重要な理由です。イベント駆動型アーキテクチャでは、発生したイベントが何かが起こったことを表していることに疑問の余地はありません。
さて、コマンドは私たちがやりたいことであり、イベントは起こったことなので、これらに名前を付けるときは別の動詞を使用する必要があります。これにより、個別の表現が促進されます。
コマンドは通常、システム外のアクターによってソース/呼び出されますが、イベントはシステム内のハンドラーやその他のコードによってソースされているようです。
これは、それらが別々に表されるもう1つの理由です。概念の明確さ。
コマンドとイベントはどちらもメッセージです。ただし、これらは実際には別個の概念であり、概念は明示的にモデル化する必要があります。
イベントは過去からの事実です。
コマンドは単なる要求であるため、拒否される場合があります。
コマンドの重要な特徴は、単一のレシーバーによって1回だけ処理される必要があることです。これは、コマンドがアプリケーションで実行する単一のアクションまたはトランザクションであるためです。たとえば、同じ注文作成コマンドを複数回処理しないでください。これは、コマンドとイベントの重要な違いです。多くのシステムまたはマイクロサービスがイベントに関心を持っている可能性があるため、イベントは複数回処理される可能性があります。'msdn'
また、ここで公開されているすべての回答に加えて、イベントハンドラーは、イベントが発生したという通知を受信した後、コマンドをトリガーできる場合があります。
たとえば、Customerを作成した後、いくつかのアカウント値なども初期化するとします。CustomerARがEventDispatcherにイベントを追加し、これがCustomerCreatedEventHandlerオブジェクトによって受信された後、このハンドラーはコマンドのディスパッチをトリガーできます。必要なものは何でも実行します。
また、DomainEventsとApplicationEventsがあります。違いは単に概念的なものです。最初にすべてのドメインイベントをディスパッチする必要があります(一部のイベントはアプリケーションイベントを生成する場合があります)。これはどういう意味ですか?
CustomerCreatedEventが発生した後にアカウントを初期化することは、DOMAINイベントです。お客様に電子メール通知を送信することは、アプリケーションイベントです。
それらを混ぜてはいけない理由は明らかです。SMTPサーバーが一時的にダウンしている場合でも、ドメイン操作がその影響を受ける必要があるという意味ではありません。それでも、アグリゲートの破損していない状態を維持する必要があります。
私は通常、アグリゲートルートレベルでディスパッチャにイベントを追加します。このイベントは、DomainEventsまたはApplicationEventsのいずれかです。両方である可能性があり、それらの多くである可能性があります。コマンドハンドラーが完了し、コマンドハンドラーを実行するコードにスタックに戻ったら、ディスパッチャーをチェックして、他のDomainEventをディスパッチします。これがすべて成功したら、トランザクションを閉じます。
アプリケーションイベントがある場合は、それをディスパッチするときです。電子メールを送信するために、データベースへの接続を開いたり、トランザクションスコープを開いたりする必要はありません。
元の質問から少し外れましたが、イベントが概念的にどのように異なる方法で処理されるかを理解することも重要です。
それからあなたはSagasを持っています....しかしそれはこの質問の範囲から外れています:)
それは意味がありますか?
いくつかの例、特にGreg Youngのプレゼンテーション(http://www.youtube.com/watch?v=JHGkaShoyNs)を実行した後、コマンドは冗長であるという結論に達しました。それらは単にユーザーからのイベントであり、そのボタンを押しました。これらはデータであり、将来のビューで使用するかどうかわからないため、他のイベントとまったく同じ方法で保存する必要があります。ユーザーがそのアイテムを追加してから後でバスケットから削除するか、少なくともしようとしました。後でこの情報を使用して、後日ユーザーにこのことを思い出させることができます。
それらは非常に異なるものを表すため、別々に表されます。@qstarinが言ったように、コマンドは拒否できるメッセージであり、成功するとイベントが生成されます。コマンドとイベントはDtoであり、メッセージであり、エンティティを作成するときに非常によく似ている傾向がありますが、それ以降は必ずしもそうとは限りません。
再利用が心配な場合は、コマンドとイベントを(メッセージ)ペイロードへのエンベロープとして使用できます。
class CreateSomethingCommand
{
public int CommandId {get; set;}
public SomethingEnvelope {get; set;}
}
しかし、私が知りたいのは、なぜあなたは:Dを尋ねているのですか?つまり、コマンド/イベントが多すぎますか?
上記の概念上の違いに加えて、一般的な実装に関連する別の違いがあると思います。
イベントは通常、イベントキューをポーリングする必要があるバックグラウンドループで処理されます。イベントの処理に関心のあるパーティは、通常、イベントキュー処理の結果として呼び出されるコールバックを登録できます。したがって、イベントは1対多の場合があります。
コマンドをそのような方法で処理する必要がない場合があります。コマンドの発信者は通常、コマンドの目的のエグゼキュータにアクセスできます。これは、たとえば、エグゼキュータへのメッセージキューの形式である可能性があります。したがって、コマンドは単一のエンティティを対象としています。
これらの素晴らしい答えに追加するだけです。カップリングの違いを指摘したいと思います。
コマンドは特定のプロセッサに向けられます。したがって、コマンドイニシエータおよびプロセッサとの依存/結合にはある程度のレベルがあります。
たとえばUserService
、新しいユーザーを作成すると、に「SendEmail」コマンドが送信されますEmailService
。
UserService
が必要であることを知っているという事実EmailService
、それはすでに結合しています。EmailService
APIスキーマを変更したり、ダウンしたりすると、関数に直接影響しますUserService
。
イベントは特定のイベントハンドラーに向けられません。したがって、イベント発行者は緩く結合されます。どのサービスがそのイベントを消費するかは関係ありません。イベントのコンシューマーが0であることも有効です。
たとえばUserService
、新しいユーザーを作成すると、「ユーザー作成イベント」が公開されます。潜在的に、EmailService
はそのイベントを消費し、ユーザーに電子メールを送信する可能性があります。
ここでは、UserService
は認識していませんEmailService
。それらは完全に分離されています。ダウンした場合、またはビジネスルールを変更した場合は、EmailService
編集するだけで済みます。EmailService
どちらのアプローチにもメリットがあります。純粋にイベント駆動型のアーキテクチャ設計は、特に大規模なシステムでは結合が緩すぎるため、追跡が困難です。また、コマンドヘビーアーキテクチャには高レベルの結合があります。したがって、バランスが取れていることが理想的です。
それが理にかなっていることを願っています。
quentin-santinの答えに追加するものは、次のとおりだと思います。
リクエストをオブジェクトとしてカプセル化することで、さまざまなリクエストでクライアントをパラメータ化し、リクエストをキューまたはログに記録し、元に戻せない操作をサポートできるようにします。
ソース。
コマンドに基づいて状態を再計算することはできません。一般に、コマンドは処理されるたびに異なる結果を生成する可能性があるためです。
たとえば、GenerateRandomNumber
コマンドを想像してみてください。呼び出されるたびに、異なる乱数Xが生成されます。したがって、状態がこの数値に依存している場合、コマンド履歴から状態を再計算するたびに、異なる状態が得られます。
イベントはこの問題を解決します。コマンドを実行すると、コマンド実行の結果を表す一連のイベントが生成されます。たとえば、GenerateRandomNumber
コマンドはGeneratedNumber(X)
、生成された乱数をログに記録するイベントを生成できます。これで、イベントログから状態を再計算すると、コマンドの特定の実行によって生成されたのと同じ番号を常に使用するため、常に同じ状態になります。
言い換えると、コマンドは副作用のある関数であり、イベントはコマンドの特定の実行の結果を記録します。
注:監査またはデバッグの目的で、コマンドの履歴を引き続き記録できます。重要なのは、状態を再計算するには、コマンドの履歴ではなく、イベントの履歴を使用するということです。