CQRS à notre secours - Compte-rendu du talk de Florent Jaby à la Duck Conf 2021

le 24/03/2021 par Antoine Mazure
Tags: Software Engineering

Florent Jaby à la Duck Conf

Le pattern CQRS ou Command Query Responsibility Segregation, que l’on pourrait traduire par « Séparation des responsabilités entre mutation et projection des données » représente le fait que les données d’un SI prennent des formes et des chemins différents s’ils suivent une logique de lecture ou une logique d’écriture. Cette séparation permet d’optimiser de manière précise et isolée ces deux chemins.

Dans ce talk, Florent nous fait part d’un retour d’expérience suite à l’utilisation de ce pattern, utilisé lors de sa dernière mission. Nous verrons que CQRS donne les clés permettant une compréhension et une participation des utilisateurs aux méthodes de résilience appliquées à l’application. En effet, cette séparation est un reflet du fonctionnement de nos organisations, ce qui permet aux acteurs de mettre en parallèle SI et organisation.

Contexte

« Des gens qui gèrent l’urgence et les imprévus »

Comme nous pouvons le voir ci-dessus, lorsqu’un incident intervient, l’information remonte à un opérateur, qui s’occupe de prévenir la personne la plus compétente selon l’événement. Cet incident peut ensuite être escaladé et arriver dans les tâches à faire d’autres personnes, plus à même de le résoudre. Lorsque cette tâche est résolue, l’opérateur retourne le résultat de cette tâche, ici sous forme de rapport.

L’information circule donc de manière ascendante et descendante, en prenant diverses formes :

  • l’information descendante : l’ordre, provient directement du terrain ;
  • l’information ascendante : le rapport de terrain, la notification, prévient d’une résolution ou d’une nouvelle information.

Tout cela forme donc une structure dite hiérarchique.

L’existant, le système d’information humain

Le point intéressant ici est que l’on a réussi à définir comment le système d’information fonctionne, sans mentionner de technologie. De fait, ce système d’information existe déjà : des humains qui communiquent avec d’autres humains, via différents canaux de messagerie. Ces personnes savent quels ordres doivent être donnés, quelles informations remonter et sous quelle forme. Notre SI doit donc récupérer cette structure connue, résiliente, et éprouvée.

Grâce à ça, un vocabulaire et des concepts communs (cf. Ubiquitous Language) ont été mis en place, pour régir les règles à développer dans le but d’obtenir un produit résilient et réactif.

Actuellement, ce système d’information est résilient car chacun des acteurs est capable de faire circuler l’information en dehors des vecteurs habituels lorsque c’est nécessaire. Devant traiter les incidents dans l’urgence, il est indispensable aux opérateurs de prévenir les bonnes personnes, capables de prendre les bonnes décisions : on parle ici de réactivité.

La construction du système d’information Temps Réel™

Nous allons donc voir comment tout cela a influencé les décisions pour construire le système d'information.

Lorsqu’un opérateur modifie ou déclare une information, celle-ci doit apparaître instantanément chez ses collègues. Le code métier transforme ces mutations en Commands, qui retournent une liste d’événements. Ces événements peuvent déclencher par réaction de nouvelles mutations, ce qui crée une boucle. Lorsque cette boucle est résolue, les utilisateurs sont notifiés.

À contrario, lorsque l’utilisateur navigue sur l’application, il exprime son intention, ce qui génère des Queries. Tout au long de la navigation d’un utilisateur, des notifications lui sont envoyées via un flux d’événements SSE afin de l’aider dans sa prise de décision.

D'un côté nous avons des réactions locales, qui réagissent à des intentions de mutation dans une seule grappe de nœuds, un seul code métier. De l'autre, nous avons des notifications globales, qui permettent d’informer tous les utilisateurs des mutations effectuées, via une projection d’événements.

« On se pose souvent la question "Comment une intention utilisateur génère un événement ?" mais un exercice moins fréquent mais tout autant intéressant est de se poser la question "Quels événements déclenchent des intentions utilisateurs ?" »

Lorsque l’on comprend quels événements génèrent quelles intentions, on peut automatiser ces intentions pour aider l’utilisateur dans son travail.

Les notifications ne font qu'informer l'utilisateur qu'une nouvelle donnée est disponible en lecture, libre à lui de demander cette donnée en exprimant son intention de projection. Quand le système n'est plus capable de fournir des données en temps réel, l'utilisateur peut alors prendre le relais et être lui-même réactif, manuellement.

Priorisation du système réactif

Grâce à tous ces éléments, nous pouvons prioriser les fonctionnalités, ici via MoSCoW. Par exemple, le Must Have serait la capacité de récupérer les données à l'affichage de la page alors que le Should Have serait l'affichage des notifications à chaque nouvel événement. Pour finir, un Nice To Have serait de fournir ces informations en temps réel.

Côté frontend : URL-driven interface

Lorsque l’on utilise l’URL-driven interface, chaque fragment du chemin représente un bloc de l'interface. Ce qui donne à l’URL une structure hiérarchique, que l’on retrouve dans l’interface. Grâce à cela, on sait quoi projeter sur chaque bloc d’interface. Ce qui permet à l’application d’afficher les données de manière précise et déterministe.

De même, lorsque l’application ne répond plus, l’utilisateur qui rafraîchit la page ne demande que ce dont il a besoin.

En résumé

  • Les utilisateurs expriment leurs intentions de projection par la navigation.
  • Ils expriment leurs intentions de mutation par leurs périphériques.
  • Les mutations déclenchent des événements.
  • Les événements donnent lieu à des notifications.
  • Les notifications poussent l'utilisateur à demander de nouvelles projections ou mutations.
  • Ces mutations peuvent être automatisées via des réactions aux événements.

Take Away

  • Pas besoin d'être dogmatique ou puriste : adaptez le vocabulaire et les principes à votre sujet fonctionnel.
  • Un système transparent (on voit à travers) permet de bien identifier les stratégies de résilience possibles et la priorisation à leur donner.
  • CQRS est probablement miscible avec les intuitions et les processus déjà mis en place par vos utilisateurs, parlez-en ensemble.
  • Nommer les concepts qui participent fonctionnellement à la résilience permet de se libérer des spécificités des protocoles et des technologies.

Plus loin