Architecture microservices, la solution pour éviter les pièges du monolithique?.

7 + 1 best practices pour en tirer pleinement les bénéfices.

Selon IDC, 9 nouvelles applications sur 10 utiliseront des architectures microservices d’ici 2022. Une proportion surement surestimée mais suffisamment représentative d’une tendance de fond en termes de développement pour que nous y consacrions ce sujet !Depuis la conception de ce type d’architectures par Netflix à une époque où le terme même de microservices n’existait pas encore (il a été popularisé en 2014), elle a été adoptée par les géants du numérique comme PayPal, eBay, Amazon, Uber, (etc.) et ne cesse depuis de se développer. Le principe est simple et largement inspiré du SOA (architecture orientée service) et, contrairement à une approche monolithique classique, elle repose sur un ensemble de services faiblement couplés qui communiquent les uns avec les autres via des API indépendantes du langage de programmation utilisé. L’intérêt est que chaque partie de votre système agit comme un module isolé qui gère un processus spécifique. Ainsi, avec une architecture microservices, vous êtes en mesure en théorie de mettre à jour ou de remplacer un service ou une fonctionnalité par une meilleure version, sans impacter les autres services.

Quels sont les principaux avantages d’une architecture microservices ?

  1. Plus de productivité. Les développements sont faits plus rapidement car ils sont concentrés sur la réalisation de petits modules qui peuvent être développés en parallèle.
  2. Time-to-market avec mise sur le marché très rapide de nouveaux services. On peut rajouter, mettre à jour ou changer des services existants sans impacter l’ensemble du système. Les mises en production de chaque nouvelle fonctionnalité sont plus rapides et comportent moins de risques car on n’a pas besoin de mettre à l’arrêt le système, ni de redéployer l’ensemble de l’application.
  3. Flexibilité technologique ! En fonction de vos ressources disponibles, de leurs compétences et des fonctionnalités attendues, ils peuvent développer leur nouveau microservice dans le langage qu’ils souhaitent, Java, Python, Javascript …
  4. Plus de qualité. La logique de modules indépendant des uns des autres permet d’identifier, d’isoler et de résoudre des bugs ou des défaillances bien plus rapidement que dans un système monolithique. Et surtout, un problème ou une défaillance sur un module en particulier ne met pas en danger le fonctionnement du système tout entier !
  5. Reusabilité. Certains modules qui supportent des processus récurrents peuvent être bien entendu réutilisables sur d’autres applications.

Les bénéfices sont de taille sur le papier. Mais en pratique, pour qu’ils tiennent leurs promesses, votre architecture en microservices doit être particulièrement bien pensée en amont, bien structurée et bien déployée. Voici nos 7 (+ 1 bonus) best practices.

#1. Le Domain-driven design, une conception basée sur le périmètre métier. 

Tout repose sur la capacité à diviser une application en petits modules autonomes pouvant être déployés de manière autonome et indépendante. Ne pas réussir à respecter ce principe de base revient à retomber dans les travers des systèmes monolithiques.

Souvent, en tant que professionnels du développement, nous avons tendance à nous concentrer sur la technologie, le code… et souvent, on en oublie le fonctionnel ! Or, dans une logique de microservices, la conception doit rester centrée sur le domaine métier qu’elle sert, l’objectif business.

La compréhension du métier et la logique associée sont centrales dans le développement de tout microservice. Dans ce type d’architecture, la conception logicielle est pilotée par le domaine et son abstraction qui en devient le modèle. Ainsi, les métiers et les équipes (architectes et développeurs) doivent collaborer ensemble dès la conception stratégique pour délimiter précisément le contexte, le langage, les sous-domaines et les cartes de contextes (Context Maps). Puis, décomposer le domaine en entités plus fines qui représentent les objets du domaine (attributs, identité, persistance dans le temps, comportements, agrégats, objets de valeur, etc.) dans chaque contexte ainsi limité. Il « ne vous reste plus » qu’à coupler vos modules de microservices pour obtenir votre application !

Pour approfondir ce sujet, quelques pistes de lecture :

#2. Les bases de données et les microservices

Un autre challenge à relever, et non des moindres, repose sur le choix en termes de base de données. Faut-il partager la base de données entre les microservices ou non ? Un choix cornélien sur lequel il convient de se pencher car les enjeux sont de taille. Effectivement, si le choix se porte sur le partage de la base de données entre les microservices, ceci mènera à l’instauration d’un fort couplage entre ces derniers … ce qui est en opposition avec le principe même de l’architecture microservices ! Les efforts de synchronisation et de communication resteraient conséquents, même pour une mise à jour ou une modification très minime dans la base de données.

A l’inverse, si chaque microservice dispose de sa propre base de données, les échanges de données entre microservices ouvrent la porte à d’autres problématiques. C’est pourtant en théorie un choix naturel pour les microservices qui utilisent un modèle de données différent pour chaque service. C’est ce qu’on appelle la persistance polygotte. Un service peut s’appuyer sur une base de données relationnelle, une autre sur une base de données tabulaire (Cassandra par ex) puis un autre sur une base clé-valeur pour les valeurs de référence, un autre sur un entrepôt type Document, etc. On peut également se retrouver dans un cas de figure où un service repose sur plusieurs bases de données.

Dans les faits, même s’il est entendu que chaque microservice devrait se limiter à une base de données, on constate que les choix d’une base de données partagée entre microservices est plus raisonnable en termes de coûts, coûts qui deviennent vites exponentiels si on doit supporter plusieurs technologies de bases de données. C’est pourquoi, les fournisseurs de bases de données (DataStaxCouchbase notamment) commencent à créer des bases de données multimodèle qui représentent une alternative intéressante, véritables plateformes de traitement de données, elles supportent plusieurs modèles de bases (relationnels, document, hiérarchiques et orientés objets, colonnes, etc.).

#3. La livraison continue (CI/CD)

L’une des caractéristiques clés de l’architecture microservices est l’indépendance de la déployabilité de chaque microservice. L’intérêt est que l’on peut modifier ou mettre à jour un microservice sans toucher aux autres. Un des principaux avantages des architectures microservices est l’accélération des cycles de mise en production.

Mais imagions que vous ayez des dizaines de microservices à déployer de manière indépendante ? Cela peut être tourner un cauchemar. Ainsi, il est indispensable d’adopter une organisation adaptée et un processus efficace en intégration / livraison continue (DevOps, CI/CD) et d’automatiser un maximum de tâches avant de vous lancer dans ce type de projet.

Migrer vers les microservices suppose une réorganisation des équipes et un changement de culture. En effet, vous aviez historiquement des équipes séparées qui collaboraient ensemble. Vous devez les réorganiser en cellules autonomes qui gèrent l’ensemble du cycle du microservice, du développement au déploiement et les faire gagner en agilité. Ainsi, chaque équipe peut générer et déployer ses propres services de manière autonome.

#4. La stack technologique

Ce principe d’architecture suppose que vous devez choisir le langage de programmation et le framework le mieux adapté à chaque microservice. Mais ce percept n’est pas sans conséquences ni exceptions ! Parfois, un microservice peut avoir besoin d’une nouvelle stack technique et nécessiter un langage de programmation comme C++/Rust pour des missions lourdes ou des exigences fortes en terme de performance du CPU. Si un microservice s’appuie sur du Machine Learning, Python peut s’avérer être le meilleur choix.

Mais attention, multiplier les langages de programmation et frameworks sans réelle nécessité n’apporte aucun bénéfice au final, bien au contraire. Imaginons un environnement technique où un microservice est développé en utilisant KotlinSpring BootPostgreSQL, et un autre avec ScalaPlay FrameworkVueJS et Oracle et le suivant avec JakartaEEJAVAMySQL et Angular ? Il peut certes y avoir de nombreux avantages …. Mais imaginer les efforts et les ressources qu’il va falloir fournir pour maintenir à jour ces différents langages de programmation, framework et autres bases de données ?

Certes, Les équipes peuvent choisir la technologie qui convient le mieux à leur service à l’aide de diverses piles technologiques et l’approche décentralisée de création de microservices a de nombreux avantages … mais cela demande de mettre en place une gouvernance rigoureuse pour que vous ne vous retrouviez pas avec pléthores de langages et de frameworks impossibles à gérer dans la durée. Nous vous conseillons chez Harington de mettre en place des standards à l’échelle de votre projet.

#5. La communication entre les microservices, point central

Avant de vous lancer dans les microservices, vous devez concevoir une architecture robuste qui permet de les orchestrer, les contrôler et de les faire évoluer car s’ils restent indépendants, ils n’en doivent pas moins travailler ensemble vers un but commun (Kubernetes est en ce sens une solution intéressante).

Si la communication est importante entre les équipes comme vu précédemment, il en est de même pour les microservices. Effectivement, l’une des décisions de conception la plus complexe à prendre au sujet d’une architecture en microservices, est la manière dont ses services vont communiquer et échanger entre eux. Tel les maillons d’une chaîne, chaque microservice échange des données et déclenche l’activité d’un autre microservice pour effectuer une mission.

L’API http REST synchrone peut paraitre une solution pragmatique à mettre en place à court terme. Le service A appelle le service B qui appelle le C et ainsi de suite. Cela suppose que B et C soient disponibles et les temps de latences s’additionnent… Et comme les microservices sont généralement des systèmes distribués, ils peuvent tomber en panne. Ainsi, dans le cas de microservices synchrones où les services sont fortement interdépendants entre eux, cela entraine inévitablement des défaillances en cascade. C’est le fameux effet domino.

Pour en optimiser leur fonctionnement, les microservices doivent pourvoir effectuer leurs traitements et remplir leurs missions propres, sans dépendre de la disponibilité d’autres services. Les microservices devraient communiquer entre eux de manière asynchrone via événements ou files d’attente des messages (Kafka, REST, ATOM). Cette « conversation » constante entraîne en effet une baisse des performances en raison de la latence du réseau et du temps nécessaire au traitement des messages. Si l’approche asynchrone est plus complexe, elle bénéficie d’une latence plus faible.

#6. Le frontend !

Il est courant de se retrouver dans un projet de microservices avec un back parfaitement modularisé … et un front monolithique. La raison est que la plupart des développeurs de backend ont une vision rétrospective du développement de frontend et le voient comme un développement plus « accessoire ». Et comme la plupart des architectes logiciels sont des développeurs de backend, ils nourrissent peu d’intérêt pour le frontend que se retrouve souvent négligé dans la conception de l’architecture.

Dans le meilleur des cas, ils développement le front avec des technologies de webcomponents (composants en HTML JS, CSS sous forme de librairies) ou des frameworkd based components (basés sur React, Angular ou Vue).

Si votre frontend est conçu avec une approche monolithique, on se retrouve avec les mêmes travers lorsqu’on doit le moderniser ! De la même manière, il convient de le découper en différents modules (ou composants) indépendants et réutilisables dans plusieurs applications afin de pouvoir les faire évoluer, les enrichir ou les mettre à jour indépendamment des différentes applications qui les utilisent. Pour exemple, les composants de sign-on, paiement ou de panier sont communs, il n’y aucune utilité à les redévelopper à chaque fois. Les équipes de développement n’ont plus qu’à intégrer ces composants (microfrontend) sans avoir à en maîtriser les domaines métiers. 

#7. Une organisation adaptée

Si une organisation a pour objectif de développer une architecture de microservices, elle doit adapter la taille de ses équipes en conséquence. Votre équipe doit être polyvalente. C’est-à-dire rassembler toutes les compétences en développement de frontend/backend, en test, en production… Le management doit lui aussi changer. Effectivement, l’architecture de microservice ne fonctionne que si l’organisation pour la supporter et la faire vivre est en place … et cela suppose une certaine décentralisation de la prise de décision.

#8. Se faire accompagner

Les architectures microservices font couler beaucoup d’encre et sont aussi un véritable bouillon d’innovations technologiques. Pourtant, elles ne sont pas adaptées à tous les projets. Ne foncez pas aveuglément  Tout le monde s’accorde aujourd’hui sur le fait que c’est une architecture intéressante et rentable lorsque votre système est devenu très lourd et qu’il se révèle impossible à maintenir et à faire évoluer. Si ce n’est pas le cas, une architecture monolithique conçue avec la bonne modularité est toujours d’actualité !

Si vous souhaitez construire une solution simple ou planifier un lancement rapide pour valider une idée ou un nouveau service, l’approche monolithique classique conviendra mieux à vos objectifs. À contrario, une architecture microservices est particulièrement adaptée aux grandes entreprises ou départements qui doivent fournir un grand nombre de services, qui ont besoin d’évoluer rapidement et de procéder régulièrement à des changements en fonction de l’évolution de leur écosystème concurrentiel. On retrouve beaucoup d’architectures microservices aujourd’hui dans le retail, dans la distribution et derrière des sites marchands e-commerce. 

L’avantage d’un système monolithique c’est qu’il est par nature simple à surveiller contrairement aux microservices. Avec une architecture microservices, vous avez des dizaines voire des centaines de modules dans des environnements différents et utilisant des langages, des API, des bases de données, des fichiers de configuration différents, etc.

Le support de votre application dans le temps n’est pas simple. Car si, en théorie un changement sur un micro-service n’est pas sensé impacter les autres, dans la pratique il n’est pas rare qu’une modification à un endroit nécessite des interventions sur plusieurs autres services pour qu’ils restent opérationnels. Une telle diversité rend le support de l’application délicat. Et oui, dans un monde idéal, les modifications apportées à un micro-service ne devraient pas avoir d’impact sur les autres composants indépendants. Pourtant, dans la pratique, une mise à jour à un endroit nécessite parfois la reconstruction de plusieurs services à la fois pour préserver leur compatibilité.

Pour conclure, il est fort à parier qu’architecture monolithique et microservices continueront à coexister comme le font SQL et No SQL.

Besoin de conseils, de ressources spécifiques ou de support pour mener votre projet, nous sommes vos côtés pour vous accompagner vers la meilleure solution pour vous.

Sources :

Partager l'article