Passer au contenu du pied de page
Iron Academy Logo
Problèmes courants en C#

CQRS Handler (C#) avec Domain Logic et Pipelines - Expliqué via la vidéo de Derek Comartin

Derek Comartin
8m 03s

Command Query Responsibility Segregation (CQRS) est un modèle de conception puissant dans les applications .NET qui aide à maintenir une séparation claire entre les opérations de lecture et d'écriture. Cette séparation permet d'améliorer l'évolutivité, la testabilité et le contrôle de la logique commerciale complexe. Cependant, au fur et à mesure que votre application se développe, vos gestionnaires CQRS en C# peuvent devenir gonflés de logique, ce qui les rend plus difficiles à maintenir et à tester.

Dans sa vidéo perspicace intitulée "Clean Up Bloated CQRS Handlers with Domain Logic & Pipelines", Derek Comartin explique comment nettoyer de tels gestionnaires de commandes CQRS en déplaçant la logique vers des modèles de domaine et en structurant un pipeline pour gérer la logique de commande étape par étape. Dans cet article, nous allons explorer l'approche de Derek en détail et apprendre comment construire des implémentations CQRS plus faciles à maintenir en C#.

Le problème des gestionnaires gonflés

Derek commence par mettre en évidence le scénario courant dans de nombreuses applications web : vous ouvrez un gestionnaire CQRS en C#, et c'est le bazar. Il y a la validation des données, l'autorisation, la logique d'entreprise, les transitions d'état, la publication d'événements, la journalisation - tout cela est enchevêtré.

Il illustre son propos à l'aide d'un objet de commande pour l'envoi d'une expédition. Le traducteur est chargé de :

  • Accès au magasin de données pour charger l'envoi.

  • Vérifier si le statut de l'envoi est prêt.

  • Mise à jour de l'état (c'est-à-dire mise à jour des données).

  • Sauvegarde des modifications dans la couche d'accès aux données.

  • Envoi d'un courrier électronique.

  • Publication d'un événement de domaine.

Tout cela se fait en un seul endroit. Cela va à l'encontre de l'intention du modèle CQRS, dont l'objectif est de séparer les préoccupations et d'améliorer les performances et la maintenabilité.

Déplacer la logique du domaine vers le modèle de données

La première étape de Derek consiste à déplacer la logique de validation et de transition d'état dans le modèle de données. Il crée une méthode Dispatch() dans la classe Shipment. C'est ici que se trouve la logique du domaine.

Au lieu de vérifier manuellement le statut de l'envoi dans le gestionnaire, la logique est encapsulée dans cette méthode, ce qui garantit l'intégrité des données et un comportement cohérent lorsque le dispatching est déclenché. Il s'agit d'un élément clé pour la mise en œuvre d'une architecture propre dans votre application basée sur le CQRS.

Par exemple, tout endroit qui appelle shipment.Dispatch() effectue automatiquement toutes les validations et transitions d'état. Elle s'aligne sur le modèle de conception CQRS, en aidant à maintenir une séparation claire entre le gestionnaire et la logique du domaine.

La valeur de la centralisation de la logique

Derek souligne que ce type de changement ne consiste pas à ajouter des abstractions inutiles. Il s'agit plutôt de centraliser la logique utilisée dans différentes parties du code de votre application. Si plusieurs gestionnaires de commandes doivent expédier un envoi, cette logique personnalisée doit se trouver à un seul endroit, dans le modèle de domaine.

Ainsi, votre modèle de données sera plus robuste et vos implémentations C# du gestionnaire CQRS seront plus simples et plus faciles à maintenir.

Présentation du modèle de pipeline

Pour nettoyer davantage le gestionnaire de commandes, Derek introduit un modèle de pipeline. Cette structure traite une commande comme une séquence de petites étapes à but unique, chacune prenant un objet de contexte et appelant l'étape suivante.

Le concept est similaire à celui de l'intergiciel ASP.NET Core, et chaque étape se concentre sur une partie spécifique du flux :

  • Récupération de l'envoi (c'est-à-dire lecture des données)

  • Dispatching it (exécution des opérations d'écriture)

  • Événements de publication

  • Sauvegarde dans le magasin de données

Ces étapes utilisent un objet de commande partagé qui passe par le pipeline. Cela crée une implémentation propre et modulaire de la séparation des responsabilités des commandes et des requêtes.

Exemple de mise en œuvre du pipeline

Dans son exemple de mise en œuvre, Derek structure le pipeline avec des étapes telles que :

  • Chargement de la cargaison - extraction des données de la couche d'accès aux données à l'aide d'un référentiel.

  • Envoi de l'expédition - invocation de la méthode Dispatch() pour appliquer la logique du domaine.

  • Ajout d'un événement de domaine - attachement d'un événement "ShipmentDispatched" au contexte.

  • Publication d'événements - envoi d'événements pour informer des systèmes externes.

  • Sauvegarde des modifications - persistance des mises à jour dans le magasin de données.

Chaque étape représente un élément distinct de la logique de commande, ce qui permet d'améliorer la validation des données et de séparer les responsabilités.

Derek note également que les notifications par courrier électronique sont désormais traitées séparément en réagissant à l'événement du domaine. Ceci est conforme aux principes de l'event sourcing et favorise la cohérence à terme.

Avantages en matière de test et de maintenabilité

L'un des principaux avantages de ce modèle est la testabilité. Avec un grand gestionnaire de commandes, vous pouvez avoir plusieurs dépendances (par exemple, des dépôts, des services de messagerie, des enregistreurs). Mais lorsque vous décomposez le gestionnaire en étapes de pipeline, chacune d'entre elles ne nécessite que quelques dépendances.

Cette approche modulaire vous permet de tester facilement des étapes individuelles grâce à l'injection de dépendances, en utilisant des fakes ou des mocks si nécessaire. Par exemple, si vous testez une étape qui appelle Dispatch(), vous n'avez pas besoin de simuler un service de messagerie ou un éditeur d'événements.

Cette séparation des préoccupations suit le modèle de séparation des responsabilités CQRS, rendant vos modèles de lecture et d'écriture plus propres et plus ciblés.

Composabilité et réutilisabilité

Un autre avantage de l'approche par pipeline est qu'elle est composable. Si vous utilisez quelque chose comme le modèle Outbox, vous pouvez vous assurer que les événements ne sont publiés qu'après la persistance des modèles d'écriture. Ce niveau de contrôle est essentiel dans les implémentations CQRS où la cohérence et les garanties de livraison sont importantes.

Vous pouvez également partager des étapes entre différents gestionnaires CQRS - par exemple, une étape générique "SaveChanges" ou une étape "ValidateRequest".

En utilisant des outils tels que la bibliothèque MediatR, qui prend en charge la gestion des commandes et des requêtes, vous pouvez même enregistrer ces étapes par injection de dépendances dans votre application .NET Core à l'aide des services IServiceCollection.

Pour mettre en place ce système, vous pouvez exécuter Install-Package MediatR via la console du Package Manager de Visual Studio - une étape courante lors de la mise en œuvre de CQRS en C#.

Les compromis

Derek n'hésite pas à faire face à la complexité accrue qui découle de cette approche. Les pipelines introduisent l'indirection, et lorsque vous regardez une pile d'appels, vous pouvez avoir l'impression de naviguer dans un labyrinthe.

Toutefois, dans le cas d'une logique d'entreprise complexe, le compromis en vaut souvent la peine. Si un gestionnaire comporte plus de 10 dépendances et des centaines de lignes logiques, le CQRS permet aux développeurs de mieux structurer et maintenir ces flux.

Réflexions finales sur le moment de la refonte

Derek conclut en rappelant aux spectateurs de bien réfléchir à la question de savoir si leur implémentation C# du gestionnaire CQRS est vraiment gonflée. Tous les scénarios ne nécessitent pas un pipeline. Son objectif est d'illustrer les possibilités, et c'est aux développeurs d'évaluer leur propre mise en œuvre du CQRS et de déterminer si de tels modèles sont utiles.

Il encourage les développeurs à examiner les zones de leur code où la séparation des préoccupations permettrait de maintenir la cohérence, de rendre le code plus modulaire et de mieux gérer les opérations de lecture et d'écriture, en particulier dans les applications web CQRS.

Conclusion

La vidéo de Derek Comartin propose un guide pratique pour nettoyer les gestionnaires CQRS à l'aide de l'encapsulation de la logique de domaine et des pipelines. Cette approche permet de résoudre les problèmes de gonflement du code, de promouvoir l'intégrité des données et d'améliorer la maintenabilité en décomposant le code de l'application en modèles distincts.

Que vous traitiez des données sur les employés, des détails sur les produits ou une nouvelle commande utilisateur, l'application du modèle CQRS avec des pipelines et une conception axée sur le domaine rendra votre base de code plus évolutive, plus testable et plus robuste.

En utilisant des objets de transfert de données, des modèles distincts et en maintenant une séparation claire entre la logique de lecture et d'écriture, votre application .NET sera mieux structurée et plus facile à faire évoluer au fil du temps.

Hero Worlddot related to CQRS Handler (C#) avec Domain Logic et Pipelines - Expliqué via la vidéo de Derek Comartin
Hero Affiliate related to CQRS Handler (C#) avec Domain Logic et Pipelines - Expliqué via la vidéo de Derek Comartin

Gagnez plus en partageant ce que vous aimez

Vous créez du contenu pour les développeurs travaillant avec .NET, C#, Java, Python ou Node.js ? Transformez votre expertise en revenu supplémentaire !

Équipe de soutien Iron

Nous sommes en ligne 24 heures sur 24, 5 jours sur 7.
Chat
Email
Appelez-moi