Pourquoi avoir choisi d’utiliser l’architecture CQRS ?

Tiller

Tiller est une solution de caisse enregistreuse intelligente au service des restaurateurs et commerçants. L’objectif est d’aider les restaurateurs et commerçants à optimiser leur business en analysant les données de ventes sur une plateforme web de gestion.

Le backend de l’application est historiquement développé en PHP avec le framework Symfony. La croissance de Tiller nous a donc amenés à repenser notre plateforme pour répondre à 2 objectifs :

  • Supporter une croissance de plus de 2000 clients et de plus de 20 millions de requêtes par jour,
  • S’assurer de la fiabilité de nos données : nous ne pouvons pas nous permettre de perdre la moindre transaction.

C’est dans ce but que nous avons réécrit une partie de notre plateforme (en particulier la partie synchronisation des transactions) en utilisant l’architecture CQRS.

CQRS ?

Le CQRS (Command and Query Responsibility Segregation) est une architecture qui permet de séparer la lecture (Query) de l’écriture (Command). La partie écriture enregistre chaque modification, généralement sous forme d’évènement. Un traitement est ensuite opéré, souvent en asynchrone, afin de générer des modèles dénormalisés. La partie lecture requête simplement ces modèles afin de minimiser le requêtage de la base.

Schéma de l’architecture CQRS (sources: clever-age.com)

Domain Driven Design

Les commandes représentent simplement les actions de l’utilisateur (ex : j’ouvre une transaction, je rajoute un produit, je paie la transaction en espèce). Elles peuvent bien sûr être refusées par l’application selon les règles métier de l’application. Le code est écrit en utilisant les mêmes termes que le métier (domain). Il est donc plus simple à comprendre et à maintenir. Ces commandes, une fois validées par la couche métier, déclenchent un ou plusieurs évènements.

Évènementiel

Le CQRS s’adapte parfaitement à l’Event Sourcing.

Contrairement à une application de type CRUD (Create, Read, Update, Delete) qui enregistre l’état final de l’objet. L’évènementiel stocke les différentes étapes qui aboutissent à l’état final. Par exemple :

  • Une transaction est ouverte ;
  • Un produit est ajouté à la transaction ;
  • Un paiement est ajouté à la transaction ;
  • La transaction est clôturée.

Cette approche permet de tracer facilement toutes les modifications sur l’objet. Elle permet également de faciliter les synchronisations entre plusieurs appareils (on n’envoie que les évènements) et de garantir l’intégrité des données.

Asynchrone

Un des enjeux d’une API est de répondre le plus rapidement possible. Grâce au CQRS, il est aisé de rendre asynchrone certaines parties. Cette architecture permet d’enregistrer les commandes et de les traiter en différé à l’aide d’un CommandBus asynchrone. Par la suite, elle met à jour les modèles grâce à un EventBus asynchrone. De plus, en cas de panne technique d’un des services, elle permet de continuer à stocker toutes les commandes et de ne perdre aucune donnée. A la reprise du service, il suffira de rejouer toutes les commandes/évènements non traités.

CQRS Asynchrone

Microservices

Un des autres avantages de l’architecture CQRS est la possibilité de séparer les différentes couches : Interface (API ou front), CommandHandler et EventHandler. Encore mieux, chaque EventHandler peut être séparé. Elle permet donc d’avoir plusieurs microservices ultra spécialisés et optimisés. Chaque service peut utiliser la technologie la plus adaptée. Le code est segmenté : il devient plus léger et donc plus simple à maintenir.

Fiabilité des données

Toutes les modifications sont automatiquement stockées à deux endroits : CommandStore et EventStore. Ce processus nous garanti de ne perdre aucune donnée. Il est d’une grande aide pour analyser l’utilisation de votre application.

Limitations

Ce n’est pas la solution à tout

Le CQRS n’est pas la solution universelle. Il s’adapte parfaitement aux objets qui subissent des séquences d’opérations comme pour compte bancaire : “débit” et“crédit”. Il s’adapte moins bien aux objets contenant seulement de l’information comme la gestion de comptes utilisateurs.

Approche complexe

L’architecture CQRS est atypique et peut dérouter. Elle peut potentiellement ralentir en première approche à cause de la multitude de composants qu’elle utilise. En particulier, une équipe junior perdra du temps à s’accoutumer à sa complexité. Finalement, le manque de ressources (internet, livres) peut s’avérer problématique.

Mise en place

Ce changement a considérablement complexifié notre stack technique :

  • AWS Lambda + DynamoDB pour nos deux systèmes de queuing (Command Bus et Event Bus)
  • PHP / Symfony2 pour la brique + Broadway pour la partie Command Handler
  • NodeJS + Go pour la partie EventHandler
  • Swift pour la partie applicative (nous avons développé un pod CQRS)

L’infogérence d’une telle infrastructure s’avère particulièrement plus complexe que celle d’un bloc monolithique. C’est pour cela qu’il est impératif de rendre chaque service totalement indépendant des autres.

Conclusion

Le CQRS est une architecture qui sépare la partie lecture de la partie écriture. La partie écriture est basée sur de l’évènementiel. Elle est pensée pour être asynchrone. Du coup, on peut l’implémenter sous forme de microservices optimisés. Elle permet d’améliorer la fiabilité et la traçabilité des données grace à l’EventStore qui enregistre l’historique des modifications.

PS : Tu as lu jusque là ? 2 choix s’offrent à toi. Lâcher ton job ou postuler chez Tiller. RDV sur notre page de recrutement www.tillersystems.com/recrutement ou envoie ton CV à team@tillersystems.com.

Like what you read? Give Vincent Oliveira a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.