Quelle est la différence entre les commandes et les événements dans les architectures qui mettent l'accent sur les événements? La seule distinction que je peux voir est que les commandes sont généralement sourcées/invoquées par des acteurs extérieurs au système, tandis que les événements semblent provenir de gestionnaires et d'autres codes d'un système. Cependant, dans de nombreux exemples d'applications que j'ai vus, ils ont des interfaces différentes (mais fonctionnellement similaires).
Les commandes peuvent être rejetées.
Des événements se sont produits.
C'est probablement la raison la plus importante. Dans une architecture événementielle, il ne fait aucun doute qu'un événement déclenché représente quelque chose qui s'est produit.
Maintenant, parce que les commandes sont quelque chose que nous voulons se produire, et les événements sont quelque chose qui a s'est produit, nous devrions utiliser différents verbes lorsque nous nommons ces choses. Cela entraîne des représentations distinctes.
Je peux voir que les commandes proviennent généralement/sont invoquées par des acteurs extérieurs au système, tandis que les événements semblent provenir de gestionnaires et d'autres codes dans un système
C'est une autre raison pour laquelle ils sont représentés séparément. Clarté conceptuelle.
Les commandes et les événements sont tous deux des messages. Mais ce sont en fait des concepts distincts, et les concepts doivent être modélisés explicitement.
De plus, en plus de toutes les réponses présentées ici, un gestionnaire d'événements peut également déclencher une commande après avoir reçu la notification qu'un événement s'est produit.
Supposons par exemple qu'après avoir créé un client, vous souhaitiez également initialiser certaines valeurs de comptes, etc. Après que votre AR client a ajouté l'événement à EventDispatcher et que celui-ci est reçu par un objet CustomerCreatedEventHandler, ce gestionnaire peut déclencher l'envoi d'une commande qui exécutera tout ce dont vous avez besoin, etc.
Il existe également des événements de domaine et des événements d'application. La différence est simplement conceptuelle. Vous voulez d'abord envoyer tous vos événements de domaine (certains d'entre eux peuvent produire des événements d'application). Qu'est-ce que je veux dire par là?
L'initialisation d'un compte après qu'un événement CustomerCreatedEvent s'est produit est un événement DOMAIN. L'envoi d'une notification par e-mail au client est un événement d'application.
La raison pour laquelle vous ne devez pas les mélanger est claire. Si votre serveur SMTP est temporairement hors service, cela ne signifie pas que votre OPÉRATION DE DOMAINE devrait en être affectée. Vous souhaitez toujours conserver un état non corrompu de vos agrégats.
J'ajoute généralement des événements à mon répartiteur au niveau racine agrégée. Ces événements sont soit DomainEvents ou ApplicationEvents. Peut être les deux et peut être plusieurs. Une fois que mon gestionnaire de commandes est terminé et que je suis de retour dans la pile vers le code qui exécute le gestionnaire de commandes, je vérifie mon répartiteur et envoie tout autre DomainEvent. Si tout cela réussit, je ferme la transaction.
Si j'ai des événements d'application, c'est le moment de les envoyer. L'envoi d'un e-mail n'a pas nécessairement besoin d'une connexion ouverte à une base de données ni d'une étendue de transaction ouverte.
Je me suis éloigné un peu de la question d'origine, mais il est également important pour vous de comprendre comment les événements peuvent également être traités différemment sur le plan conceptuel.
Ensuite, vous avez des Sagas .... mais c'est WAYYYY HORS de la portée de cette question :)
Est-ce que ça fait du sens?
Après avoir travaillé sur quelques exemples et en particulier la présentation de Greg Young ( http://www.youtube.com/watch?v=JHGkaShoyNs ) je suis arrivé à la conclusion que les commandes sont redondantes. Ce sont simplement des événements de votre utilisateur, ils ont appuyé sur ce bouton. Vous devez les stocker exactement de la même manière que les autres événements, car ce sont des données et vous ne savez pas si vous souhaitez les utiliser dans une future vue. Votre utilisateur a ajouté puis supprimé cet élément du panier ou au moins a tenté de le faire. Vous souhaiterez peut-être ultérieurement utiliser ces informations pour le rappeler ultérieurement à l'utilisateur.
En plus des différences conceptuelles mentionnées ci-dessus, je pense qu'il existe une autre différence liée aux implémentations courantes:
Les événements sont généralement traités dans une boucle d'arrière-plan qui doit interrogation les files d'attente d'événements. Toute partie intéressée à agir sur l'événement peut généralement enregistrer un rappel qui est appelé à la suite du traitement de la file d'attente des événements. Donc un événement peut être un à plusieurs.
Les commandes peuvent ne pas avoir besoin d'être traitées de cette manière. L'expéditeur de la commande aura généralement accès à l'exécuteur prévu de la commande. Cela pourrait être, par exemple, sous la forme d'une file d'attente de messages à l'exécuteur. Ainsi, une commande est destinée à une seule entité.
Ils sont représentés séparément parce qu'ils représentent des choses très différentes. Comme @qstarin l'a dit, les commandes sont des messages qui peuvent être rejetés et qui, en cas de succès, produiront un événement. Les commandes et les événements sont des Dtos, ce sont des messages, et ils ont tendance à être très similaires lors de la création et de l'entité, mais à partir de là, pas nécessairement.
Si vous vous inquiétez de la réutilisation, vous pouvez utiliser des commandes et des événements comme enveloppes pour votre charge utile (messge)
class CreateSomethingCommand
{
public int CommandId {get; set;}
public SomethingEnvelope {get; set;}
}
cependant, ce que j'aimerais savoir, c'est pourquoi demandez-vous: D c'est-à-dire que vous avez trop de commandes/événements?
Je pense que quelque chose à ajouter à la réponse de quentin-santin est qu'ils:
Encapsulez une demande en tant qu'objet, ce qui vous permet de paramétrer les clients avec différentes demandes, demandes de file d'attente ou de journal, et de prendre en charge les opérations annulables.
Source .
Le événement est un fait du passé.
La commande n'est qu'une demande et peut donc être refusée.
Une caractéristique importante d'une commande est qu'elle ne doit être traitée qu'une seule fois par un seul récepteur. En effet, une commande est une action ou une transaction unique que vous souhaitez effectuer dans l'application. Par exemple, la même commande de création de commande ne doit pas être traitée plus d'une fois. Il s'agit d'une différence importante entre les commandes et les événements. Les événements peuvent être traités plusieurs fois car de nombreux systèmes ou microservices peuvent être intéressés par l'événement. "msdn"
Vous ne pouvez pas recalculer un état basé sur des commandes, car en général, elles peuvent produire des résultats différents à chaque fois qu'elles sont traitées.
Par exemple, imaginez une commande GenerateRandomNumber
. Chaque fois qu'il est invoqué, il produira un nombre aléatoire différent X. Ainsi, si votre état dépend de ce nombre, chaque fois que vous recalculez votre état à partir de l'historique des commandes, vous obtiendrez un état différent.
Les événements résolvent ce problème. Lorsque vous exécutez une commande, elle produit une séquence d'événements qui représentent le résultat de l'exécution de la commande. Par exemple, la commande GenerateRandomNumber
peut produire un événement GeneratedNumber(X)
qui enregistre le nombre aléatoire généré. Maintenant, si vous recalculez votre état à partir du journal des événements, vous obtiendrez toujours le même état, car vous utiliserez toujours le même nombre qui a été généré par une exécution particulière de la commande.
En d'autres termes, les commandes sont des fonctions avec des effets secondaires, les événements enregistrent le résultat d'une exécution particulière d'une commande.
Remarque: vous pouvez toujours enregistrer un historique des commandes à des fins d'audit ou de débogage. Le fait est que pour recalculer l'état, vous utilisez l'historique des événements, pas l'historique des commandes.