CQRS, pour Command Query Responsibility Segregation est une architecture logiciel qui repose sur un principe simple : la séparation, au sein d’une application, des composants de modification et de restitution de l’information sous les termes Command (pour l’écriture) et Query (pour la lecture).
Ces termes sont repris du pattern CQS, pour Command and Query Separation, selon lequel les méthodes d’une classe doivent être divisées en 2 catégories bien distinctes :
Les « Queries » : renvoient un résultat et ne modifient pas l’état observable du système (sont donc exemptes d’effet de bord).
Les « Commands » : modifient l’état d’un système mais sans renvoyer de valeur
CQRS applique donc CQS au niveau applicatif.
CQRS applique donc CQS au niveau applicatif.
En lecture : des besoins de scalabilité, de dénormalisation, d’agrégation de différentes sources, de recherche
En écriture : des besoins transactionnels, de garantir la cohérence des données, de normalisation
Scinder ces différentes visions en 2 modèles bien distincts induit donc une séparation au niveau du code, rendant également possible une séparation au niveau hardware si nécessaire (sources de données, voir microservices).
On remplace ainsi des action PATCH, au sens « CRUDien », pauvres en terme de sens, par des classes Command reflétant les cas d’utilisation fonctionnels, avec un nom d’action simple, à l’impératif : PayOrder, RenewPassword, CreateUser …
Dans une application web, la requête est généralement validée de manière superficielle, transformée en « Command », puis validée et traitée par un « Handler » qui va avoir pour responsabilité principale de coordonner les actions de la couche métier.
Comme un Handler traite unitairement une Command, il est d’autant plus facile de mettre en place des écritures transactionnelles avec une gestion simplifiée des erreurs et des retours en arrière, en profitant pleinement des fonctionnalités avancées d’un ORM (Object Relational Mapping) par exemple.
Cerise sur le gâteau, en permettant de se focaliser sur les modifications de l’état d’un système, la couche d’écriture est donc un partenaire de choix pour des modélisations métier basées sur Domain Driven Design, permettant de profiter pleinement par exemple du pattern Aggregate pour garantir la cohérence des données tout au long de son cycle de vie.
Il est donc possible de retourner plusieurs visions d’un même agrégat, basées sur le besoin fonctionnel, facilitant l’émergence d’IHM orientées tâches.
Le principal bénéfice de cette approche : la performance ! On oublie l’ORM et on tire partie au maximum de requêtes dédiées et optimisées, avec jointures et directives SQL spécifiques à votre système de base de données.
Besoin d’encore plus de performance : isolez les bases de données de lecture et d’écriture et passez au pattern Database per service et bénéficiez des avantages de scalabilité d’une architecture en microservices. Vous aurez cependant à veiller à la synchronisation entre la base de données principale, gérée par la couche d’écriture, source de vérité, et les différentes projections crées pour le ou les modèles de lecture, chose qui peut être résolue de manière asynchrone avec de la gestion d’événements.
Ces termes sont repris du pattern CQS, pour Command and Query Separation, selon lequel les méthodes d’une classe doivent être divisées en 2 catégories bien distinctes :


CQRS applique donc CQS au niveau applicatif.
CQRS : Diviser pour mieux régner ?
Les développeurs à l’origine de CQRS partent du principe suivant : les besoins, fonctionnels ou techniques, d’une application peuvent être très différents que l’on soit dans un scénario de lecture ou d’écriture :

Scinder ces différentes visions en 2 modèles bien distincts induit donc une séparation au niveau du code, rendant également possible une séparation au niveau hardware si nécessaire (sources de données, voir microservices).
Le modèle d’écriture du pattern Command Query Responsibility Segregation
C’est le modèle qui porte les règles et le comportement métier de notre application. Avec CQRS, chaque action utilisateur est contextualisée : on ne se contente pas de modifier une liste de données, la commande porte l’intention et borne le champ d’intervention sur une ressource.On remplace ainsi des action PATCH, au sens « CRUDien », pauvres en terme de sens, par des classes Command reflétant les cas d’utilisation fonctionnels, avec un nom d’action simple, à l’impératif : PayOrder, RenewPassword, CreateUser …
Dans une application web, la requête est généralement validée de manière superficielle, transformée en « Command », puis validée et traitée par un « Handler » qui va avoir pour responsabilité principale de coordonner les actions de la couche métier.
Comme un Handler traite unitairement une Command, il est d’autant plus facile de mettre en place des écritures transactionnelles avec une gestion simplifiée des erreurs et des retours en arrière, en profitant pleinement des fonctionnalités avancées d’un ORM (Object Relational Mapping) par exemple.
Cerise sur le gâteau, en permettant de se focaliser sur les modifications de l’état d’un système, la couche d’écriture est donc un partenaire de choix pour des modélisations métier basées sur Domain Driven Design, permettant de profiter pleinement par exemple du pattern Aggregate pour garantir la cohérence des données tout au long de son cycle de vie.
Le modèle de lecture du pattern CQRS
Ici plus besoin de modèle riche, nous sommes dans la couche de restitution de l’information. Les données sont donc renvoyées via des DTOs, taillés sur mesure pour les cas d’utilisation auxquels ils correspondent.Il est donc possible de retourner plusieurs visions d’un même agrégat, basées sur le besoin fonctionnel, facilitant l’émergence d’IHM orientées tâches.
Le principal bénéfice de cette approche : la performance ! On oublie l’ORM et on tire partie au maximum de requêtes dédiées et optimisées, avec jointures et directives SQL spécifiques à votre système de base de données.
Besoin d’encore plus de performance : isolez les bases de données de lecture et d’écriture et passez au pattern Database per service et bénéficiez des avantages de scalabilité d’une architecture en microservices. Vous aurez cependant à veiller à la synchronisation entre la base de données principale, gérée par la couche d’écriture, source de vérité, et les différentes projections crées pour le ou les modèles de lecture, chose qui peut être résolue de manière asynchrone avec de la gestion d’événements.
Bilan de l’architecture CQRS
Les avantages du pattern CQRS




Les inconvénients de ce pattern



Pour aller plus loin




L’architecture CQRS vous intéresse ? Vous souhaitez échanger avec l’un de nos experts au sujet de cet article ?
à lire aussi…