Architecture des APIs dans les systèmes distribués

by Christian on 7 février, 2016

Les travaux de Owen Rubel sur les APIs sont très stimulants bien qu’assez controversés (autour de moi personne n’en voit l’intérêt). j’essaye ci-après d’en faire une synthèse très partielle et probablement personnelle.

Dans une architecture logicielle, une API a pour fonction d’assurer ce que l’anglais nomme « separation of concern » que je traduis ici par séparation des préoccupations ou des aspects. Il s’agit de simplifier la vie du développeur en lui offrant des entrées et sorties de communication (I/O) standardisées et découplées de leur implémentation applicative. Cette fonction première des APIs se retrouve dans tous les styles d’API : API pour accéder à du hardware, des OS, des bases de données, des applications,etc.
Ce rôle de standardisation des communications pour assurer une séparation des préoccupations fait aujourd’hui problème dans les architectures distribuées. On peut en effet distinguer les APIs qui se présentent comme une bibliothèque logicielle, où les appels à l’API se font en local, des APIs qui se présentent comme des protocoles où les appels se font à distance (remote). Dans le premier cas l’API est encapsulée dans le logiciel, dans le second elle est exposée à l’extérieur et peut interagir avec tous les composants distribués (proxy, gateway, MQ,..)
Que se passe-t-il dans ce passage ? On passe d’une logique applicative centralisée à une logique applicative distribuée : la fonction de l’API s’en trouve transformée. Dans le premier cas l’API a une fonction privée de séparation des préoccupations alors que dans le deuxième cas elle a une fonction publique de séparation des préoccupation.
Concevoir des APIs pour des architectures distribuées et distantes comme on le fait pour des APIs d’ architectures centralisées serait assurément une erreur de conception d’architecture logicielle. Elle est pourtant fréquente car on continue de gérer au niveau du contrôleur applicatif des tâches qui devraient être gérées au niveau de l’interface de communication qu’est l’API. Que les fonctions de communication et les fonction applicatives soient intriquées et liées entre-elles dans une architecture centralisée n’est pas si grave, mais dans une architecture distribuée, c’est cette pelote initialement privée et interne à l’application que l’on se retrouve à publier sur le réseau.
Une API de protocole dans une architecture distribuée peut-elle encore assurer sa fonction première de séparation des préoccupations quand elle est publiée et exposée ?
Dans toute architecture logicielle distribuée, il arrive toujours un moment ou le travail de séparation des préoccupations trouve ses limites. Avoir du code bien modulaire qui prend en charge les différents aspects applicatifs  fonctionne bien, mais uniquement jusqu’à un certain point. Il arrive toujours un moment – et d’autant plus vite quand on est dans des architectures distribuées –  où des parties de code doivent gérer plusieurs préoccupations. Une conception uniquement basée sur le pattern de séparation des préoccupation est tendantiellement irréalisable dans l’évolution des architectures distribuées. On n’arrive jamais à avoir un puzzle avec toutes ses pièces bien découpées sans jamais avoir de chevauchement ou de pièces en double.
puzzle
Concevoir une architecture logicielle basée sur une séparation des préoccupations c’est comme faire une division : dans certaines situations, par exemple avec les applications centralisées, la division peut donner un résultat entier, mais dans le cas des architectures distribuées la division des préoccupations va avoir un reste. C’est ce reste de la division, cette infime partie de code qui mélange des préoccupations qui sont transverses (cross-cutting) et n’ont pas trouvé de place unique dans le découpage du système, qui va être l’origine de nombreux maux.
Cela va se manifester essentiellement selon le scénario suivant : cet entremêlement de code transverse (cross-cutting) va créer des dépendances entre différents les systèmes composants,  ces dépendances vont être momentanément palliées en faisant de la duplication de code et/ou de data dans le système (scattering), mais cette duplication de code va augmenter l’entremêlement et donc l’entropie du système, on va donc rajouter de nouvelles duplication de code pour y pallier, et ainsi de suite jusqu’à étouffer l’architecture (TTM horrible, calcification du code legacy, coûts d’évolution qui monte en flèche, douleur pour ceux qui doivent le maintenir et le faire évoluer, etc.)
Cette petite portion de code initial qui était transverse va générer une tumeur qui ne va cesser de faire des métastases dans votre architecture distribuée. L’architecture du SI distribué peut alors prendre la figure de l’esprit putride dans Le Voyage de Chihiro de Miyazaki.
architecture putride
Revenons donc à nos APIs de protocole (API Web) et rappelons que ce qu’elles ont de spécifique c’est qu’elle sont exposées sur le réseau, elles sont publiées et non plus encapsulée au sein des applications non-distribuées ou faiblement distribuées. Dit autrement, ces APIs sont partagées.
Des questions se posent : qu’est-ce-qui se joue dans ce partage ? L’API assure-t-elle encore sa fonction première de séparation des préoccupations ? La réponse est non : une API web n’a plus le rôle de séparation des préoccupations mais plutôt un rôle de partage des préoccupations. L’idée est forte, puisque cela revient à dire que, dans un système distribué, il n’y a pas de bonne séparation sans que celle-ci ne repose in fine sur un partage, à condition toutefois de garder à l’esprit que la seule chose que partage une API sur le réseau, ce sont les éléments relatif à la communication. Dans une API Web, ce qui est partagé c’est toute la logique de communication qui se trouve être découplée de la logique applicative. Pour les API encapsulées dans les applications, les logiques de communication et les logiques métiers étaient fortement couplée au niveau de l’API . Ce défaut était sans conséquence dans une architecture centralisée, mais il devient critique dans un système distribué : ne pas découpler la logique de communication – les messages, les requêtes et les réponses – ce que j’appelle la logique épistolaire des systèmes distribués – de la logique applicative peut hypothéquer l’évolution et l’avenir d’un système.
Cette séparation qu’opère une API entre couche de communication et couche applicative n’est pas une séparation des préoccupations : c’est un partage des préoccupations de communication qui conduit à une séparation des services. Cette proposition a son importance pour une architecture qui va vers les microservices ; en effet une architecture de type microservices ne respecte plus le pattern de séparation des préoccupations, uniquement celui de séparation des services.
Le rôle d’une API de protocole n’est pas de séparer les préoccupations mais de partager les préoccupations pour pouvoir séparer les services.  
Concrètement, quels sont les éléments de communication que doit partager une API web ? Les end-points, les règles d’autorisation et les rôles, les règles de formatage des ressources, des requêtes et des réponses, la gestion des batch plutôt que de la déléguer au controleur applicatif, etc. Tout ceci n’a rien à faire au niveau des méthodes de la logique applicative et doit être traité en amont et en aval, précisément au niveau des communications. Toute la couche du protocole de communication doit gérer les requêtes et les réponses dans les handlers et les intercepteurs, de sorte que le contrôleur applicatif puisse se concentrer sur la logique métier. Aussi, le contrôleur applicatif n’est pas le end point de l’API web puisque le end point, en tant que point d’entrée de l’API,  relève pleinement de la couche de communication ; plus exactement nous dirions que dans l’API il y a l’intercepteur qui joue une fonction de resolver de end-point là où il y a des end-point résolus au niveau du contrôleur applicatif.
Au final la fonction de partage que joue l’API va être concentrée dans un fichier de configuration avec les métadonnées de communication (tout çà pour un fichier de conf  diront certains).
J’essaye de résumer la thèse ici présentée : on ne peut pas réaliser une séparation complète des préoccupations dans les systèmes distribués, il y a toujours des parties de code qui vont être transverses. Il ne faut donc pas masquer ce qui est transverse mais le partager car ce partage permet d’avoir une séparation claire et efficace entre les services de communication et les services applicatifs. Ceux qui prônent la séparation des précoccupations comme pattern des architectures microservices font une confusion car c’est le pattern de séparation des services qui est premier dans ce contexte. Séparation des préoccupations et séparation des services sont deux patterns complètement différents.
Print Friendly
Signaler sur Twitter

{ 1 comment… read it below or add one }

Aurélien février 11, 2016 à 3:45

Avec ta synthèse je comprends mieux le rejet que génère les propos Owen Rubel.

C’est son hypothèse de départ qui pose problème: Mélanger la notion avec d’API avec le concept de « separation of concern » c’est une absurdité. C’est d’ailleurs sa conclusion.

Personnellement je ne prendrais pas au sérieux un architecte qui défendrais qu’une API est là pour assurer la « separation of concern » ou qui confondrait réutilisation de librairie (application centralisé) avec réutilisation de service (application distribuée)

Bref je ne vois pas l’intérêt d’en faire autant et si compliqué pour défendre des concepts basiques et largement admis en matière d’architecture distribuée.

Répondre

Leave a Comment

Previous post:

Next post: