
PHP est partout. Mature, robuste et massivement déployé, il reste au cœur de nombreux systèmes en production. Pourtant, dès que l’on aborde des sujets comme la performance, les calculs intensifs, le caching applicatif ou la gestion d’état, le réflexe est presque toujours le même : trouver un service externe.
Un micro service apparaît, parfois accompagné de Redis ou de Kafka. Les conteneurs se multiplient, les appels réseau deviennent la norme et la complexité augmente progressivement. Ce choix est souvent rationnel, mais rarement neutre. Il introduit des frontières techniques, de la latence et une charge réseau qui n’est pas toujours en adéquation avec le problème à résoudre.
Étant architecte logiciel Golang au sein de l’entreprise ekino et non expert PHP, j’ai abordé ce sujet avec une question simple :
Créons-nous des micro services par réflexe plutôt que par nécessité ?
L’objectif n’est pas de “booster PHP” ou de comparer les langages, mais plutôt d’explorer un nouveau compromis architectural.
Cet article est le premier volet d’une série dédiée à notre raisonnement : expérimentation structurée, conception d’architecture, implémentation et mesures comparatives, je partage un retour d’expérience afin de pouvoir observer ce qui se passe lorsque l’on enlève une variable importante dans les architectures actuelles : la frontière technique.
Ce retour d’expérience vise à éclairer une problématique plus large : comment améliorer les performances d’un système sans multiplier les frontières et la complexité d’un système distribué ?
Le réflexe moderne : extraire !
La plupart du temps, dans un projet web avec un frontend et un backend séparé, une nouvelle fonctionnalité est synonyme d’apparition de l’intégration d’une nouvelle brique externe au logiciel.
En effet, selon un découpage très scolaire, un réflexe est de se dire qu’une responsabilité différente doit être dans une brique logicielle différente. Si cette brique logicielle est suffisamment complexe ou éloignée des services du backend, un micro service apparait, qu’il soit fait maison ou que ce soit un driver pour s’y connecter.
Prenons pour exemple un backend ayant pour rôle de servir un frontend qui va montrer les habilitations des employés dans une entreprise. Si je veux intégrer une fonctionnalité de gestion des congés, je vais certainement aller chercher toutes les solutions possibles, et les intégrer directement dans le backend ou encore regarder les solutions tierces déjà existantes sur le marché ( l’option la plus souvent choisie). Cela demandera “simplement ” d’intégrer un nouveau driver au backend ainsi que d’établir les processus synchrones et asynchrones de synchronisation des données avec ce service tiers.
On vient ainsi “par habitude” d’introduire un micro service. On peut retrouver ce type de raisonnement pour des fonctionnalités comme le traitement d’évènements ou encore l’utilisation d’un cache applicatif. Ceci est lié aux nouvelles architectures très modulaires qui permettent de faire du plug and play avec des drivers. Ainsi, dans une architecture en micro services, on peut allouer un pod par micro service avec ses propres paramètres de montée en charge, de scalabilité. Et vu que chaque micro service est indépendant, on peut même avoir une équipe différente par micro service car les repositories, les cycles de déploiement et même le projet en lui même sont totalement séparés. Ce qui est très pratique mais qui a également un coût.
Le coût invisible des micro services
Extraire une fonctionnalité dans un service dédié ne fait pas disparaître la complexité.
Elle la déplace.
En effet, ce nouveau driver dans le backend va certainement faire des appels HTTP ou gRPC. Un DTO (data transfer object) va donc devoir être sérialisé (en JSON par exemple). Cette nouvelle fonctionnalité va avoir un coût réseau ainsi qu’un coût en termes d’infrastructure qui sera beaucoup plus palpable lors des premiers tests d’intégration. Une complexité cachée se révèle ; une latence réseau apparaît ; la gestion des logs et du monitoring est séparée et plus complexe à suivre ; l’observabilité multi services doit être améliorée ; un déploiement coordonné doit être effectué ; etc.
La frontière technique, qui auparavant était éphémère dans l’intégration de l’existant, se retrouve être une frontière technique permanente. Et cela malgré une charge réelle qui diminue et une logique isolée. Le besoin initial ne demandait certainement pas une architecture modulaire et plus important encore, l’équipe technique en charge du backend ne demandait certainement pas à avoir un service en plus qui ajoute de la complexité dans la compréhension globale du projet.
Un bug qui se propage de services en services devient un vrai défi à reproduire en local sans parler du fait que des bugs dans plusieurs services peuvent se compenser…
Conclusion
Ainsi, créer cette frontière est une solution facile mais qui n’est pas gratuite. C’est précisément cette question là qui m’intéresse. J’aimerais ainsi vous présenter mon expérience pour tenter de répondre à cette question au travers de plusieurs articles.
Pour répondre à cette question, j’ai construit un cas volontairement simple mais représentatif :
un service de suivi du personnage d’un joueur dans un jeu vidéo avec de l’event sourcing qui permettra de traquer ses actions, avec accumulation d’événements, reconstruction d’état utilisateur et calcul de score en temps réel.
Deux implémentations de ce service ont été réalisées :
– une architecture avec un service externe
– une architecture où la même logique est embarquée directement dans l’application (via l’intégration d’un module Go grâce à FrankenPHP)
L’objectif n’était pas de démontrer qu’une approche est “meilleure” qu’une autre, mais d’observer concrètement ce que change, ou ne change pas, cette frontière dans le comportement du système.
J’ai donc mesuré via un benchmark des métriques telles que la latence selon la charge réseau afin de présenter ces chiffres et voir si notre approche est bonne.
Au-delà des chiffres, c’est surtout notre manière de dessiner les frontières dans une application qui mérite d’être questionnée.
Micro services : réflexe ou besoin réel ? was originally published in ekino-france on Medium, where people are continuing the conversation by highlighting and responding to this story.
