Microservices vs monolithe : comment décider en 2026
Le critère décisif n’est pas technique, il est organisationnel. Loi de Conway, monolithe modulaire, coût réel du distribué, strangler fig et grille de décision : de quoi trancher sans idéologie.

La question n’est pas celle que vous croyez
Le débat oppose deux architectures. La décision, elle, porte rarement sur l’architecture. Elle porte sur le nombre d’équipes qui doivent livrer sans se coordonner, sur ce que votre organisation sait diagnostiquer à trois heures du matin, et sur la vitesse à laquelle vous devez pouvoir changer d’avis.
Cet article ne défend ni le monolithe ni les microservices. Il propose une grille de décision et, surtout, il rend explicite le prix de chaque option — y compris celui qui n’apparaît sur aucun devis : l’astreinte, l’observabilité, les tests de contrat et la coordination inter-équipes.
Une précaution de méthode avant d’entrer dans le sujet. Un découpage se juge sur trois ans, pas sur le sprint de mise en place. Les bénéfices du distribué arrivent tard, quand plusieurs équipes livrent en parallèle sans se bloquer. Les coûts, eux, arrivent dès la première mise en production. Toute comparaison qui ignore ce décalage de calendrier donne une réponse fausse.
Le vrai critère est organisationnel, pas technique
Melvin Conway l’a formulé en 1968 : une organisation qui conçoit un système produit une architecture qui reproduit sa structure de communication. Cinquante ans plus tard, c’est toujours le meilleur prédicteur du découpage réel — pas du découpage dessiné sur le schéma, mais de celui qui existera au bout de dix-huit mois.
La conséquence pratique est directe : découper le logiciel sans découper l’organisation ne produit pas des microservices, cela produit un monolithe distribué. Les équipes continuent de se coordonner pour chaque livraison, mais avec en plus des appels réseau, des versions d’API et des environnements d’intégration à synchroniser.
Avant de parler de services, répondez honnêtement à ces questions :
- Combien d’équipes doivent pouvoir livrer en production le même jour sans se parler ?
- Chaque équipe pressentie possède-t-elle sa verticale complète : code, base de données, déploiement, astreinte ?
- Qui arbitre quand deux équipes veulent modifier la même frontière métier ?
- Les frontières de domaine sont-elles stabilisées, ou encore en discussion ?
Si le découpage cible ne correspond à aucune frontière d’équipe réelle, il ne survivra pas. Une équipe unique qui maintient sept services paie tous les coûts du distribué sans en toucher le bénéfice principal, qui est l’autonomie de livraison.
Ce que nous avons observé sur un périmètre multi-marques
Sur le périmètre front de SFR — espace client, identité et boutique en ligne — quatre marques cohabitaient : SFR, RED by SFR, RMC et BFM, sans cible d’architecture commune. Notre mission a consisté à auditer les applications du périmètre, formuler des recommandations d’architecture, puis concevoir et mettre en œuvre une nouvelle chaîne CI/CD reprise par les équipes de développement.
Le point à retenir pour ce sujet : l’unification s’est jouée sur la chaîne de livraison partagée, pas sur un découpage runtime supplémentaire. Quand plusieurs marques divergent, le premier levier n’est presque jamais « plus de services ». C’est un chemin de build, de test et de déploiement commun, qui rend ensuite tous les autres arbitrages possibles.
Le monolithe modulaire comme défaut raisonnable
Le monolithe modulaire n’est pas un compromis mou. C’est le choix qui préserve le plus longtemps possible votre capacité à changer d’avis : un seul déployable, mais des frontières internes traitées avec la même rigueur que des frontières réseau.
src/
├── modules/
│ ├── orders/
│ │ ├── api/ // contrat public du module
│ │ ├── domain/ // logique métier, non exportée
│ │ ├── infra/ // persistance, messaging
│ │ └── OrderModule
│ ├── inventory/
│ │ ├── api/
│ │ ├── domain/
│ │ ├── infra/
│ │ └── InventoryModule
│ └── payments/
│ └── ...
├── shared/ // strictement minimal
└── Application
Trois règles font la différence entre un monolithe modulaire et un monolithe simplement bien rangé :
- Un contrat public explicite par module. Le reste est invisible depuis l’extérieur. La visibilité du langage (packages, modules, exports) sert à cela.
- Un schéma de base de données par module. Pas de jointure directe entre schémas. La donnée d’un autre module s’obtient par son API ou par un événement.
- Une règle vérifiée en intégration continue. Un test d’architecture — ArchUnit dans l’écosystème Java, un contrôle du graphe de dépendances ailleurs — qui échoue le build quand quelqu’un traverse une frontière.
Sans le troisième point, les deux premiers s’érodent en quelques mois. Une frontière qui n’est pas vérifiée automatiquement n’est pas une frontière, c’est une convention.
L’avantage économique est simple à formuler : dans un monolithe modulaire, se tromper de frontière coûte un refactoring et une compilation. Entre deux services déployés séparément, la même erreur coûte une migration de données, une API versionnée, une phase de double écriture et une coordination entre équipes. C’est le même geste, avec deux ordres de grandeur d’écart.
Quand découper vraiment
Certaines contraintes justifient pleinement des déploiements séparés. Elles ont un point commun : elles sont mesurables et elles étaient connues avant l’architecture.
- Un profil de charge qui décroche. Un composant dont la charge varie d’un ordre de grandeur par rapport au reste, et dont le dimensionnement uniforme coûte trop cher ou dégrade les autres fonctions.
- Une exigence de disponibilité différenciée. Quand un incident sur une fonction annexe ne doit en aucun cas emporter le cœur du service, l’isolation du rayon d’impact devient un besoin, pas une préférence.
- Une cadence de release imposée de l’extérieur. Une contrainte réglementaire ou un calendrier partenaire qui impose un rythme incompatible avec celui du reste du produit.
- Une autonomie d’équipe réelle. Une équipe qui possède son domaine de bout en bout, jusqu’à l’astreinte, et que la file d’attente de livraison commune ralentit objectivement.
- Une contrainte technologique irréductible. Un runtime, une bibliothèque ou un modèle d’exécution incompatible avec la stack principale — et non un simple goût d’équipe.
Une contrainte écrite avant l’architecture
Sur la plateforme France Travail, conçue et développée pour le Ministère du Travail, la contrainte dominante était posée dès le départ : la charge de pointe et l’obligation de service public. Ce n’était pas un objectif de confort, c’était le cadre. L’architecture retenue s’appuie sur Kubernetes et OpenShift, avec Java, Spring Boot, Angular et PostgreSQL. La plateforme sert plus de 100 000 utilisateurs actifs — demandeurs d’emploi et conseillers — avec 99,9 % de disponibilité et un temps de traitement réduit de 60 %.
Ce qui compte dans cet exemple n’est pas le nombre de composants. C’est l’ordre des décisions : l’exigence de charge et de disponibilité a été écrite en premier, elle était chiffrée, et l’investissement en orchestration a été justifié par elle. Quand cet ordre est inversé — la plateforme d’abord, la justification ensuite — le coût reste, la contrainte n’existe pas.
À l’inverse, voici les motifs qui ne suffisent pas : « le monolithe est devenu illisible » (un code mal structuré donne des services mal structurés, plus le réseau), « cela facilitera le recrutement », « nous voulons faire du Kubernetes », « c’est ce que font les grandes plateformes ». Aucun de ces quatre arguments ne survit à la question : quelle contrainte mesurable disparaît après le découpage ?
Le coût caché du distribué
Le distribué ne supprime pas la complexité, il la déplace du code vers l’exploitation. Voici les postes que nous voyons systématiquement sous-estimés au moment du cadrage.
Observabilité
Dans un monolithe, une stack trace suffit souvent. Dans un système distribué, elle ne dit plus rien : il faut du tracing distribué, une propagation de contexte homogène, des identifiants de corrélation présents dans chaque log et une politique d’échantillonnage. C’est un chantier à part entière, avec un coût de stockage et de cardinalité qui grimpe vite. Il doit être livré avant le premier service extrait, pas après le premier incident.
Transactions
La transaction ACID s’arrête à la frontière du service. Ce qui était un rollback devient une saga, avec des étapes de compensation, un pattern outbox pour ne pas perdre d’événement, et de l’idempotence sur chaque consommateur. Surtout, cela devient une question métier : quelqu’un doit décider ce que voit l’utilisateur pendant l’état intermédiaire, et ce qui se passe quand la compensation échoue. Cette discussion n’est pas technique et elle ne peut pas être esquivée.
Tests de contrat
Sans contrats vérifiés — des tests de contrat pilotés par le consommateur, avec un outil comme Pact ou un équivalent — chaque évolution d’API se valide dans un environnement d’intégration commun. Cet environnement devient alors le goulot d’étranglement que le découpage était censé supprimer. On retrouve la file d’attente de livraison, en plus lente.
Latence et défaillance partielle
Chaque appel synchrone ajoute de la latence et un mode de panne. Les latences ne s’additionnent pas seulement en moyenne : le P99 d’une chaîne d’appels se dégrade bien plus vite que celui de chaque maillon. Il faut donc des délais d’attente explicites, des reprises avec temporisation, des disjoncteurs et une gestion de la contre-pression. Une chaîne de cinq appels synchrones sur un chemin critique est un signal d’alerte, pas une architecture.
Astreinte et propriété
C’est le poste le plus souvent oublié au cadrage, et le plus douloureux ensuite. Notre règle de travail est simple : un nouveau service arrive avec son runbook, ses objectifs de niveau de service et le nom de l’équipe qui prend l’astreinte. Si l’une des trois cases reste vide, le service n’est pas prêt à exister.
Sortir progressivement : le strangler fig
Quand le découpage est justifié, la réécriture complète reste le pire chemin : elle gèle les évolutions métier pendant des mois et fait porter tout le risque sur une seule bascule. Le pattern strangler fig, décrit par Martin Fowler, extrait le système par tranches en gardant l’ancien en production.
- Placer une façade devant l’existant. Une passerelle ou un reverse proxy qui capte le trafic et permettra de router fonction par fonction, sans que l’appelant le sache.
- Choisir la première tranche pour ce qu’elle enseigne. Une frontière métier nette, peu d’écritures partagées avec le reste, une douleur mesurable. La première extraction sert autant à valider l’outillage — observabilité, contrats, déploiement — qu’à livrer de la valeur.
- Déplacer les lectures avant les écritures. Une lecture mal placée se corrige en changeant une route. Une écriture mal placée se corrige en réconciliant des données.
- Traiter la donnée comme le vrai sujet. C’est là que les migrations échouent. Un seul écrivain à la fois, une synchronisation explicite pendant la transition — capture de changements ou outbox — puis coupure du lien. Deux écrivains sur la même table pendant plusieurs mois, c’est une réconciliation manuelle garantie.
- Supprimer l’ancien code, avec une date. Une extraction sans critère d’arrêt produit un doublon permanent : deux implémentations, deux jeux de bugs, et une équipe qui maintient les deux. La suppression du chemin historique fait partie du périmètre, pas du « plus tard ».
Une extraction réussie se reconnaît à un détail : le nombre de lignes du système historique a baissé. Si le total augmente des deux côtés, la migration n’a pas commencé, elle s’est ajoutée.
Les signaux qui disent qu’on a découpé trop tôt
Ces symptômes sont faciles à observer et ne demandent aucun audit. S’ils sont plusieurs à être présents, le découpage est en avance sur l’organisation.
- Deux services sont toujours déployés ensemble. C’est la définition opérationnelle du monolithe distribué.
- Une fonctionnalité banale demande de modifier quatre dépôts et d’ouvrir trois demandes de fusion coordonnées.
- Une bibliothèque partagée dont la montée de version impose un redéploiement de tous les services. La dépendance de build a remplacé la dépendance de code, sans rien découpler.
- Plusieurs services lisent directement la même table. La frontière est dessinée dans le code, pas dans la donnée.
- Personne ne fait tourner l’ensemble en local, et le diagnostic d’un bug commence par « dans quel service ? ».
- L’environnement d’intégration est devenu une ressource que l’on réserve.
- Le temps passé en réunions de coordination a augmenté depuis le découpage.
Le remède n’est pas une honte. Refusionner deux services trop couplés est une décision d’architecture normale, et généralement peu coûteuse quand elle est prise tôt. Ce qui coûte cher, c’est de conserver un découpage dont plus personne ne défend la justification, parce que revenir en arrière serait perçu comme un aveu.
Une grille de décision honnête
Aucune de ces lignes ne tranche seule. Lisez-les ensemble, et regardez de quel côté penche la majorité.
| Question | Plutôt monolithe modulaire | Plutôt découpage |
|---|---|---|
| Équipes sur le périmètre | 1 à 3, périmètres qui se chevauchent | 4 et plus, périmètres distincts et stables |
| Astreinte | Une seule équipe pour tout | Chaque équipe sur son propre service |
| Frontières métier | Encore en discussion | Stabilisées et documentées |
| Profil de charge | Homogène sur l’ensemble | Un composant décroche d’un ordre de grandeur |
| Disponibilité attendue | La même partout | Différenciée, isolation du rayon d’impact requise |
| Cadence de release | Une seule feuille de route | Imposée de l’extérieur, divergente |
| Maturité plateforme | CI/CD et logs centralisés | Orchestration, tracing distribué, SLO par service |
| Cohérence des données | Transactions locales nécessaires | Cohérence à terme acceptée par le métier |
| Coût d’une erreur de frontière | Un refactoring | Une migration de données et une API versionnée |
Une lecture majoritairement à gauche ne signifie pas « jamais de services ». Elle signifie : pas maintenant, et surtout pas partout. Notre position en mission est constante — garder le découpage réversible aussi longtemps que possible, poser les frontières dans le code avant de les poser dans le réseau, et n’extraire un service que lorsqu’on peut nommer la contrainte mesurable qui disparaît une fois l’extraction faite.
Si vous devez arbitrer sur ce sujet, nous documentons ce type de décision en ADR défendables par vos équipes sans nous : voir notre expertise architecture logicielle, ou décrivez-nous la décision devant vous via la page contact. Un cadrage de 45 minutes suffit généralement à savoir si le sujet est un problème de découpage ou un problème de chaîne de livraison.
FAQ
Questions fréquentes
Les grandes plateformes fonctionnent en microservices, pourquoi pas nous ?
Parce que leur contrainte n’est pas la vôtre. Ces organisations comptent des centaines d’équipes autonomes et des équipes plateforme dédiées à l’observabilité, au déploiement et à l’outillage interne. Le découpage y résout un problème de coordination à grande échelle. Sans cette échelle organisationnelle, vous héritez des coûts sans le bénéfice.
Un monolithe modulaire, n’est-ce pas juste un monolithe bien rangé qu’on renomme ?
La différence tient à un point vérifiable : les frontières sont contrôlées automatiquement en intégration continue et le build échoue quand on les traverse. Ajoutez un schéma de base par module et un contrat public explicite, et vous obtenez une structure extractible service par service. Sans ces trois éléments, c’est effectivement un monolithe classique.
Combien de services faut-il viser ?
Aucun nombre cible n’a de sens. Le nombre de services devrait découler du nombre d’équipes autonomes et des contraintes de charge ou de disponibilité réellement différenciées. Un service qui n’a ni propriétaire identifié, ni runbook, ni objectif de niveau de service propre n’a pas de raison d’exister séparément.
Peut-on revenir en arrière après avoir découpé ?
Oui, et c’est parfois la bonne décision. Refusionner deux services systématiquement déployés ensemble supprime du réseau, de la latence et de la coordination sans rien retirer au produit. L’opération est d’autant moins coûteuse qu’elle est décidée tôt, avant que les deux bases de données aient divergé.
Faut-il Kubernetes pour faire des microservices ?
Pas obligatoirement, mais il faut un équivalent fonctionnel : déploiement automatisé, découverte de services, gestion des configurations et des secrets, observabilité centralisée. L’inverse est en revanche un piège fréquent — disposer d’un orchestrateur ne justifie pas de découper une application qui n’en a pas besoin.
Quel est le bon premier service à extraire ?
Celui qui combine une frontière métier nette, peu d’écritures partagées avec le reste du système et une douleur mesurable — coût d’infrastructure, temps de livraison ou incidents récurrents. La première extraction sert aussi à valider votre outillage de tracing, de contrats et de déploiement : choisissez-la assez significative pour être instructive, assez isolée pour être réversible.