Architecture hexagonale: Prends ton livre et n’fais pas de bruit dans ma bibliothèque !!

Voici un article sur l’architecture hexagonale. Vous trouverez mon exemple (application takebook), en langage java, projet sous maven, sur ce repository.

Le but de cet article est de faire un exemple, si vous voulez plus d’information théorique sur l’architecture hexagonale, vous pouvez lire cet article.

Voici un peu d’explication.

Mon domaine d’exemple, les bibliothèques

Faire de l’architecture hexagonale, cela veut dire que l’on a un domaine a géré. Si on fait juste une projet technique, on perd l’intérêt.

Du coup, mon application d’exemple permet de gérer les prêts de livres d’un groupe de bibliothèque.
Nos bibliothèques n’ont pas d’application pour gérer l’emprunt des livres entre différentes bibliothèques, nous intervenons pour combler ce problème.
J’ai une première version de l’application. Je ferai peut être un futur article (PS: Article fait) pour faire évoluer cette super application en devenir …

Voici le principe de prêt d’un livre:
– Le livre est disponible, si il se trouve sur une étagère
– Un utilisateur emprunte un livre si il est disponible
– L’utilisateur retourne le livre dans une bibliothèque
– Le livres est à nouveau disponible des que l’on le remet sur une étagère, etc …

En ce qui concerne les bases de données et comme les interfaces graphiques, les bibliothécaires (utilisateurs de l’application) utilisent actuellement différentes solutions et désirent garder chacun la leur.
On utilise l’architecture hexagonale pour gérer ce problème …

Mon Hexagone (le module “takebook-domain”)

On retrouvera le seul hexagone. Il se trouve dans le module “takebook-domain”.

Commençons par le pom.xml de ce module. Si on regarde au niveau dépendance, on a uniquement des librairies de tests.
Aucun framework (comme Spring, JEE, REST, JPA …) doit être présent. Dans l’hexagone, on gère uniquement le métier.

J’ai découpé l’application en différents modules.
Ce n’est pas obligatoire, mais cela permet bien de voir que le module “takebook-domain” ne possède aucune dépendance technique. (hormis pour les tests, mais cela ne compte pas. :))

Il y a 2 packages intéressants. On retrouve nos classes modèles (Book, Library …) dans le package “model”.
Les portes d’entrée et de sortie se trouvent dans le package “port”.
La porte d’entrée “LibraryBookInputPort” sera notre moyen d’utiliser les actions pour modifier l’état d’un livre.
Les portes de sortie “BookOutputPort”, “LibraryOutputPort” et “ShelfOutputPort” permettent de récupérer et sauvegarder les données, quelque soit le framework.

Moins de Blabla, plus d’exemple

Ok, pour montrer comment cela marche notre hexagone, on va le tester.
J’ai fait un exemple simple qui se trouve dans le module “takebook-app-stream-intern”. 
Regardons le runner StreamInternApp.

On a un adaptateur unique pour les portes de sortie “InternRepositoryAdapter”.
J’ai fait une implémentation pour 3 interfaces, afin de gagner du temps.
Cet adaptateur utilise des listes d’objet, pas de base de donnée, la donnée reste stocker dans l’application.

On affiche nos résultats, du coup, on utilise un adaptateur “InternOutputAdapter” pour la porte d’entrée “LibraryBookInputPort” afin d’interagir avec l’utilisateur dans la console.
Lances le runner “StreamInternApp” pour tester tout ça. Saisis l’action dans la console java pour pouvoir interagir avec l’application.

Le plus important dans l’architecture hexagonale (et ailleurs): Les tests

Tu peux voir dans les différents tests du module take-domain dans le dossier “test”. Ce qui est intéressant, c’est que l’on a besoin d’aucun framework à configurer pour tester.

Techno différentes, un même domaine

Allez, plus rigolo comme exemple, on va implémenter le framework Spring avec notre application.
Tu peux trouver l’application dans le module takebook-app-spring, lancer le runner SpringApp et tester via l’url http://localhost:8080/takebook/index.html

Attention, si tu ne comprends rien à Spring, tu risques de galérer un peu.
Spring possède une notion d’injection de dépendance (Spring IoC).
L’implémentation des portes de sorties possèdent des annotations Spring, ce qui permet d’auto-gérer des injections liées à des interfaces.
Dans la configuration de l’application (classe “SpringConfiguration”), on va indiquer que la porte d’entrée est injectable et elle a comme dépendances, les interfaces de portes de sorties auto-injectées.

Conclusion

Je vous conseille de lire ces vidéos qui m’ont beaucoup aidées:
– https://www.youtube.com/watch?v=Hi5aDfRe-aE&index=199&list=PLTbQvx84FrARa9pUtZYK7t_UfyGMCPOBn
– https://www.youtube.com/watch?v=wZ7cxcU4iPE&t=25s (3 heures de bonheur 🙂 Non, franchement, cette vidéo est excellente !!)

J’espère que cet exemple t’a permis de mieux comprendre l’architecture hexagonale. Si tu as des questions ou des remarques, n’hésites pas à les envoyer.

6 thoughts on “Architecture hexagonale: Prends ton livre et n’fais pas de bruit dans ma bibliothèque !!”

  1. Salut

    Tu utilises tes objets de domaine a l’intérieur d’un DTO. ( https://github.com/mottezjulien/takebook_part1_hexagonal_architecture/blob/master/takebook-facade/takebook-facade-spring-web/src/main/java/fr/lapausedev/takebook/facade/web/transport/object/BookDTO.java )

    Je trouve que ça introduit du couplage entre ton domaine ( interne ) et l’extérieur. Du coup, si tu modifies ton objet de domaine, ton API change transitivement.

    Tu as d’ailleurs utilisé ce que tu appelles des assembler permettant de convertir DTO vers domaine et réciproquement. Le rôle de ces assemblers (qui sont selon moi des adapters si on utilise le jargon ), en plus de permettre de passer d’un modèle a l’autre est de casser a la compilation au lieu que ce soit ton API qui ne fasse.

    On peut les voir comme des amortisseurs de voiture qui absorbent des chocs.

    C’est une bonne idée d’utiliser les modules de java 9 dans ton exemple car ils vont forcer le développeur a se poser la question de qui peut dépendre de quoi. Ce qui est fondamental selon moi quand on réfléchit a une architecture hexagonale. L’orientation des dependences devient explicite.

    Par ailleurs on comprend assez bien l’utilité de l’inversion de dépendance quand on souhaite isoler le domaine de l’extérieur.

    Tu as raison concernant les tests, ils deviennent plus facile pour vérifier le comportement de ce qui concerne strictement les règles métier. Un cas d’utilisation que je vois est la réécriture ou l’évolution des technologies d’infrastructure. Ne pas oublier quand-même d’écrire en plus quelques tests d’intégration pour vérifier que tout se branche bien correctement 😀

    En ayant complètement isolé le métier, on peut réécrire ou écrire une application de basant sur le même métier. On peut imaginer un bot slack par exemple avec une API conversationnelle pour gérer ses livres.

    Ou encore une ligne de commande. On peut également introduire du messaging asynchrone avec rabbitmq… Le domaine ne change pas.

    Bravo pour cet article, c’est un bel effort de vulgarisation.

    1. Je te remercie pour l’ensemble de tes remarques.

      Pour les tests d’intégration, je suis d’accord. Je n’ai pas eu le courage de le faire … 🙂

      Je suis d’accord, il faut normalement vérifier toutes les entrées de l’application, la couche contrôleur pourrait ajouter des vérifications pour voir si les DTOs sont conformes (ces fameux amortisseurs :))

      D’ailleurs, la classe LibraryServiceImpl (https://github.com/mottezjulien/takebook_part1a_hexagonal_architecture/blob/master/takebook-domain/src/main/java/fr/lapausedev/takebook/domain/service/internal/LibraryServiceImpl.java), il y a par exemple la fonction reload, car, je n’ai pas confiance en l’extérieur. 😉

      Par contre, pour ta première remarque, j’utilise des DTO pour être découpé du domaine. Je comprends ce que tu veux dire car mon DTO affiche l’ensemble des données du domaine, mais le but reste d’être découpé. On pourrait créer des DTO spécifique pour la requête et pour la réponse de chaque service REST afin d’être vraiment découpé. Ça serait plus intéressant ?

        1. OK, pareil, j’ai fait en plus simple. Cet article m’a pris pas mal de temps et j’avoue que je m’arrête des que l’exemple est concret pour mon article. Mais je comprends ta remarque, j’essayerai d’y faire attention pour les articles suivants et je transformerai des que je pourrai …

          Je vais regarder ton lien.

          1. Hello, après plusieurs mois je reviens sur le sujet. Après m’être également cassé les dents sur une archi hexagonale en production. Le projet était relativement simple et les indirections ajoutées par certains mappings de DTO (+ les tests associés) étaient fastidieuses. Nous avons du coup choisi un compromis “hexagonal light”. Notre API retournait directement les objets du domaine (qui étaient sérialisés avec Jackson). Ajouter une couche de dto n’ajoutait que de la compléxité et des mappings inutiles (en tout cas pour la taille et la compléxité du projet).

            Du coup je reviens un peu sur mon commentaire précédent. Essayer d’avoir une approche hexagonale “puriste” peut être contre productif dans le contexte d’une application relativement simple. Ca gagne en intéret si l’application et le domaine se compléxifient et si les DTO sont applatis par exemple ce qui justifie un peu plus un mapping et un découplage avec le domaine. Egalement si ton API est consommée par des clients que tu ne maitrise pas, les DTOS te permettent de maintenir ton API compatible tout en te permettant de faire évoluer ton domaine.

  2. Pingback: Architecture hexagonale: Interactions entre hexagones – La pause Dev'

Leave a Reply

Your email address will not be published. Required fields are marked *