La Duck Conf 2023 - Compte-rendu de la keynote de Gregor Hohpe - "I made my app loosely coupled, will it fall apart?"

le 14/04/2023 par Mathieu Cailly
Tags: Software Engineering

Le 29 mars dernier s’est déroulée La Duck Conf 2023 au parc floral du bois de Vincennes. Et c’est Gregor Hohpe, architecte évangéliste chez AWS, qui a fait l’honneur de lancer cette édition !

Sa conférence, intitulée "I made my app loosely coupled, will it fall apart?", souhaite nous parler d’architecture et de la notion de couplage, notamment dans de larges systèmes distribués où il est un défi majeur. Et comment parler de couplage sans évoquer les architectures event-driven !

Gregor nous offre ici à la fois un cours magistral sur l’événementiel et un partage de son expérience fort de ses 20 années de métier !

Des lignes et des boîtes

On se représente bien souvent les choses avec des schémas, cet outil visuel est apprécié des architectes pour représenter des systèmes complexes et illustrer les liens qui existent entres les différentes parties qui les composent. On dessine alors des boîtes qui sont nos différents composants, puis des lignes ou des flèches pour les relier.

Gregor Hohpe a commencé sa conférence en rappelant l'importance des connexions entre les différentes boîtes d'un système. Bien qu'on ait tendance à se concentrer sur les boîtes elles-mêmes, les interactions entre les composants sont tout aussi importantes. Ces interactions définissent comment les composants s’associent entre eux, et de ce fait comment le système fonctionne.

Il avertit : les simples flèches qui les symbolisent ne traduisent pas la complexité de celles-ci, et tous les aspects importants qu’un bon architecte doit considérer comme le format de données, le flux de contrôle, la temporalité, le type d'interaction, etc..

“Considérez vous comme des chefs. Les bons ingrédients sont importants mais le rôle principal du chef est d’associer ces ingrédients pour en faire un repas savoureux.”

Gregor Hohpe

Connexions et couplage

Ces interactions amènent l’architecte à raisonner en termes de couplage. Lorsqu'on connecte deux systèmes A et B via une connexion directe, à quel point sont-ils couplés ?

“How do you make two systems loosely coupled ? Don’t connect them !”

David Orchard, BEA

Gregor nous donne sa définition préférée du mot: le couplage est une mesure de la “variabilité indépendante” entre deux systèmes connectés. La variabilité indépendante est la capacité d'un système à fonctionner de manière autonome sans être affecté par les modifications apportées aux autres systèmes avec lesquels il est connecté.

Il ne faut pas considérer le couplage comme étant l'ennemi numéro 1 d'un architecte. C’est une question de compromis et d’équilibre entre les différentes considérations ! Il ajoute : “Un extrême ou l’autre est rarement la bonne réponse”. Il a rappelé que le couplage avait de nombreuses facettes, telles que le couplage de données, de technologies, ou encore de protocoles.

Équilibrer le couplage

Pour réduire le couplage entre deux éléments, il peut être nécessaire d'introduire de nouveaux éléments intermédiaires, tels que des queues de messages dans le cas d'un système asynchrone. Cela augmente la complexité du système et nécessite la gestion de plus de contraintes et d'états, impliquant forcément un coût non négligeable au découplage.

Gregor Hohpe explique qu'il est impossible d'éviter totalement le couplage dans un système interconnecté. Pour mieux le comprendre, il le décompose en trois dimensions: la force, la distance et la volatilité du couplage. La force correspond au degré de liaison entre deux éléments, tandis que la distance représente la séparation entre ces éléments. La volatilité, quant à elle, évoque la probabilité qu'un changement sur un élément en provoque un autre sur un autre élément. Pour éviter les problèmes liés au couplage, l'architecte doit prendre en compte ces dimensions et choisir où le couplage est nécessaire ou acceptable en fonction de la complexité engendrée.

Selon lui, le bon niveau de couplage au moment de la conception dépend du niveau de contrôle dont on dispose sur les différents composants du système. comprendre son contexte et ce que l'on conçoit est crucial pour bien gérer le couplage.

Le contexte importe : intégration vs. systèmes distribués

Gregor compare l'intégration de systèmes tiers à la conception de systèmes distribués. Bien que ces deux approches puissent sembler similaires dans leur représentation graphique, leurs contextes respectifs diffèrent grandement en termes techniques, organisationnels, de cycle de vie et de niveau de contrôle. Quand on intègre, on a généralement très peu de contrôle sur les terminaisons, comme par exemple avec des systèmes tiers comme Shopify ou achetés sur étagère.

Les différents niveaux de contrôle, cycles de vie du développement,
organisations et outils en fonction du contexte.

Le contexte est donc crucial pour répondre à la question: intégrez-vous ou construisez-vous des applications distribuées ? Une question importante pour évaluer le bon niveau de couplage !

L'importance de la la sémantique

Le concept de message est au cœur des architectures event-driven. Il s'agit du mode d'interaction entre un ou plusieurs systèmes informatiques, où un système envoie une enveloppe de données à un autre système pour lui transmettre une information.

Contrairement à un appel de procédure à distance, les messages ne nécessitent pas de pile d'appel. Ainsi, le système destinataire peut traiter le message de manière asynchrone sans attendre de réponse immédiate de la part du système émetteur. Une propriété clé pour découpler deux éléments.

Il existe trois types de messages: la commande, le document et l'événement. Et c’est ce dernier qui est fréquemment utilisé dans des architectures event-driven car il permet d’inverser les dépendances du producteur au consommateur. Le producteur n’attends rien des consommateurs, il les informe d’un fait, et ils sont libres de réagir ou non. Le producteur n’est donc pas couplé aux consommateurs, à l’inverse de la commande qui est ordre, et où le producteur attend une réaction de la part  des consommateurs.

Exemples de sémantiques de nom de canal en fonction du message envoyé

Dans cet l'exemple, Gregor explique que la sémantique des interactions entre deux systèmes dépend de l'approche employée et définit également le niveau de couplage entre eux. Par exemple, si on traite une commande, on utilise comme nom de canal "ProcessPayment" pour demander clairement une action, alors que si on traite un événement, on utilise le nom de canal "OrderPlaced" pour décrire une commande placée.

Selon le contexte, l'approche à privilégier diffère : si le système est dynamique, l'événement est plus adapté, mais il comporte des contraintes, alors que si le système est stable, l'approche système est amplement adaptée sans introduire de complexité inutile.

Commandes passive-aggressives

Gregor met en garde contre l'utilisation de la sémantique appropriée dans les événements en citant Martin Fowler qui dit : "Méfiez-vous des événements qui s’utilisent comme des commandes passive-aggressive : [...] si le système source attend que le consommateur mène une action, alors elle devrait utiliser un message de type commande !".

Le risque de ces "commandes passive-aggressive" est que deux systèmes communiquant via des événements soient considérés comme découplés, alors qu'en réalité, ils ont une attente cachée d'une action. Il est important de noter que dans le cas d'un événement, on ne peut pas présupposer ce qu'il va se passer, car il est de la responsabilité du consommateur de le traiter.

Concrètement, comment faire le lien entre deux boîtes ?

Chaque approche pour établir un canal de communication entre deux systèmes a ses avantages et ses contraintes en termes de niveau de couplage, de variabilité et de complexité. Le choix de l'architecture dépend des besoins du système et des niveaux de flexibilité et de contrôle requis. Il existe différentes options telles que l'utilisation d'un élément intermédiaire (le composer), l'établissement d'une liaison directe ou encore la hiérarchisation des canaux via une notation à base de points. Il est également possible de mettre en place des règles sur le contenu du message pour un contrôle plus fin.

Event-driven vous-dites ?

Gregor souligne que ce n'est pas le système de messages en lui-même qui rend l'application event-driven, mais plutôt la manière dont l'application l'utilise qui le détermine.

Il y a différentes approches quant à l’anatomie et l’utilisation des événements.

  • L'event notification est la manière la plus simple d'utilisation, mais crée un couplage entre l'envoyeur et le consommateur, en raison de la double interaction nécessaire pour obtenir plus d'informations.  En effet, le consommateur aura généralement besoin de demander au producteur de la donnée pour effectuer un traitement.

  • Le event-carried state transfer ajoute de la donnée en plus du nom de l'événement, mais cela ajoute de la complexité dans la gestion des événements et crée un couplage entre les consommateurs et les données.

Illustration du PubSub et du Message Broker

Il y a également plusieurs façons de gérer l’envoie de ces messages. La méthode la plus simple est PubSub, où les messages sont publiés sur un canal et reçus par les consommateurs qui y sont abonnés. Cependant, une autre approche est le message broker, qui introduit un élément intermédiaire pour effectuer des tâches telles que la validation, la transformation et le routage.

Bien qu'il n'y ait pas de bonne ou de mauvaise solution, chaque approche a ses avantages et ses inconvénients. La première est moins complexe mais met plus de responsabilité sur les endpoints, tandis que la seconde offre plus de flexibilité mais implique l'introduction d'un élément intermédiaire

Abstraction vs. Illusions

Si on aime nos boîtes et nos flèches c’est parce qu’elles nous simplifient la compréhension d’un système en abstrayant la complexité de ce qui le compose. Il est important de construire des abstractions claires et de veiller à ne pas tomber dans des illusions. Gregor prend l’exemple des remote procedure calls (RPC) qui pose l’illusion qu’ils s'opèrent comme des appels de fonction en local, alors que c’est tout le contraire.

Le choix des outils est également crucial pour la réussite d'une architecture event-driven. Gregor Hohpe a ainsi présenté l'utilisation d'AWS CDK et de modèles pour coder les abstractions cloud, introduisant la notion de topology-as-code, la suite de l’infrastructure-as-code selon lui !

Conclusion

En conclusion, la conférence de Gregor Hohpe nous rappelle l'importance de la flexibilité et de l'adaptabilité dans les architectures distribuées. En effet, pour concevoir des architectures robustes et évolutives, il est primordial de garder le contrôle sur les solutions techniques et de maintenir un niveau de couplage adéquat. Toutefois, il est vrai que chaque choix d'architecture implique des compromis et ajoute de la complexité au système. L'architecte doit donc être vigilant et prendre en compte ces coûts pour trouver le bon équilibre entre flexibilité, évolutivité et maintenabilité du système.