Monolithe ou microservices ? Les avantages du monolithe au lancement d'un produit
Que change un découpage en microservices lorsqu’un produit démarre, et comment savoir si une séparation devient utile ?
Découper avant de connaître la charge
Au lancement, on connaît les premières fonctions à construire, mais rarement celles qui absorberont le plus de trafic, coûteront cher à exécuter ou devront évoluer à leur propre rythme. Un monolithe les réunit dans une application à livrer ; les microservices les répartissent en applications autonomes. Ce second choix oblige à décider tout de suite où passent les frontières et quelles données appartiennent à chacun. Sans usage ni mesures, ces décisions reposent surtout sur des hypothèses.
Entre deux modules d’une même application, un appel reste local. Entre deux services, il traverse le réseau et peut échouer alors que chacun fonctionne correctement. Il faut prévoir les délais, les reprises, les formats d’échange et la cohabitation de plusieurs versions. Les données posent une autre question : si chaque service possède les siennes, comment les maintenir cohérentes ? Ces contraintes existent dès le premier jour, même quand le produit n’a encore que peu d’utilisateurs.
La possibilité de déployer ou de dimensionner une fonction indépendamment peut être précieuse. Mais pour en profiter, il faut savoir quelle fonction a réellement besoin de cette autonomie. Tant que ce point n’est pas établi, l’architecture distribuée augmente la complexité technique sans résoudre de limite identifiée.
Git et CI/CD quand les services se multiplient
Dans une application unique, une évolution qui touche plusieurs modules peut tenir dans une même branche et une même pull request. La revue suit le changement dans son ensemble, et une seule version contient tout ce qui doit partir en production. Si le code est réparti entre plusieurs dépôts Git, cette évolution peut demander plusieurs branches et plusieurs validations. Il faut savoir quelles pull requests vont ensemble et éviter qu’une moitié du changement soit livrée seule.
Un dépôt unique n’efface pas tout : des microservices peuvent y cohabiter, mais leurs versions continuent de vivre séparément. La CI/CD, qui automatise les tests et les déploiements, doit vérifier autre chose que chaque service pris isolément. Une validation réussie pour chacun ne prouve pas que le parcours complet fonctionne avec les versions réellement en production. Il faut tester les contrats entre services et conserver la compatibilité lorsqu’un service est mis à jour avant un autre.
Le déploiement doit ensuite tenir compte de l’ordre des mises en production et du retour arrière. Revenir à une version précédente peut laisser le service voisin avec un format de données qu’il ne comprend plus. Pour développer et tester localement, il faut lancer les bons services dans des versions cohérentes. En production, diagnostiquer un incident suppose de suivre une demande dans plusieurs journaux et de distinguer une erreur métier d’un appel réseau perdu. Cela réclame de la supervision, des alertes et des procédures de reprise. L’automatisation réduit l’effort répétitif, mais il faut d’abord la construire et l’entretenir.
Tout cela alourdit le temps de développement, l’exploitation et la facture d’infrastructure avant que le produit ne tire avantage de déploiements indépendants.
Prévoir les frontières dans le code
Un monolithe n’oblige pas à entasser les responsabilités. On peut regrouper le code par fonction du produit, donner à chaque module une interface claire et éviter que l’un écrive directement dans les tables de l’autre. Les tests vérifient les règles de chaque module, puis les parcours qui les relient. Cette discipline rend les dépendances visibles sans ajouter de réseau entre les fonctions.
Les modules sont livrés ensemble. Cela facilite une modification qui traverse plusieurs responsabilités, tout en permettant de revoir leurs frontières à mesure que le produit prend forme. Une transaction locale reste disponible lorsque plusieurs opérations doivent être cohérentes dans une même base ; avec des services séparés, cette cohérence demanderait un autre mécanisme.
Si un module doit un jour sortir de l’application, son rôle sera déjà plus facile à cerner. Il faudra malgré tout lui confier ses données, définir ses échanges à distance et prévoir les pannes propres à cette nouvelle frontière. Le découpage du code prépare ce travail, sans obliger à le faire avant d’en avoir besoin.
Mesurer avant de séparer
Une application lente ne demande pas automatiquement un nouveau service. On commence par chercher le goulot d’étranglement : temps de réponse, charge du processeur et de la mémoire, contention sur la base, coût de l’infrastructure. Une requête mal conçue restera lente derrière une API distincte si elle continue à solliciter la même base. Un index, du cache, un traitement en arrière-plan ou davantage de ressources pour l’application entière peuvent parfois suffire.
Une extraction devient intéressante lorsqu’une fonction conserve un profil de charge très différent, a besoin d’un déploiement indépendant ou oblige à surdimensionner tout le monolithe pour elle seule. La décision part alors d’un objectif précis : améliorer un temps de réponse, absorber un volume connu ou réduire un coût mesuré. Ce gain doit être comparé aux données à synchroniser, aux tests entre services et à l’exploitation supplémentaire.
Sur une boutique en ligne, la recherche de produits finit par ralentir les commandes pendant les pics de trafic. Les mesures le confirment, même après l’optimisation des requêtes et l’ajout d’un cache. Lui consacrer un service et des ressources propres devient alors utile pour préserver le passage en caisse ; il faudra aussi maintenir son catalogue à jour.
Garder la décision ouverte
Il peut exister dès le départ une contrainte technique vérifiée : une charge déjà observée sur un produit repris, ou un traitement qui exige un matériel particulier. Dans ces cas, construire une frontière tôt se défend. Sans signal de ce genre, une application bien structurée permet de livrer et d’apprendre sans financer tout de suite l’exploitation de plusieurs services.
Chez Kairisio, nous gardons cette décision ouverte aussi longtemps que les faits le permettent. Les cycles courts et les livraisons régulières aident à mesurer l’usage du produit, puis à investir dans la partie qui en a réellement besoin. Le développement et l’automatisation suivent alors une contrainte précise, plutôt qu’une architecture dessinée pour un trafic imaginaire.
Pour poursuivre la lecture
Martin Fowler discute cette approche dans Monolith First, avec ses avantages, ses limites et les difficultés d’un découpage trop précoce.
Son article Microservice Prerequisites détaille les capacités de déploiement et de supervision nécessaires pour exploiter plusieurs services.
La documentation d’architecture de Microsoft aborde aussi la propriété et la cohérence des données entre services, un point à examiner avant toute extraction.
