Du monolithe aux microservices : quand franchir le pas
Les microservices ne sont pas un insigne de maturité. Voici comment savoir quand une scission est réellement rentable, ce qu'elle coûte vraiment et comment migrer sans tout casser.
Par Innovation T Team
À un moment donné, « nous passons aux microservices » est devenu une façon de signaler qu'une équipe avait mûri. Cela se passe rarement aussi proprement. Beaucoup d'équipes ont fait voler en éclats une application parfaitement saine en une dizaine de services, ont triplé leur charge opérationnelle et ont découvert que le problème d'origine n'avait jamais été l'architecture. La vraie question n'est pas « monolithe ou microservices ». C'est « qu'essayons-nous réellement de résoudre, et un système distribué est-il le moyen le moins coûteux d'y parvenir ».
Ce guide plaide pour un choix par défaut ennuyeux (commencer par un monolithe bien structuré), puis expose les signaux qui rendent une scission utile, les coûts dont personne ne vous prévient et un schéma de migration qui vous permet d'évoluer sans réécriture risquée.
Commencer par un monolithe modulaire
Pour la plupart des produits, la bonne première architecture est une application unique déployable dotée de frontières internes nettes. C'est le monolithe modulaire, et ce n'est pas un compromis. C'est un choix légitime à long terme.
À l'intérieur, votre code reste organisé autour de domaines métier : facturation, catalogue, comptes, notifications. Chaque module possède ses propres données et expose une interface claire aux autres, mais les modules communiquent par des appels de fonctions en processus, non par des requêtes réseau. Vous obtenez l'essentiel de la discipline de conception des microservices sans presque aucune de leur taxe opérationnelle.
Les avantages sont réels. Une seule base de code signifie un seul build, un seul déploiement, un seul endroit où regarder quand quelque chose casse. Un appel de fonction fonctionne ou lève une exception, si bien que vous ne déboguez jamais un flux à moitié terminé dispersé sur trois services. Refactoriser à travers les frontières est un renommage assisté par le compilateur, et les transactions sont simples parce que tout partage une seule base de données.
Point crucial, un monolithe modulaire propre garde vos options ouvertes. Lorsque vous tracez tôt des frontières nettes entre les modules, chacun d'eux peut être extrait plus tard dans son propre service avec bien moins de douleur. La discipline que vous investissez dans les frontières des modules est exactement celle qu'exigent les microservices, si bien que rien n'est perdu. Vous ne choisissez pas le monolithe pour toujours. Vous choisissez de reporter la distribution jusqu'à ce que vous ayez une raison concrète de la mettre en œuvre.
Les signaux qui justifient réellement une scission
Une scission se justifie par une pression organisationnelle et opérationnelle, non par l'esthétique. Assurez-vous d'observer plus d'un de ces signaux avant de vous engager.
Passage à l'échelle des équipes et coût de coordination. La raison la plus durable de scinder, ce sont les personnes. Lorsque plusieurs équipes contribuent toutes à la même base de code et se disputent le même pipeline de déploiement, chaque livraison devient une négociation, et la fonctionnalité inachevée d'une équipe bloque le correctif urgent d'une autre. Les services permettent à chaque équipe de posséder, déployer et faire évoluer sa partie selon son propre calendrier. Si vous avez une ou deux équipes, cette pression n'existe pas encore, et une scission ne vous aidera pas.
Un besoin de déploiement indépendant et fréquent. Lorsqu'une partie du système est livrée plusieurs fois par jour tandis qu'une autre change une fois par trimestre, les regrouper dans un seul déploiement crée des frictions. Un module de paiements qui ne doit jamais régresser ne veut pas être redéployé chaque fois que le texte marketing change. C'est un bénéfice réel, mais seulement si votre stratégie de tests et de retour arrière peut gérer de nombreux petits déploiements plutôt que quelques gros.
Des besoins de mise à l'échelle réellement divergents. Parfois, un composant est gourmand en CPU et grimpe à plusieurs fois sa charge normale lors d'une promotion, tandis que le reste de l'application reste inactif. Si vous ne pouvez pas faire évoluer ce chemin critique sans payer pour faire évoluer tout ce qui l'entoure, l'isoler comme un service peut en valoir la peine. Soyez honnête ici : les serveurs d'applications modernes et une bonne couche de cache résolvent bon nombre de problèmes de mise à l'échelle sans aucune scission. Scinder pour économiser du calcul n'en vaut la peine que lorsque la divergence est importante et persistante.
Isolation indépendante des pannes. Si une intégration tierce lente ou une tâche de fond emballée peut faire tomber toute votre application, extraire ce travail risqué dans son propre service peut contenir le rayon d'impact, surtout lorsque certaines parties du système ont des exigences de fiabilité très différentes.
Remarquez ce qui ne figure pas sur cette liste : « la base de code semble grosse », « nous voulons un autre langage pour une fonctionnalité » ou « une conférence a dit que les monolithes ne passent pas à l'échelle ». Ce ne sont pas des raisons. Ce sont des humeurs.
Les coûts que personne ne met dans la présentation
Chacun de ces bénéfices s'achète au prix d'un coût réel et récurrent. Avant de scinder, intégrez-les dans votre calcul.
Le réseau est désormais sur votre chemin critique. Dans un monolithe, un appel entre modules dure quelques nanosecondes et ne peut pas échouer tout seul. Entre services, ce même appel traverse un réseau lent, peu fiable et parfois hors service. Vous devez maintenant gérer les délais d'attente, les nouvelles tentatives, les défaillances partielles et les pannes en cascade. Une requête qui touche six services accumule six occasions d'échouer.
La cohérence des données devient difficile. Une base de données unique vous offre les transactions gratuitement. Dès que chaque service possède son propre magasin de données, vous perdez la capacité de mettre à jour plusieurs choses de manière atomique, et vous entrez dans le monde de la cohérence à terme, des sagas et des actions compensatoires. Faire concorder une commande, un décompte de stock et un paiement entre trois services sans transaction partagée est l'un des problèmes véritablement difficiles des systèmes distribués, et il est facile de se tromper subtilement.
L'observabilité devient un projet, pas un fichier de log. Dans un monolithe, une trace de pile vous raconte toute l'histoire. Dans un système distribué, une seule action utilisateur laisse des empreintes sur de nombreux services et machines. Sans traçage distribué, journalisation centralisée et identifiants de corrélation, le débogage devient de l'archéologie. Vous devez construire cette couche avant d'en avoir besoin, pas après le premier incident à 2 heures du matin.
La charge opérationnelle se multiplie. Chaque service a besoin de son propre pipeline, de son déploiement, de sa supervision, de ses alertes, de ses secrets et de son astreinte. Le développement local signifie désormais faire tourner une flotte de services ou la simuler, et la facture cloud grimpe. Si vous vous engagez dans cette direction, planifiez votre budget délibérément : notre guide d'optimisation des coûts cloud explique comment empêcher une empreinte multiservices de vider discrètement votre trésorerie.
Les contrats entre services se figent. Dans un monolithe, vous pouvez modifier une interface partagée et laisser le compilateur trouver chaque appelant. Entre services appartenant à des équipes différentes, ce même changement devient une négociation d'API versionnée avec une compatibilité ascendante à préserver. Bien concevoir ces interfaces compte énormément, il vaut donc la peine de lire notre guide sur comment concevoir des API que les développeurs adorent avant de figer la moindre frontière.
Migrer avec le figuier étrangleur, pas avec une réécriture
Si vous avez des signaux honnêtes et que vous avez chiffré les coûts, n'arrêtez pas tout pour une réécriture. Les réécritures d'un système qui fonctionne sont la façon dont les entreprises perdent un an et ne livrent rien. Utilisez plutôt le motif du figuier étrangleur.
Le nom vient d'une liane qui pousse autour d'un arbre hôte, s'appropriant peu à peu sa structure jusqu'à ce que l'original puisse être retiré. Appliqué au logiciel, cela signifie que vous faites croître la nouvelle architecture autour de l'ancienne, une pièce à la fois, pendant que le système continue de tourner.
En pratique, vous placez une couche de routage, généralement une passerelle API ou une façade, devant le monolithe afin que les appelants ne sachent ni ne se soucient de ce qui se trouve derrière. Vous choisissez une capacité bien délimitée, l'extrayez dans un nouveau service et redirigez discrètement son trafic par la passerelle. Le monolithe se réduit d'une responsabilité. Vous vérifiez, vous stabilisez, et seulement alors vous choisissez la pièce suivante. Au fil de nombreuses étapes petites et réversibles, le monolithe est étranglé jusqu'à disparaître, ou jusqu'au noyau qu'il est judicieux de conserver.
La force de cette approche est que chaque étape est livrée en production et peut être annulée indépendamment. Vous n'êtes jamais à un seul grand basculement de la catastrophe, et vous pouvez vous arrêter à tout moment si le monolithe restant s'avère parfaitement satisfaisant.
Tracer les frontières autour des domaines, pas des couches
La décision la plus importante est de savoir où placer les coutures, et l'erreur la plus courante est de découper le long des couches techniques : un « service de base de données », un « service de logique métier », un « service d'interface ». Cela crée des services incapables de faire quoi que ce soit d'utile seuls et qui doivent bavarder sans cesse pour accomplir la moindre tâche réelle. Vous obtenez tout le coût de la distribution et aucune indépendance.
Découpez plutôt le long des domaines métier. Un service doit posséder une capacité complète de bout en bout, y compris ses propres données. « Commande », « facturation » et « stock » sont de bonnes frontières parce que chacune représente quelque chose que l'entreprise fait réellement. Un service bien tracé peut modifier ses entrailles, son schéma et sa logique sans demander la permission, parce que rien à l'extérieur n'en dépend.
Une bonne frontière est celle où les interactions sont massives plutôt que bavardes (quelques appels significatifs, pas des centaines de minuscules), où les données se regroupent naturellement d'un côté de la ligne, et où une seule équipe peut posséder l'ensemble. Si deux « services » mettent constamment à jour les données l'un de l'autre d'un même souffle, ils ne sont en réalité qu'un seul service scindé au mauvais endroit.
Liste de vérification de préparation
Avant d'extraire votre premier service, vous devriez pouvoir répondre oui à la plupart de ces points.
- Vous avez un signal concret (passage à l'échelle des équipes, déploiements indépendants ou mise à l'échelle divergente), pas seulement l'impression que le monolithe est gros.
- Votre monolithe est déjà modulaire, avec des frontières nettes le long desquelles découper.
- Vous disposez d'une intégration et d'une livraison continues matures, de sorte que livrer de nombreux petits déploiements est routinier et non risqué.
- Vous avez en place une journalisation centralisée, des métriques et un traçage distribué, ou un plan ferme pour les ajouter d'abord.
- Vous avez une approche d'infrastructure (conteneurs, orchestration, provisionnement automatisé) qui rend peu coûteuse la mise en place d'un nouveau service.
- Vous avez un plan pour la cohérence des données entre services et savez quels flux nécessiteront une cohérence à terme.
- Les équipes sont structurées pour posséder les services de bout en bout, y compris leurs données et leur astreinte.
- Vous avez chiffré le coût opérationnel et cloud continu, et l'entreprise l'accepte.
Si la plupart de ces réponses sont non, le travail le plus rentable n'est pas de scinder. C'est d'abord de ranger le monolithe modulaire et de développer les muscles opérationnels.
Anti-modèles à éviter
Le monolithe distribué. Des services qui doivent tous être déployés ensemble, au pas cadencé, partagent une base de données et échouent comme un seul. Vous avez payé le plein prix de la distribution tout en conservant tous les inconvénients du monolithe. C'est le pire des deux mondes et de loin l'échec le plus courant.
Scinder pour corriger la qualité du code. Un mauvais code ne s'améliore pas en étant réparti sur un réseau. Une logique enchevêtrée devient une logique enchevêtrée avec de la latence et des nouvelles tentatives greffées dessus. Nettoyez d'abord le code à l'intérieur du monolithe.
Les nano-services. Des frontières si fines qu'une seule action utilisateur se disperse sur une dizaine de services. La surcharge de coordination submerge tout bénéfice, et personne ne peut tenir le système dans sa tête.
Une base de données partagée derrière plusieurs services. Si plusieurs services lisent et écrivent dans les mêmes tables, ils sont soudés l'un à l'autre. Un seul changement de schéma casse tout le monde, et vous n'avez d'indépendance que de nom.
Réécrire au lieu d'étrangler. Geler le travail sur les fonctionnalités pour tout reconstruire à partir de zéro. L'ancien système continue d'évoluer pendant que vous reconstruisez, la cible bouge et le projet dérape. Faites plutôt croître le nouveau autour de l'ancien.
La conclusion pragmatique
Les microservices sont un outil pour un ensemble précis de problèmes, principalement l'échelle organisationnelle et le déploiement indépendant, et ils résolvent ces problèmes en échangeant la simplicité contre l'autonomie. Cet échange vaut la peine lorsque vous avez les personnes, la pression et la maturité opérationnelle pour en absorber le coût. C'est un mauvais échange lorsque vous courez après une tendance ou masquez un code désordonné. Commencez modulaire, restez honnête sur vos signaux, migrez avec le figuier étrangleur, et tracez vos frontières autour des domaines plutôt que des couches.
Si vous pesez cette décision et souhaitez un second avis lucide, c'est exactement le genre de problème que nous aidons les équipes à résoudre. Découvrez nos services d'ingénierie logicielle et cloud, ou contactez-nous pour discuter de votre architecture avec l'équipe Innovation T.
Prêt à construire avec Innovation T ?
Qu'il s'agisse de sécurité, de croissance ou d'ingénierie, notre équipe peut vous aider à livrer dans les meilleures conditions.