Les architectures “micro-(web)-services”

Les micro-services drainent un certain nombre de mauvaises pratiques… Le “hype” a encore frappé.

SOAP, ReST, WebApi, WOA, ROA… les architectures distribuées sont plus que jamais d’actualité. Il y a quelques années, les web-services étaient encore relativement difficiles à implémenter et à mettre en production. De nos jours, il est devenu très simple de les implémenter. Les frameworks contemporains permettent de gérer de façon simple et déclarative les questions transverses comme l’authentification, le logging, la sérialisation des données, mais aussi, les protocoles d’échange, comme HTTP. C’est tout le sens de la WebApi. Avec le Cloud, les développeurs peuvent maintenant transférer en toute transparence les services écrits sur leurs environnements de développement vers des plateformes distantes, et automatiser toute la chaîne de déploiement. Tout cela permet (en théorie) de se concentrer sur l’aspect fonctionnel. De ce fait, les web-services se multiplient et leur présence n’est plus challengée par les développeurs, qui les implémentent quel que soit le contexte.

Retour sur les définitions

De façon générale, la notion de service est un peu nébuleuse. Nous savons qu’un service doit être stateless (il ne maintient aucun état en provenance de ses clients), il doit fournir des informations ou exposer des capacités à un ou plusieurs tiers. D’un point de vue purement fonctionnel, un service caractérise plutôt une aptitude de l’entreprise au sein d’un domaine.

“Business Service : supports business capabilities through an explicitly defined interface and is explicitly governed by an organization.”

Open Group (OG)

Les définitions convergent de façon orthogonale, mais la définition de l’OG laisse très explicitement entrevoir les enjeux fonctionnels auxquels doivent répondre ces services. Cet aspect fonctionnel fait cruellement défaut aux définitions applicatives. Cette lacune était la principale faute du SOA, et c’est aussi la principale erreur commise avec les micro-services. Leur définition est extrêmement vague. Elle doit être précisée.

Les micro-services

Depuis l’avènement des architectures micro-services, les web-services tendent à se spécialiser autour d’une responsabilité unique, la plus fine possible. Dans l’intention, c’est plutôt une bonne chose. Cette approche vise à proposer une alternative radicale aux composants monolithiques d’antan, en réduisant la base de code pour chacun de ces composants. Côté DevOps, cette stratégie vise aussi à simplifier le déploiement, la montée à l’échelle, et la maintenance de ces applications. Ces “nouveaux” web-services empruntent aux classes et aux méthodes le principe de responsabilité unique (SRP), parfois à l’extrême. A l’heure actuelle, il n’est pas rare de voir des web-services se spécialiser autour du CRUD en base, et répondre à des préoccupations exclusivement techniques. On parle alors de nano-services. Cela est sensé contribuer à la maintenabilité du système d’information, aider à sa scalabilité, et à sa sécurité (idée généreusement portée par REST). L’idée semble neuve mais elle a été identifiée comme un anti-pattern du SOA traditionnel, il y a quelques années. Il est très dommage de constater que les du SOA retrouvent à travers certaines implémentations des architectures micro-services la respectabilité dont ils ont été déchus.

“Si ça tient sur une ligne, c’est une instruction, ce n’est pas un service…”

Anonyme

Après quelques années de mise en pratique, de succès, d’échecs, les premiers retours d’expérience nous confirment que ces architectures sont bonnes (simples à coder, à tester, et à déployer…) lorsque les micro-services sont alignés sur les besoins du métier, et agissent sur un périmètre fonctionnel clair, intelligible par celui-ci. En conséquence, s’ils doivent implémenter des responsabilités d’ordre exclusivement technique, il est préférable d’opter pour une intégration plus classique, par une librairie par exemple. La réutilisation sera plus simple et les performances bien meilleures. Ceci est un premier point de vigilance.

HTTP, or not HTTP ?

Aussi, rien dans les définitions précédentes ne laisse transpirer quoi que ce soit sur les modalités qui permettront de consommer le service : requêtes HTTP ? notifications par un middleware ? consommation synchrone ou asynchrone ? Si on s’attache à ces définitions, il semble qu’il soit tout à fait possible de réaliser une micro-services sans le moindre web-service. Hors, ce n’est pas l’approche dominante. Concrètement, cela présente l’immense avantage de limiter la distribution du système et de contrôler ce qui est pire qu’un mauvais couplage applicatif, à savoir un mauvais couplage fonctionnel. Ceci est un second point de vigilance.

“My First Law of Distributed Object Design : don’t distribute your objects.”

Martin Fowler

Le terme d’architecture micro-services désigne un système composé de services faiblement couplés, devant collaborer (voir interagir…) au travers d’interfaces permettant de masquer les modalités d’exécution, comme la technologie employée. Au milieu de tout cela, le web-service est avant tout un outil d’interopérabilité. C’est historiquement sa mission.

L’utilisation des web-services

Techniquement, il n’y a aucun intérêt à exposer des aptitudes qui seraient consommées par un tiers unique. Surtout par un web-service, lorsque l’on sait combien les appels distants sur un réseau sont coûteux. Dans ce sens, et malgré ce que l’on veut bien comprendre de la définition, un micro-service (et qui plus est un web-service) promeut bel-et-bien la réutilisabilité de ses aptitudes : il les expose dans ce but précis !

Du point de vue fonctionnel, si l’on se fie aux bonnes pratiques qui émergent du terrain, un service suppose l’existence d’un Bounded Context (BC). Il privilégie un caractère collaboratif et un minimum d’interactions avec d’autres BCs d’autres services. Un BC privilégie hautement des applicatifs indépendants, faiblement couplés fonctionnellement (ce que je décris comme une “collaboration”).

Si nous mettons maintenant face à face les 2 définitions, nous voyons quand même un prisme. La définition technique nous parle d’un couplage faible. Mais fonctionnellement, si nous utilisons des web-services, cela se traduit par des interactions directes, qui amènent à un couplage fort entre ces composants. S’ils sont découplés, c’est uniquement par la structure du code source, peut-être par leurs responsabilités respectives (et uniques) si l’on adopte une vision très locale, mais fonctionnellement, en prenant du recul, ils sont hautement couplés, à un point tel qu’un web-service indisponible peut compromettre le bon fonctionnement d’une bonne partie du système. Cela ne correspond pas à l’organisation souhaitée d’une entreprise : si un service dans une entreprise est dévasté par la grippe, rien ne doit empêcher les autres services de fonctionner. Niveau code, si un web-service est paralysé (panne, opération de maintenance, bug applicatif, mauvaise montée à l’échelle…), ses clients le seront aussi. Les web-services répondent à certaines problématiques (fournir de l’interopérabilité entre les systèmes notamment…), mais ils peuvent aussi créer des problèmes. Il faut par exemple prévoir très en amont des stratégies pertinentes de reprise sur erreurs, et mettre au point des mécanismes pour garantir la consistance des transactions. Ceci est un troisième point de vigilance.

Fonctionnellement, plus nous avons de web-services dans la solution, plus les couplages fonctionnels seront importants. Si l’ambition de l’architecture micro-services est de garantir un couplage fonctionnel qui puisse être le plus faible possible, il semble évident qu’implémenter cette architecture en s’appuyant exclusivement sur des web-services est très contre-productif.

Comment fait-on pour la donnée ?

L’une des grandes règles concernant les données dans une architecture micro-services est de n’avoir, pour un type de données, qu’un seul et unique système d’enregistrement, et de validation. Sans contournements ou dérogations possibles par rapport aux contrats d’interface qu’expose le service. Chaque micro-service est garant de la consistance de ses données, et des informations qu’il gère. Cela vaut pour les insertions, les modifications et les suppressions en base. Par corollaire, un micro-service répondant uniquement à des problématiques de CRUD en base devra probablement implémenter des règles de validation différentes provenant de services différents. Hors, il faut autant que possible pouvoir implémenter une architecture qui ne prive pas les BCs de leur substance, de leurs règles, sous peine de créer de nouveaux points de contention, là ou l’on tentait au contraire de décentraliser. Ceci est un nouveau point de vigilance.

Pour les lectures en base, les architectures micro-services s’entendent parfaitement avec ReST. L’intérêt de ReST, bien au delà de la question du web-service et des APIs, réside dans son caractère “stateless” affirmé. Le serveur ne connaît rien de l’état dans lequel se trouvent ses clients, aucune information concernant les clients n’est assimilée par le serveur. Ce principe permet de garantir la scalabilité : pour monter à l’échelle, il suffit simplement de déployer autant d’instances du serveur que possible, sans se soucier d’un quelconque couplage avec d’autres tiers. Ce principe permet surtout de garantir l’encapsulation et le respect du CQS. Aucune règle, aucun processus, aucun détail portant sur l’implémentation du service, aucune des informations abstraites par le web-service ne peut s’échapper du contexte, en dehors de ce que l’on souhaite en exposer. ReST est un protocole très centré sur la donnée, les 4 principaux verbes de ReST traduisent les 4 opérations CRUD des bases. C’est un bon protocole pour véhiculer les données d’un BC à l’autre, même si cette proximité avec la donnée ne lui permet pas de tout implémenter. Toutefois, il faut être vigilant sur le fait que ReST ne présente aucun intérêt si les 4 verbes HTTP pointent directement sur les opérateurs CRUD en base. L’API ReST a pour but d’exposer des ressources, et pas des données. Les ressources en question sont des objets métier construits pour les clients à partir des données persistées, mais les règles de gouvernance de la donnée appartiennent exclusivement au service : comment historise-t-on les données, comment les supprime-t-on ? comment les sécurise-t-on ?

Le middleware

L’utilisation d’APIs ReST fera du sens pour des données critiques devant être disponibles en temps réel, de façon synchrone. Partout ou l’on utilise ces APIs, qui sont des web-services à part entière, on obtient un couplage fonctionnel fort. Il est important de challenger d’autres approches. Dans ce sens, il est clair que des notifications postées sur un bus d’entreprise seront beaucoup plus aptes à diminuer le couplage fonctionnel entre les composants du système. Toutefois, il y a un prix à payer. Les notifications impliquent que le système sera dans un état “éventuellement consistant”. Cela traduit le fait que 2 micro-services ne seront pas obligatoirement informés d’un événement au même instant, à cause notamment du temps de propagation de la notification : contrairement aux web-services, les notifications sont asynchrones. En termes de cloisonnement pour le BC, les notifications présentent tout l’intérêt de l’approche ReST. Mais elles présentent un intérêt supplémentaire : avec des notifications qui transitent sur un bus d’entreprise, les acteurs du SI ignorent tout de leur environnement et de la topologie du système. Toutes ces APIs s’adressent un interlocuteur unique, qui se chargera de lisser la charge dans le cas de fortes sollicitations : le bus d’entreprise. Il n’y a plus besoin de maintenir un inventaire de services. Moins d’interactions, moins de couplages. Attention, les notifications ne doivent pas uniquement servir à déclencher des traitements. Elles embarquent des informations (pas des données) qui doivent être raffinées par ceux qui y souscrivent, afin qu’ils puissent enrichir et mettre à jour leurs modèles fonctionnels respectifs, et construire des décisions élaborées.

La transaction

Les micro-services fonctionnent chez les géants du web. Facebook, Twitter, etc… Dans d’autres secteurs, la transaction est au coeur du système. C’est le cas des systèmes bancaires. Sur Facebook, lorsque les transactions vers le moteur de persistance sont retardées (par le biais de hacks au sein de l’interface utilisateur elles semblent synchrones…), il n’y a pas mort d’homme. Ce n’est pas le cas d’un système bancaire qui est gouverné par une foule de contraintes réglementaires de traçabilité, de consistance. Ce n’est pas le cas d’un système de trading automatique à faible latence ou chaque aspect du temps doit être totalement maîtrisé… hors, une approche distribuée empêche toute transaction distribuée (c’est très compliqué, voir impossible…). Cet aspect doit aussi faire l’objet d’une attention toute particulière et doit piloter la définition de chacun des périmètres couverts par les services. Note : dans le cas d’un système de trading automatique, le service bus ne sera pas plus adapté qu’un web-service…

Conclusion

Alors, qu’est-ce qu’un micro-service ? Il semble que les architectures micro-services empruntent beaucoup plus au qu’aux web-services, dans leur stratégie commune d’encapsulation du métier. Par contre, elles sont implémentées par des développeurs qui ne maîtrisent pas forcément les principes du . Les retours d’expérience sur ces architectures nous parlent de Bounded Contexts, de middleware, de notifications, beaucoup plus finalement que de web-services, qu’ils tentent de mitiger bien au contraire. Mais le mal est fait. La question du découplage applicatif entre ces services ne tient plus face aux enjeux du découplage fonctionnel, et la seule vraie manière de piloter ce mode de conception est la recherche de l’alignement sur le métier. Lui seul saura nous dire si une consistance éventuelle entre 2 BCs est prohibitive ou pas. Le métier est seul arbitre. Il est longtemps resté difficile de trouver une définition officielle des micro-services, ou bien, celle-ci a tardé. Ils ont longtemps été présentés comme la seule alternative aux applications très monolithiques en promouvant une architecture fractionnée en de nombreux composants de taille réduite. Les retours d’expérience tentent de mitiger cette approche et de relativiser le recours systématique aux web-services.

Add a Comment

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

35 + = 36