Architecture, CQRS, de quoi parle-t-on ?
CQRS, définition
CQRS est un acronyme pour Command Query Responsability Segregation. Il s’agit d’un pattern d’architecture qui vise à séparer les couches de lecture et d’écriture.
Le besoin est né du constat que la plupart des architectures proposent une unique couche d’accès aux données permettant de faire la lecture et l’écriture. Or, dans la plupart des applications, les besoins en écriture ne coïncident pas avec ceux en lecture.
Prenons l’exemple d’un quelconque site de e-commerce, là où les infos de la fiche produit seront lues des milliers de fois chaque jour (parfois chaque seconde), la mise au panier n’interviendra qu’à un rythme beaucoup moins soutenu.
D’une manière générale, on va séparer (Segregation) la responsabilité (Responsability) des lectures (Query) et écriture (Command).
Néanmoins, la mise en place de CQRS n’est pas chose aisée et peut poser quelques problèmes.
CQRS, problématique
Quand on essaie pour la première fois de comprendre CQRS, on se retrouve devant quelque chose de passablement abstrait et plutôt difficile à intégrer avec de réels problèmes :
- Comment je vais pouvoir implémenter ça ?
- Comment adapter ces concepts à mon contexte actuel ?
- Est-ce pertinent pour mon besoin ?
- Est-ce que ça ne va pas coûter trop de temps par rapport au gain final ?
- …
Toutes ces questions sont centrales et pertinentes. On ne doit pas se lancer dans un modèle d’architecture sans en maîtriser les tenants et aboutissants, sans être capable d’en tirer ce qui est pertinent pour notre besoin du moment et sans s’assurer que notre projet aura à y gagner dès le départ.
Architecture, niveau 1, le monolithe
On avait une petite application à coder, on est pros, on est propres, on a fait du n-tiers qui marche bien :
C’est beau, ça marche, tout le monde est content…
Et puis il faut ajouter de nouvelles fonctionnalités, modifier et enrichir les existantes…
On se rend alors compte qu’on a codé un véritable monolithe avec un couplage fort entre les couches et que chaque évolution impacte toutes les couches. Et comme disait nos ancêtres les gaulois, « bouger un monolithe, c’est dur », avant l’arrivée de la potion magique…
Pour pallier à tout ça, en tant que bons concepteurs orientés objet que nous sommes, on va découpler un peu tout ça pour rendre ce monolithe un peu plus souple.
Architecture, niveau 2, le découplage
On ne va plus appeler directement chacune des couches, mais on va passer par des interfaces, ça nous permettra de mettre un peu de généricité et de mutualiser du code. Ça nous permettra de mettre en place des tests unitaires pour se protéger lors des prochaines évolutions !
On va également isoler chaque élément de domaine afin de cloisonner les fonctionnalités pour prévenir les régressions intempestives !
Petit exemple avec le domaine « Command » qui va permettre de gérer toutes les commandes de notre superbe application de e-commerce !
Ah, là, on est bien… Enfin… Si on met ça en place pour chaque classe de domaine qu’on possède….
On n’aurait pas cassé le RAP (Reused Abstraction Principle) ? On a mis en place un niveau d’abstraction (notre interface) qui n’est utilisé qu’une seule fois ! Le principe de l’abstraction est de pouvoir être réutilisé ! Sans ça, on ne profite pas de ce que l’abstraction aurait à offrir et on ajoute de la lourdeur aux instanciations et aux tests unitaires !
Et quand viennent les nouvelles demandes d’évolution, on se retrouve face à un nouveau monolithe… Découplé, mais monolithe quand même ! Et on nous demande de nouvelles vues, de nouvelles données, sauf qu’à chaque modification de table, on casse toutes nos implémentations, modèles et vues actuels… Accessoirement, l’application commence à poser des problèmes de performances…
Il va peut-être falloir commencer à séparer les modules de lecture et d’écriture…
Architecture, niveau 3, CQRS (un peu)
Quels sont les éléments les plus affichés dans mon application ? La fiche article ? Le panier ? Les promos ? Très bien, on va créer une autoroute pour ces éléments-là. Pour le reste, on va s’assurer que nos données restent fiables.
On possède une base en lecture dénormalisée, nos performances sont maintenant bien meilleures ! On a mis en place un module qui répercute les écritures sur la base de lecture et tout va bien non ? Pas tout à fait…
La mise en place de ce mode de codage reste coûteuse et le faire pour chaque domaine fonctionnel de l’application s’annonce beaucoup trop long. Les demandes d’évolutions vont s’empiler et le client va s’impatienter… Il faut donc prioriser les domaines à basculer, mais comment choisir ?
Pour répondre à cette interrogation, il convient de répondre à une question fondamentale : quel est l’avantage stratégique du métier ? Sur quoi veut-il faire la différence ? Quel est son plan de développement business à moyen terme ?
On va ainsi devoir dialoguer avec le métier, et pour le faire efficacement, il conviendra de modéliser ses concepts en termes de domaines, d’événements faits… Tous les acteurs du projet, fonctionnels ET techniques y trouveront du sens !
Architecture, niveau 4, CQRS (un peu plus avec du DDD)
Maintenant que « tout le monde » fait du scrum, on va s’appuyer sur notre pratique des user stories pour orienter tout ça vers les notions de faits et d’événements. Mon client peut ajouter un produit à son panier ? Il en découle un fait, une intention, ‘AjoutProduitAuPanier’ et un événement (immuable puisque déjà passé) ‘ProduitAjoutéAuPanier’. Au niveau code, on va transformer ces intentions en Command et ces événements en Events. Regrouper ces faits et événements par éléments de domaine (panier, commande, navigation…) est hérité du DDD (Domain Driven Design ou Conception Dirigée par le Domaine). On dispose ici d’un langage commun avec le métier et d’un parallèle fort entre l’organisation métier et technique ce qui va faciliter la lecture du code pour les futurs entrant.
Côté technique, les actions utilisateurs vont déclencher des commandes (réversibles) suivies par des événements (immuables). Il s’agit ensuite de bien organiser tout ça afin d’assurer la pertinence du tout.
Tout ce petit monde fonctionne à merveille, mais maintenant que le business tourne bien, le marketing, la direction et d’autres entités du métier se sont greffés au projet et aimeraient obtenir des informations sur les comportements utilisateurs (ajout/suppression du panier, articles explorés avant ajout au panier…). Comment faire ça sans ré-impacter tous les scénario de l’application ? Il nous faudrait un genre de machine à voyager dans le temps !!!
Architecture, niveau 5, CQRS (encore plus, avec DDD et ES)
On a une machine à voyager dans le temps ! Ce sont nos événements ! Pour permettre le voyage dans le temps, il convient de stocker tous ces événements. On pourra ainsi reconstruire tout un cheminement à travers l’application en temps réel. On pourra également restaurer avec finesse à un état antérieur : la sauvegarde du panier a planté ? Peu importe, on sait quels articles ont été ajoutés puis enlevés du panier ! On appelle ce concept l’Event Sourcing (ES).
C’est ce genre de fonctionnement qui est utilisé par les banques pour calculer avec certitude un solde sur un compte bancaire. Le solde n’est pas enregistré tel quel, il est recalculé à partir des mouvements successifs et peut donc être retrouvé à n’importe quel jour du mois avec beaucoup de facilité.
Architecture, CQRS, pourquoi, où, comment, combien ?
CQRS peut nous aider à résoudre des problématiques particulièrement complexes. Néanmoins, sa difficulté de mise en œuvre doit inciter à la prudence. Il faut se poser les bonnes questions :
- Ai-je réellement besoin d’un modèle aussi complexe ?
- Ai-je besoin de tous les niveaux d’implémentation ?
- Ai-je l’équipe me permettant de mettre en place ces concepts ?
- Est-ce que je suis bien outillé pour le faire ?
Face à une problématique métier forte, ce qui importe plus, c’est la capacité de l’architecte à faire preuve de pragmatisme et à préférer une solution adaptée à une solution élégante. Il faut également se souvenir que c’est le besoin métier qui doit diriger nos choix en architecture et non l’application qui doit piloter les besoins métiers.
CQRS, quelques ressources
Cet article a été très largement inspiré (jusqu’au titre) de la présentation faites par Thomas Jaskula (http://blogs.developpeur.org/tja/) au MUG Lyon le 24/06/2016 : http://fr.slideshare.net/tjaskula/cqr-sv2
J’ai également utilisé quelques sites en amont pour dégrossir le sujet : http://blog.eleven-labs.com/fr/cqrs-pattern/ , http://martinfowler.com/bliki/CQRS.html
Quelques notions sur le DDD peuvent s’avérer fort utiles : http://blog.xebia.fr/2009/01/28/ddd-la-conception-qui-lie-le-fonctionnel-et-le-code/ , http://blog.octo.com/domain-driven-design-des-armes-pour-affronter-la-complexite/
Enfin des bouquins de référence proposé par Thomas Jaskula lors de la présentation : https://www.amazon.fr/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577 et https://www.amazon.fr/Patterns-Principles-Practices-Domain-Driven-Design/dp/1118714709