Article

Comprendre CQRS avec une commande client

CQRS distingue les règles qui valident une opération des données préparées pour les vues. Une commande client explique les deux modèles et leur synchronisation.

Enregistrer une commande et afficher la liste des achats posent des problèmes différents. Le premier traitement doit vérifier des règles ; le second doit fournir rapidement les informations attendues à l'écran. CQRS permet de leur donner des modèles distincts. Cette séparation peut simplifier un domaine complexe, mais elle ajoute aussi du travail si des copies de lecture doivent être maintenues.

La même commande sert à valider un achat et à l'afficher

Lorsqu'un client modifie les quantités de sa commande, l'application doit vérifier les valeurs, recalculer le total et respecter les règles de changement de statut. Une commande annulée, par exemple, ne doit pas devenir expédiée à la suite d'une simple modification.

La page « Mes commandes » a un autre besoin. Elle affiche un numéro, une date, un montant et un statut pour chaque achat. Elle n'a pas besoin de recalculer toutes les règles métier pour présenter ces lignes.

Un modèle unique peut parfaitement remplir ces deux rôles. Les séparer devient intéressant lorsque le modèle utile aux modifications se prête mal aux écrans, ou lorsque les lectures et les écritures ont des besoins très différents.

Le modèle d'écriture vérifie les règles

Le modèle d'écriture, souvent appelé write model, reçoit les demandes de modification et décide si elles sont valides. Il conserve les informations qui font référence pour le domaine concerné.

Une demande telle que « modifier la quantité de cette ligne » est une commande au sens de CQRS. Le mot désigne ici une action demandée au système, et non l'achat du client. Le traitement peut accepter cette action ou la refuser avec une explication.

Les règles qui doivent toujours être respectées sont parfois appelées invariants. « Une quantité ne peut pas être négative » en est un exemple. Le modèle d'écriture doit protéger ces règles, y compris lorsque deux utilisateurs modifient les données en même temps.

Dans la modélisation métier, un groupe d'objets dont les règles sont vérifiées ensemble peut former un agrégat. Pour notre commande client, ce groupe peut comprendre les lignes et le total. Le stock et le paiement peuvent relever d'autres groupes, avec lesquels il faut se coordonner.

Le modèle de lecture prépare les données pour leur usage

Le modèle de lecture, ou read model, fournit les données demandées sans modifier l'état métier. Une requête est cette demande d'information : retrouver une commande, afficher une liste ou calculer un tableau de bord.

Pour la page « Mes commandes », le modèle peut fournir directement une ligne de résumé par achat. Il évite au code d'affichage de parcourir les objets chargés de vérifier les règles métier.

Modèle d'écritureModèle de lecture
BesoinAccepter ou refuser une modificationPrésenter les informations demandées
ExempleVérifier une modification de quantitéAfficher le total et le statut
OrganisationAdaptée aux règles métierAdaptée aux recherches et aux écrans
StockageConserve les données de référencePeut lire ces données ou une copie préparée

Le sigle CQRS développe Command Query Responsibility Segregation, soit la séparation des responsabilités entre commandes et requêtes. Greg Young rattache cette approche au principe de séparation commande/requête de Bertrand Meyer.

Dans une API, le résultat d'une commande peut inclure une confirmation, un identifiant ou une erreur. Le point à préserver est la distinction des responsabilités ; une requête de consultation ne doit pas déclencher discrètement une modification métier.

Une projection construit une vue à partir des données de référence

Lorsque le modèle de lecture dispose de sa propre copie, un traitement doit la mettre à jour. Ce calcul s'appelle une projection. Il transforme les données de référence en une forme adaptée à la lecture.

Quand la commande passe à « expédiée », la projection reporte ce statut dans son résumé. Elle peut être exécutée dans la même transaction ou plus tard. Le schéma suivant montre le second cas.

Le write model (source de vérité) alimente, par projection en différé, le read model (vue dénormalisée pour la lecture).
Dans cet exemple asynchrone, une projection reporte les changements vers le modèle de lecture. CQRS peut aussi utiliser une mise à jour synchrone ou un stockage partagé.

Une mise à jour différée crée un décalage possible : la commande est expédiée dans le modèle d'écriture, mais la liste affiche encore son ancien statut. Si les mises à jour finissent par être appliquées, la copie rejoint l'état de référence. C'est le principe de la cohérence éventuelle.

Une projection peut être reconstruite si les informations nécessaires à son calcul sont conservées. Pour retrouver le statut actuel, l'état courant de la commande peut suffire. Pour compter ses changements de statut au fil du temps, il faut aussi garder un historique. Une copie contenant une information unique ne peut pas être supprimée sans perte.

Deux modèles ne nécessitent pas deux bases de données

Martin Fowler décrit une forme de CQRS dans laquelle les modèles partagent la même base. Le guide de Microsoft présente aussi cette possibilité. La séparation peut donc commencer dans le code, sans bus de messages ni serveur supplémentaire.

Des stockages distincts deviennent utiles lorsque les besoins le justifient : un index pour la recherche, par exemple, ou des ressources séparées pour absorber beaucoup de lectures. Ils ajoutent en contrepartie des mises à jour à surveiller et une stratégie de reconstruction.

CQRS n'impose pas non plus de conserver tous les événements passés. Cette technique, appelée event sourcing, est un choix distinct de stockage. Le besoin d'historique doit être établi séparément.

Choisir cette séparation là où elle simplifie réellement le travail

Je commencerais par une partie précise de l'application dont les règles de modification deviennent difficiles à faire cohabiter avec les besoins d'affichage. La séparation doit rendre cette partie plus compréhensible ou permettre un gain mesurable sur son fonctionnement.

Un fort écart entre les volumes de lecture et d'écriture peut aussi justifier des modèles ou des stockages distincts. Dans les deux cas, il faut compter le coût de leur entretien, pas seulement le bénéfice attendu.

Pour un formulaire qui enregistre quelques champs puis les réaffiche, un modèle unique reste souvent plus facile à maintenir. L'article sur CAP permet d'approfondir les choix de cohérence lorsque des données sont partagées entre machines ; cette complexité n'est pas un passage obligé pour commencer à séparer commandes et requêtes.

Sources

Explorer

Sur le même sujet

Choisis dans l’index d’après les étiquettes de cet article — les plus proches d’abord, hors de sa série. Rien n’est écrit à la main : un article publié demain avec les mêmes étiquettes y prendra place.

Laisser un commentaire

Elle n'est jamais affichée ni publiée. Elle sert à regrouper vos commentaires et, si vous vous inscrivez un jour avec elle, à vous les rendre.

Votre commentaire sera relu avant d'être publié.