Architecture Hexagonale & Clean architecture : bonnet blanc, blanc bonnet ? - Compte-rendu du talk de Christophe Breheret-Girardin du Comptoir x La Duck Conf 2023

le 20/01/2023 par Lana LESIK
Tags: Software Engineering

Afin de pallier aux problèmes des architectures N-tiers, plusieurs alternatives ont émergé après les années 2000, dont l’architecture Hexagonale et la Clean architecture. Seulement, elles ne sont pas toujours bien comprises : pour expliquer l'une, certains utilisent parfois les termes de l'autre ; d’autres se basent sur des croyances plutôt que sur les publications d'origine. Et si nous comparions ces deux architectures pour lever le doute une fois pour toutes ?

Les concepts d’architecture hexagonale et de clean architecture sont parfois mélangés ou mal compris. Dans son intervention vidéo, au sein du comptoir OCTO x La Duck Conf 2023, Christophe BREHERET-GIRARDIN, Manager Référent chez OCTO avec plus de 23 ans d’expérience dans le secteur tech, tente de lever l'ambiguïté entre ces deux concepts.

Avant d'évoquer les grands principes liés à ces architectures applicatives, cherchons à comprendre leur raison d'être en remontant le temps.

Au début (dans les années 2000) le code manquait de structure et ressemblait, au fil du temps, à un vrai plat de spaghettis, d'où son nom "architecture spaghetti". Ce mode de fonctionnement était très efficace pour le développement des premières fonctionnalités mais montrait très vite ses limites : plus le code s’étoffait, plus il était difficile de maintenir et de faire évoluer le logiciel.

Les problématiques rencontrées avec l’architecture spaghetti ont ainsi provoqué des réflexions sur la structure du code et son découpage de / des application(s) en couches. C'est dans ce contexte qu'émerge l'architecture en couches (aka "l’architecture lasagne").

Chacune de ces couches ayant une responsabilité précise : une couche gère les accès à la base de données, une autre gère la logique métier et une autre fait remonter les informations nécessaires aux rendus des vues utilisateurs.

Le problème de cette architecture est qu'elle relève d’une vision fonctionnelle calquée sur le modèle de données. En l'occurrence, dans le cas d’un modèle relationnel, limité par la rigidité de sa structure (notamment par l'interdépendance des tables), l'implémentation de la logique métier peut s'avérer douloureuse et difficilement testable en mélangeant le code d'intégration avec la logique métier. Ce qui aura pour conséquence de complexifier l'évolutivité du système. L'exemple typique de cette complexité serait un changement sur le schéma de la base de données. Avec une vision métier dépendante de la structure d’une base de données relationnelle, toutes les évolutions fonctionnelles seront donc aussi complexes à gérer que les évolutions techniques.

Un couplage était également présent avec les objets de persistance qui traversaient plusieurs couches.

L’arrivée des frameworks a alors facilité la vie des développeurs, mais les montées de version structurantes et le maintien des librairies pouvaient radicalement impacter le développement du métier.

Le concept des microservices a essayé de résoudre les inconvénients des architectures existantes par la division de l’application en petits périmètres moins complexes. Les micro-services peuvent être utiles à condition :

  1. D’en avoir vraiment besoin

  2. De maîtriser tous les aspects techniques utilisés

  3. De trouver le bon découpage des périmètres

Sans respect de ces conditions, l'application risque de rencontrer les mêmes problèmes que les architectures précédentes voire pire car ces problématiques vont être distribuées dans tout le système !

Ces premières tentatives nous enseignent plusieurs éléments importants à retenir durant une phase de conception :

  • l'architecture logicielle est le coeur du système et ce système doit pouvoir évoluer le plus facilement possible

  • la valeur d'un logiciel ne se trouve pas dans sa technologie mais dans le métier qu'il embarque, ce métier étant beaucoup plus pérenne et durable

  • la manière de concevoir des logiciels doit pouvoir évoluer librement

Nous finissons notre parcours historique avec la démocratisation des pratiques qui suit l’avancement des technologies. Nous ne concevons plus des logiciels comme avant les années 2000. La démocratisation des bonnes pratiques, commencée depuis 2000, s’est professionnalisée à partir de 2015 avec, entre-autres, l’arrivée de l’architecture hexagonale et de la clean architecture.

Schéma illustrant les étapes de démocratisation des pratiques

L’architecture hexagonale

L’architecture hexagonale a été imaginée par Alistair Cocburn en 2005.

Pourquoi un hexagone ?

De par sa forme géométrique et ses côtés pour y placer des éléments, cette figure doit protéger la valeur en l'isolant des technologies qui l'entourent. L’hexagone pourrait intégrer une librairie, mais cela doit être justifié et rester exceptionnel.

Un diagramme d’architecture hexagonale montrant l’hexagone au milieu et deux adapteurs qui se branchent de deux côtés opposés de l'hexagone.

Au milieu de l’hexagone se trouve votre métier (“Application”) qui communique grâce aux ports et adapters :

  • Le port de gauche, c’est la fonctionnalité offerte par notre système (par exemple, une réservation d’une chambre d'hôtel) - Appel “User-Side”

  • Le port de droite, c’est ce que l’hexagone doit définir pour fonctionner (par exemple, la récupération des chambres libres ou l’ajout d’une réservation via une base de données) -  C’est la partie “Server-side”.

Les adapters, quant à eux, sont le monde extérieur par rapport au métier, c’est-à-dire la technologie :

  • L’adapter de gauche utilise les fonctionnalités métier (par exemple, un contrôleur REST qu’on appelle via HTTP)

  • L’adapter de droite ce qui se conforme au contrat du port du droit, “Server-side” (par exemple, un ajout d’une réservation dans le système)

Une belle illustration de cette architecture PORT ET ADAPTER est la prise électrique: elle donne de l'énergie, mais elle ne sait pas qui se branche à elle, de la même façon les ports n’ont pas conscience des adapters qui se branchent à eux.  Le port peut avoir plusieurs adapters ou changer facilement si un jour la technologie change, sans modifier une seule ligne de code de l’hexagone.

L'implémentation des adapters commence avec les tests (par exemple, les tests unitaires côté gauche et une doublure côté droit). Ce choix d’architecture permet de repousser les choix technologiques. Le port de droite est représenté par une abstraction (interface), et l’adapter de droite est une classe qui va implémenter cette interface via de l'inversion de dépendances (le principe “D” de SOLID).

Concernant le port à gauche, c’est moins clair, cela peut être une interface comme le côté droit, soit une classe concrète qui peut être appelée par une autre classe adapter.

Le métier est représenté par une modélisation composée de structures simples. Dans ces modèles, nous avons les données (par exemple, l’objet Hôtel, Chambre ou Prix) et les comportements associés.

L’architecture hexagonale n’explique pas comment modéliser le métier. Afin de trouver ces éléments, il faut s'orienter vers les patterns tactiques du Domain Driven Design.

La clean architecture

Un diagramme de clean architecture montrant 4 cercles concentrique : entities au milieu, puis use-cases, puis une couche des contrôleurs  et gateways et les devices, web, interfaces extérieures.

La clean architecture est représentée par des cercles concentriques. Elle a été imaginée par Robert C. Martin en 2012 (aka “uncle Bob”).

Ces cercles ont chacun des responsabilités:

  • Au milieu, les entities, ce sont des règles d’entreprise (le métier).

  • Autour ce sont les use-cases (ce qu’utilise le métier)

  • Ensuite, c’est un contrôleur (qui appelle les use-cases) et des gateways (des passerelles vers des éléments technologiques comme les bases de données).

En faisant un parallèle avec l’architecture hexagonale, l'hexagone représente des use cases et des entities. Les use-cases sont des ports de gauche et entities sont la partie “Application”. La gateway représente l’adapter de droite - la passerelle vers le monde technologique.

De même que tout à l’heure, si nous voulons nous prémunir des modifications technologiques, nous ne voulons pas mettre la technologie dans les deux premiers cercles les plus internes (entities et use-cases).

Diagramme de clean architecture montrant l'importance d'isolement de la valeur (métier)

À la différence de l’architecture hexagonale, la mise en œuvre de la clean architecture demande toujours une interface à gauche (“Use case input port”). Le use case se conforme à cette interface et communique avec la gateway - donc l'extérieur - via son interface. Le retour des informations au port de gauche est représenté également par une interface (“use case output port”). Le contrôleur va fournir une implémentation de cette interface (par exemple qui pourrait transformer les données en JSON), ainsi, il ne retourne rien côté use-case, il alimente un presenter, le use-case n’a pas conscience de ce que fait le présenter, mais il l’appelle.

S’il faut retenir une chose concernant l'implémentation de la clean architecture: il est nécessaire d'avoir une interface en entrée et une interface en sortie.

Final round

Et si on fait le bilan, le design applicatif a-t-il besoin de l’architecture hexagonale ou de la clean architecture ? Parfois aucune des deux. Si vous travaillez sous le domaine qui n’est pas le cœur de votre applicatif, qui n’apporte pas d'éléments différenciants par rapport au concurrent, il est inutile de vous lancer dans la clean architecture. Si vous êtes dans le cœur de votre sous-domaine métier, mais que vous êtes dans l’audit ou des transactions financières, les architectures clean et hexagonales ne sont pas les choix les plus adaptés non plus.

En revanche, pour tout le reste, c’est tout à fait adapté et conseillé.

HEXA VS CLEAN - Les avantages communs :

  • Découpage, isolation

  • Flexibilité

  • Pérennité

  • Testabilité

  • Repousser les choix techniques

  • Fonctionne avec le Front et le Back

HEXA VS CLEAN - La différence :

  • Guidage :

    • Hexagonal est moins guidé

    • Clean est fortement guidé

  • Taille des ports :

  • Échange d’information :

    • Hexagonal

      • L'intérieur ne doit pas fuir

      • Retour classique puis le controller doit s’occuper du formatage /présentation des données

    • Clean

      • Plus de détail sur le rôle des couches externes

      • Utilisation d’un "présenter" permettant de découpler les responsabilités de présentation des données

  • Terminologie : une correspondance dans chacun des termes (par exemple, user-side adapter c’est un contrôleur et son implémentation, application, c’est entities).

Exemples de la terminologie différente entre clean et hexagonal architecture: User c'est User User-Side adapter c'est controller, presenter User-side port abstraction c'est use-case input port avec use-case output port User-side port c'est use-case interactor Application   c'est entity Server-side port c'est gateway abstraction server-side adapter c'est gateway technology c'est framework et Driver

TAKE AWAY

Les 3 éléments importants à retenir :

  1. Un objectif commun : Isoler la valeur métier

  2. Elles ont des avantages et inconvénients communs :

    • Avantages : Découpage, flexibilité, mieux structuré, etc

    • Inconvénients :

      • Pas de guidage pour le design du métier

      • Pas adapté à toutes les situations

  3. Elles impliquent des niveaux de guidage différents :

    • Screaming architecture

    • Interfaces partout ou non

    • Retour des informations

Alors, vous vous dîtes : “Cet article est très intéressant, mais nous n’avons toujours pas  la réponse : Hexagonal ou Clean architecture ?!”

Et voilà la réponse :

“Entre hexagonal et clean … C’est la clean archigonale !”

Nous pouvons prendre le meilleur de deux mondes : par exemple, le terme de “use case”, la taille de ports avec la  scream architecture, l’adapter ou le repository (terme DDD), présence d’une interface sur le use case si vous voulez tester le contrôleur, etc.  Bref, vous pouvez faire un mix avec l’aide du DDD au milieu qui va aider à désigner le modèle. C’est la clean archigonale DDD :)

La vidéo du comptoir est disponible ici.