Par exemple, lorsque vous soumettez un formulaire d'inscription, vous devez vérifier le Domain Model
(WriteModel
dans CQRS
) qu'il est dans un état valide (exemple, syntaxe de l'adresse e-mail, âge, etc.).
Ensuite, vous créez un Command
et l'envoyez à un Command Bus
.
Je comprends que les commandes ne doivent rien renvoyer.
Alors, comment gérez-vous une erreur au-delà de Command Bus
? (Par exemple, un utilisateur s'est enregistré 1 seconde avant avec le même username/email
).
Comment savez-vous que cette commande a échoué et comment connaissez-vous l'erreur?
Je comprends que les commandes ne doivent rien renvoyer.
C'est une vue, mais elle n'est pas entièrement gravée dans la pierre. Considérez les écritures (PUT, POST, DELETE) dans HTTP - tous ces messages sont des commandes, dans le sens où ce sont des messages avec demande que l'état de la ressource change, et pourtant ils renvoient tous des réponses.
Alors, comment gérez-vous une erreur au-delà du bus de commande? (Par exemple, un utilisateur s'est enregistré 1 seconde avant avec le même nom d'utilisateur/e-mail).
Comment savez-vous que cette commande a échoué et comment connaissez-vous l'erreur?
Ainsi, dans le cas où vous communiquez directement avec le gestionnaire de commandes, un message renvoyé est un moyen parfaitement raisonnable de reconnaître que la commande a été reçue et traitée.
Si vous utilisez un middleware, comme un bus, qui vous empêche de communiquer directement avec la cible, je vous suggère de rechercher des modèles de messagerie asynchrones - comment obtenir le gestionnaire de commandes pour renvoyer un message au votre interlocuteur?
Une idée est de souscrire au résultat de la commande; cela emprunte à certaines des idées des modèles d'intégration d'entreprise de Hohpe. L'idée de base est que, étant donné que le client connaît le message de commande qui a été envoyé, il est bien placé pour s'abonner à tout nouveau message publié à la suite du message de commande. Le gestionnaire de commandes, après avoir enregistré les données dans le livre d'enregistrement, publie les événements annonçant que le changement a réussi, et le client s'abonne à ces événements - reconnaissant les événements corrects en considérant la coïncidence de divers identifiants dans le message (identifiant de causalité, id de corrélation , etc.).
Les approches alternatives sont un peu plus directes. L'une consisterait à inclure dans le message un rappel, qui peut être invoqué par le gestionnaire de commandes une fois le message traité avec succès.
Une alternative très similaire consiste à réserver de l'espace dans le message de commande pour que le gestionnaire de commandes écrive l'accusé de réception - puisque le client a déjà le message de commande en question, le circuit est déjà terminé. Pensez " promesse " ou " futur completable". Le message indique au gestionnaire de commandes où écrire l'accusé de réception; cela signale au client (verrou de compte à rebours) que l'accusé de réception est disponible.
Et bien sûr, vous avez la possibilité supplémentaire de supprimer le middleware qui semble gêner simplement la bonne chose.
Par exemple, un utilisateur s'est enregistré 1 seconde avant avec le même nom d'utilisateur/e-mail
Si vous gérez l'enregistrement des utilisateurs de manière idempotente, ce ne serait pas nécessairement une erreur - la répétition des messages jusqu'à ce qu'une réponse soit observée est un moyen courant d'assurer au moins une fois la livraison.
Par exemple, lorsque vous soumettez un formulaire d'inscription, vous devez vérifier dans le modèle de domaine (WriteModel dans CQRS) qu'il est dans un état valide (exemple, syntaxe de l'adresse e-mail, âge, etc.)
Il existe de nombreux types de validation. La validation lorsque vous vérifiez la syntaxe de l'adresse e-mail et le format d'âge est un type de validation qu'une commande peut effectuer. Ce n'est pas vraiment une préoccupation de domaine. Cela peut sembler ainsi parce que certains experts du domaine vous diraient ces spécifications, mais vous devriez faire ce type de validation lors de la création de la commande. En fait, l'idée générale est de faire la validation le plus tôt possible car après avoir créé une commande et l'envoyer à un BUS, il est plus compliqué de prendre des mesures.
Alors, comment gérez-vous une erreur au-delà du bus de commande? (Par exemple, un utilisateur s'est enregistré 1 seconde avant avec le même nom d'utilisateur/e-mail).
Ce type de validation est très discuté dans la communauté CQRS, depuis le début du CQRS. Où le faire? C'est très débattu. J'utilise personnellement l'approche suivante: Avant d'envoyer la commande au BUS, je marque le nom d'utilisateur/e-mail comme pris de manière centralisée (c'est-à-dire une contrainte d'indexation unique sur le nom d'utilisateur/e-mail). Après cela, j'envoie la commande. L'inconvénient est que, si la commande échoue, pendant un court laps de temps ce nom d'utilisateur est pris et non utilisé; cela est acceptable pour mon entreprise, probable pour votre entreprise.
Comment savez-vous que cette commande a échoué et comment connaissez-vous l'erreur?
Si une commande asynchrone est rejetée par l'agrégat en raison d'un invariant de domaine, certaines mesures doivent être prises en émettant une commande compensatoire qui avertit en quelque sorte l'émetteur de la commande (c'est-à-dire envoyer un e-mail expliquant que la commande a échoué).
Le problème avec les e-mails en double est que vous ne pouvez pas envoyer un e-mail car cette adresse e-mail appartient à une autre personne, c'est pourquoi je la vérifie avant d'envoyer la commande au bus.
La validation doit être effectuée chez un décorateur. Ensuite, toute commande nécessitant une validation peut être décorée comme telle.
Les validations peuvent être traitées avec des exceptions si vous retournez void avec votre commande afin qu'elles puissent être récupérées avec des appels de synchronisation ou asynchrones avec le résultat de la tâche retournée.
Une autre possibilité est de considérer la validation comme un type de "requête" qui retournerait un résultat de validation. Exécutez la requête de validation, puis si elle est réussie, exécutez la commande. Ce serait une alternative à l'approche décorative.