Tout le monde veut des microservices. C'est le marqueur de modernité. On lit les articles sur Netflix et son architecture à 500 services, on regarde les talks de conférence sur la résilience distribuée, et on se dit : nous aussi. Sauf que Netflix a 10 000 ingénieurs et vous en avez 8. Et la plupart des équipes qui se précipitent vers les microservices ne fuient pas un problème de monolithe — elles fuient un problème d'organisation qu'elles projettent sur l'architecture.

Je vais être direct : 80% des équipes qui font des microservices ne devraient pas en faire. Pas parce que les microservices sont mauvais. Parce qu'ils ne résolvent pas le problème que ces équipes pensent résoudre, et qu'ils en créent d'autres, pires, que personne n'anticipe.

L'illusion de l'herbe plus verte

Le monolithe a un problème : tout est couplé. Un changement dans le module de facturation peut casser l'authentification. Les tests prennent 40 minutes. Le déploiement est un acte de courage. Donc on se dit : si on sépare en services, chaque équipe pourra déployer indépendamment, tester indépendamment, avancer indépendamment. Problème résolu.

Sauf que. Le couplage ne disparaît pas. Il se déplace. Dans un monolithe, le couplage est dans le code — un import, un appel de fonction, une shared dependency. Dans les microservices, le couplage est dans le réseau — un appel HTTP, un message Kafka, un contrat d'API. Et le couplage réseau est pire que le couplage code, parce qu'il est invisible, asynchrone, et qu'il peut échouer de 47 façons différentes.

Un appel de fonction échoue de trois façons : il réussit, il lève une exception, ou il ne retourne pas. Un appel réseau échoue de façons que vous n'imaginez pas : DNS qui ne résout plus, connection reset, timeout partiel, réponse lente mais valide, circuit breaker ouvert, retry qui double les effets de bord, ordre des messages inversé. Le distributed computing est un monde où "ça marche" est un état temporaire et improbable.

Le cauchemar du distributed tracing

Dans un monolithe, quand une requête est lente, vous lancez un profiler. Vous voyez la stack trace. Vous trouvez la fonction lente. Fin de l'histoire.

Dans un système distribué, une requête utilisateur traverse 7 services. Le service A appelle B, qui appelle C et D en parallèle, D appelle E, qui appelle B à nouveau (oui, il y a une boucle). La requête met 4 secondes. Où est le problème ?

Sans distributed tracing — Jaeger, Zipkin, OpenTelemetry — vous êtes aveugle. Et le distributed tracing n'est pas gratuit : il faut instrumenter chaque service, propager les trace headers, corréler les spans, stocker les traces, les indexer, les requêter. C'est une infrastructure complète, juste pour pouvoir répondre à la question "où est le problème ?". Question que le monolithe répondait avec un profiler gratuit.

Combien d'équipes que je vois avec "microservices" n'ont aucun tracing distribué ? La majorité. Elles ont remplacé un problème simple (trouver une fonction lente) par un problème impossible (trouver une fonction lente à travers 7 services sans tracing). Bravo.

Les partial failures : l'enfer que personne ne mentionne

Dans un monolithe, une opération réussit ou échoue. Transaction, rollback, fini. Dans un système distribué, une opération peut partiellement réussir. Le service A débite le compte. Le service B, qui doit créditer l'autre compte, est down. L'argent a disparu. Non, il n'a pas disparu — il est dans un état intermédiaire que personne ne peut voir. Mais pour l'utilisateur, il a disparu.

Les solutions à ce problème existent : Saga pattern, outbox pattern, eventual consistency, idempotency keys. Mais chaque solution ajoute de la complexité. Et chaque service supplémentaire multiplie les scénarios de partial failure. Un système à 3 services a peut-être 10 scénarios de failure intéressants. Un système à 30 services en a des centaines. Les testez-vous tous ? Bien sûr que non. Personne ne le fait. C'est pourquoi la production est pleine de bugs que personne n'a anticipés.

Le coût d'un appel réseau vs un appel de fonction

Un appel de fonction : nanosecondes, en mémoire, sans sérialisation. Un appel réseau entre services : millisecondes, avec sérialisation JSON (ou protobuf, si vous êtes sophistiqués), avec TCP handshake, avec TLS, avec retry logic. Le rapport est de 1 à 10000.

Ça ne veut pas dire que les microservices sont lents. Ça veut dire que vous ne pouvez pas faire la même chose avec. Un monolithe peut faire 100 appels de fonction pour traiter une requête sans que personne ne le remarque. Un système distribué qui fait 100 appels réseau pour une requête est un système qui met 2 secondes à répondre. Donc vous devez repenser vos interfaces : moins d'appels, plus de batch, plus de cache, plus de dénormalisation. L'architecture change la conception des APIs.

Quand les microservices ont du sens

Je ne suis pas un intégriste du monolithe. Les microservices ont du sens dans des cas précis :

Si aucun de ces critères ne s'applique à vous, les microservices sont un coût sans bénéfice. Vous ajoutez de la complexité opérationnelle sans résoudre de problème réel.

Quand les microservices n'ont pas de sens

Le monolithe modulaire : le milieu de terrain sous-estimé

Entre le monolithe spaghetti et les microservices distribués, il existe un terrain de milieu : le monolithe modulaire. Une seule application déployée, mais avec des modules aux frontières claires, des interfaces explicites, des dépendances unidirectionnelles. Spring Modulith en Java, Vertical Slice Architecture en .NET, les bounded contexts de DDD appliqués au sein d'un seul déploiement.

Le monolithe modulaire vous donne : déploiement simple, tests simples, debugging simple, pas de réseau entre les modules. Et il vous prépare aux microservices : si un module a besoin d'être extrait plus tard, la frontière existe déjà. C'est un chemin de migration naturel, pas un saut dans le vide.

Les entreprises qui reviennent au monolithe

Il y a un mouvement silencieux mais réel. Des entreprises qui ont goûté aux microservices et qui reviennent au monolithe. Segment, en 2020, a publié un article sur leur retour au monolithe après des années de microservices. Les raisons : debugging impossible, déploiements complexes, incidents multi-services impossibles à diagnostiquer. D'autres ont suivi. Ce n'est pas un retour en arrière. C'est un apprentissage : la complexité distribuée n'en vaut pas toujours la peine.

Et soyons clairs : revenir au monolithe n'est pas un échec. C'est une correction. Le vrai échec, c'est de rester dans une architecture qui ne vous sert pas, par fierté ou par conformité au hype.

Le test que personne ne fait

Comptez vos services. Combien sont déployés ensemble, au même moment, par la même équipe, avec des releases synchronisées ? Si la réponse est "la plupart", vous n'avez pas des microservices. Vous avez un monolithe distribué — le pire des deux mondes. La complexité du distribué, sans les bénéfices de l'indépendance.

Et vous ?

Combien de services avez-vous qui ne sont déployés qu'ensemble, au même moment, par la même équipe ? Ce sont des modules, pas des services.

Partager votre retour
Partager : in X f