Gestionnaires de commandes et DDD

10

J'ai une application ASP.NET MVC, qui utilise un service de requête pour obtenir des données et un service de commande pour envoyer des commandes. Ma question concerne la partie commande.

Si une demande arrive, le service de commande utilise un répartiteur de commande qui acheminera la commande vers son gestionnaire de commandes désigné. Ce gestionnaire de commandes valide d'abord la commande et si tout est acceptable, il exécute la commande.

Exemple concret: AddCommentToArticleCommandHandler reçoit un AddCommentToArticleCommand, qui a un ArticleId, CommentText et EmailAddress.

Première; la validation doit avoir lieu, comme: - vérifier si l'article existe - vérifier si l'article n'est pas fermé - vérifier si le texte du commentaire est rempli et entre 20 et 500 caractères - vérifier si l'adresse e-mail est remplie et a un format valide.

Je me demande où mettre cette validation?

1 / dans le gestionnaire de commandes lui-même. Mais alors, il ne peut pas être réutilisé dans d'autres gestionnaires de commandes.

2 / dans l'entité de domaine. Mais comme une entité de domaine ne connaît pas les référentiels ou les services, elle ne peut pas effectuer la validation nécessaire (ne peut pas vérifier si un article existe). Mais d'un autre côté, si l'entité ne contient pas de logique, alors elle devient un simple conteneur de données, qui ne suit pas les principes DDD.

3 / le gestionnaire de commandes utilise des validateurs, de sorte que la validation peut être réutilisée dans d'autres gestionnaires de commandes.

4 / Autres mécanismes?

Je cherche la chaîne de responsabilités pour cet exemple particulier et quels objets (entités, référentiels, ...) y jouent un rôle.

Avez-vous des idées sur la façon dont vous implémenteriez cela, depuis le gestionnaire de commandes jusqu'aux référentiels?

L-Four
la source
"Mais comme une entité de domaine ne connaît pas les référentiels ou les services, elle ne peut pas faire la validation nécessaire"? Pourquoi pas? Quel principe de DDD l'exige?
S.Lott
J'ai lu partout qu'une entité ne devrait pas connaître les référentiels ou autre chose.
L-Four
Pouvez-vous fournir un devis, un lien ou un exemple de ce que - spécifiquement - vous avez lu? Nous ne savons pas quelles descriptions de DDD vous lisez.
S.Lott
Jimmy Bogard a partagé quelques vues sur ce sujet ... lostechies.com/jimmybogard/2009/02/15/validation-in-a-ddd-world
Mayo

Réponses:

4

Je pense que vous devez séparer deux types de validation dans ce cas; validation de domaine et validation d'application .

La validation d'application est ce que vous avez lorsque vous vérifiez que la propriété de commande «texte» est comprise entre 20 et 200 caractères; vous validez donc cela avec l'interface graphique et avec un validateur de modèle de vue qui s'exécute également sur le serveur après un POST. Il en va de même pour le courrier électronique (btw, j'espère que vous vous rendez compte qu'un courrier électronique tel que `32.d +" Hello World .42 "@ mindomän.local" est valide selon la RFC).

Ensuite, vous avez une autre validation; vérifiez que cet article existe - vous devez vous poser la question de savoir pourquoi l'article ne devrait pas exister s'il existe en effet une commande envoyée depuis l'interface graphique qui consiste à y attacher un commentaire. Votre interface graphique a-t-elle finalement été cohérente et vous disposez d'une racine agrégée, l'article, qui peut être physiquement supprimée du magasin de données? Dans ce cas, vous déplacez simplement la commande dans la file d'attente des erreurs car le gestionnaire de commandes ne parvient pas à charger la racine agrégée.

Dans le cas ci-dessus, vous auriez une infrastructure qui gère les messages incohérents - ils réessayeraient par exemple le message 1 à 5 fois, puis le déplaceraient dans une file d'attente empoisonnée où vous pourriez inspecter manuellement la collection de messages et renvoyer ceux qui sont pertinents. C'est une bonne chose à surveiller.

Alors maintenant, nous avons discuté:

  • Validation des candidatures

    • Avec javascript dans l'interface graphique
    • Avec validation MVC sur le serveur Web
  • Files d'attente racine + poison agrégées manquantes

Qu'en est-il des commandes qui ne sont pas synchronisées avec le domaine? Peut-être avez-vous une règle dans la logique de votre domaine qui dit qu'après 5 commentaires sur un article, seuls les commentaires en dessous de 400 caractères sont autorisés, mais un gars était trop en retard avec le 5ème commentaire et devait être le 6ème - GUI ne l'a pas saisi car il n'était pas cohérent avec le domaine au moment où il envoyait sa commande - dans ce cas, vous avez un «échec de validation» dans le cadre de votre logique de domaine et vous renverriez l'événement d'échec correspondant.

L'événement peut prendre la forme d'un message sur un courtier de messages ou sur votre répartiteur personnalisé. Le serveur Web, si l'application est monolithique, pourrait écouter de manière synchrone à la fois un événement de réussite et l'événement d'échec mentionné et afficher la vue / partielle appropriée.

Souvent, vous avez un événement personnalisé qui signifie l'échec de nombreux types de commandes, et c'est cet événement auquel vous vous abonnez du point de vue du serveur Web.

Dans le système sur lequel nous travaillons, nous faisons des requêtes-réponses avec des commandes / événements sur un bus de messages MassTransit + RabbitMQ + un courtier et nous avons un événement dans ce domaine particulier (modélisation d'un flux de travail en partie) qui est nommé InvalidStateTransitionError. La plupart des commandes qui tentent de se déplacer le long d'une arête dans le graphique d'état peuvent provoquer cet événement. Dans notre cas, nous modélisons l'interface graphique d'après un paradigme finalement cohérent, et nous envoyons donc l'utilisateur vers une page de `` commande acceptée '' et ensuite laissons les vues du serveur Web se mettre à jour passivement via les abonnements aux événements. Il convient de mentionner que nous faisons également du sourcing d'événements dans les racines agrégées (et le ferons également pour les sagas).

Donc, vous voyez, une grande partie de la validation dont vous parlez sont en fait des validations de type application, et non une logique de domaine réelle. Il n'y a aucun problème à avoir un modèle de domaine simple si votre domaine est simple mais que vous faites DDD. Cependant, au fur et à mesure que vous modélisez votre domaine, vous découvrirez que le domaine n'est peut-être pas aussi simple qu'il l'a été au départ. Dans de nombreux cas, la racine / entité agrégée peut simplement accepter un appel de méthode provoqué par une commande et changer une partie de son état sans même effectuer de validation - en particulier si vous faites confiance à vos commandes comme vous le feriez si vous les validiez sur le serveur Web qui vous contrôlez.

Je peux recommander de regarder les deux présentations sur DDD de la Norwegian Developer Conference 2011 ainsi que la présentation de Greg à Öredev 2010 .

À la vôtre, Henke

Henrik
la source
Merci! Une chose à propos de la validation: pour le moment, cette validation est déclenchée par l'interface utilisateur (en émettant une demande de validation (commande) au service), qui utilise le Validate () de l'entité Comment elle-même. Ensuite, si la commande est valide, le client émet une commande Exécuter, qui exécutera à nouveau Validate () pour être sûr, et si elle est valide, la commande réelle est exécutée. La validation principale est donc effectuée par l'entité Comment, car dans tous les contextes la validation sera la même (l'email doit toujours être valide, le texte du commentaire n'est pas trop long, etc.) Est-ce une bonne approche?
L-Four
La validation que vous semblez décrire ne me semble pas justifier de la modéliser avec un protocole de validation en 2 phases - bien sûr, validez les paramètres de l'appel de méthode sur l'entité comme vous le feriez dans un test unitaire, mais en plus de cela; la couche application / GUI pourrait facilement valider les règles que vous décrivez sans envoyer de commandes au domaine. Imo. Sauf si le client est malveillant, la commande devrait alors fonctionner. Si le client est malveillant, la commande échoue et votre modèle de lecture n'obtient jamais d'événement correspondant et vous pouvez inspecter la commande problématique dans la file d'attente d'erreurs.
Henrik
Dans l'interface utilisateur (ASP.NET MVC), j'utilise des attributs de validation pour effectuer toute la validation. Donc si cette validation réussit, je n'ai pas à valider à nouveau sur le domaine alors, mais juste exécuter la commande?
L-Four
1
Oui, vous exécutez la commande mais assurez-vous que la commande n'est pas invalide à la fois dans la couche application et le domaine.
Henrik
0

EDIT: lien WaybackMachine: http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/17/a-response-to-validation-in-a-ddd-world.aspx

Il n'y a pas de réponse.

Il y a deux scénarios de projet clairs qui me viennent à l'esprit lorsque j'essaie de répondre à l'endroit où la validation doit vivre. La première est celle où une couche DTO est utilisée pour transférer des informations entre les couches de vue et de domaine. Par exemple, vous pouvez avoir un objet Client dans votre couche de domaine et un DTO Client associé dans une autre couche sur laquelle vous mappez les informations Client, pour ensuite donner à la vue de présentation des informations Client à l'utilisateur.

Le deuxième scénario est un projet dans lequel les entités de la couche domaine sont partagées directement avec la vue pour présenter les données à l'utilisateur. Par exemple, au lieu de conserver une couche DTO distincte et de mapper un objet de domaine aux DTO à attribuer à la vue, la vue peut être attribuée directement à l'objet Client. Ainsi, au lieu de parler via un DTO géré séparément pour afficher le nom d'un client, la vue demanderait simplement à l'objet client lui-même les informations.

S.Lott
la source