Architecture Hexagonale: Découplez votre logique métier de votre code technique (HexArch)

Logique métier à la mer!

Pendant une de mes missions, mon équipe a été appelée à porter une ancienne application sur une nouvelle stack (e.g. passer d’une application EAR / SQL à une application autonome / NoSQL). Lors de l’analyse, nous avons rapidement réalisé que nous devions refaire toute l’infrastructure… les nouveaux frameworks étaient tellement différents de ceux utilisés il y a dix ans. En fait, la logique de l’entreprise était la seule chose qui n’avait pas changé. Il était donc logique de vouloir réutiliser le code métier, non?

classic layered architecture (1)
une architecture classique en couche

Après un examen plus approfondi, le module maven nommé model était composé uniquement de POJOs, totalement anémiques … et bien qu’il y ait aussi un module de service, la logique métier était partagée entre toutes les couches (création de DAO, sérialisation, gestion de pool, etc…). Et aucun moyen de l’extraire correctement, certaines parties du code métier reposaient sur le comportement technique de l’ancienne infrastructure que nous essayions de supprimer. Et pourquoi? Parce qu’il n’y avait pas de séparation nette entre le code technique et la logique métier.

Ségrégation des responsabilités

Nous avons cherché un moyen de réaliser cette séparation de telle sorte que si nous devions un jour changer à nouveau la stack, nous pourrions réutiliser totalement la logique métier. Et l’un de nos collègues nous a parlé de l’architecture hexagonale . L’un des concepts clés de cette architecture est de mettre tous les modèles/logiques métier en un seul endroit. Donc, si je reviens sur le schéma précédent, nous aurons quelque chose comme ceci:

overview of classic layered arch with domain

Un autre concept clé est que le domaine ne dépend que de lui-même ; C’est le seul moyen de garantir que la logique métier est découplée des couches techniques. Comment pouvons-nous y parvenir sur le schéma précédent? Le domaine dépend clairement de la couche de persistance! Eh bien, en utilisant un mécanisme que vous connaissez peut-être: l’inversion de contrôle. Si nous refaisons le schéma précédent avec ceci – en appelant le domaine l’Hexagone parce qu’Alistair Cockburn (créateur de l’HexArch) aime la géométrie – nous aurons quelque chose comme ceci:

overview of hex arch

Ok l’inversion de contrôle était assez magique, nous verrons plus tard comment ça marche. Mais maintenant vous avez un aperçu de ce qu’est l’architecture hexagonale:

  • Seulement deux mondes, à l’intérieur de l’Hexagone,avec tous les modèles / logiques métier, en dehors de l’Hexagone: l’infrastructure – c’est-à-dire tout votre code technique.
  • Les dépendances vont toujours de l’extérieur vers l’intérieur de l’Hexagone, ce qui garantit l’isolement du domaine métier (pour pouvoir être réutilisé si vous modifiez ultérieurement votre infrastructure!).
  • Un corollaire de ceci est que l’Hexagone ne dépend que de luimême, et pas seulement de vos propres couches: il ne doit pas dépendre d’un framework technique, y compris des annotations externes comme Jackson ou JPA. Pour vous en assurer, si vous utilisez maven, vous pouvez utiliser le plugin enforcer.

Laissez-moi vous expliquer un peu plus le dernier point, qui est vraiment important. Dans une autre expérience, mon équipe a dû porter une application du framework Spring «classique» à Spring Boot. Spring Boot simplifie beaucoup de choses pour vous; cela signifie qu’il peut être parfois très différent du framework Spring. Le principal problème (douloureux) que nous avons rencontré est que nous nous sommes beaucoup appuyés sur les tests d’intégration de Spring pour valider nos fonctionnalités et que ces fonctionnalités dépendaient beaucoup de Spring. Et parce que nous n’avions pas réalisé que Spring Boot avait une intégration spéciale avec un autre framework que nous utilisions, la toute première fois que nous l’avons intégré, tous ces tests ont échoué. Nous n’avons pas été en mesure de dire si nous avons cassé la logique métier quelque part ou si cela venait d’un problème technique pur. Lorsque nous avons compris que cela était lié à un problème d’intégration au niveau du test, nous avons corrigé tous les tests un à un en croisant les doigts, espérant que le domaine était toujours correct.

En s’assurant que l’hexagone ne dépend d’aucun framework, on s’assure que le domaine métier peut être réutilisé même si vous décidez de modifier votre stack .Vous allez également augmenter la testabilité de votre domaine car vous ne le mélangez plus avec des problèmes d’intégration, vous allez donc faire de vrais tests fonctionnels. De cette façon, ces tests interagiront directement avec l’hexagone et seulement avec lui; Je vais en parler plus tard.

Le tour de magie de l’architecture hexagonale

Vous vous rappelez de l’inversion de contrôle? Afin d’assurer l’isolement de l’hexagone, les dépendances sur les couches en aval ont été inversées. L’astuce est en fait assez simple, comme vous pouvez le voir:

hexagon (15)

L’extérieur de l’hexagone (l’infrastructure) est divisé en deux parties virtuelles, la gauche et la droite. A gauche, vous avez tout ce qui va interroger le domaine (le contrôleur, la couche REST, etc.) et à droite, vous avez tout ce qui fournira des informations / services au domaine (couche de persistance, services tiers, etc). Pour permettre à l’extérieur d’interagir avec le domaine, l’hexagone fournit des interfaces métier réparties en deux catégories:

  • L’API rassemble toutes les interfaces pour tout ce qui doit interroger le domaine. Ces interfaces sont implémentées par l’hexagone.
  • La SPI (Service Provider Interface) regroupe toutes les interfaces requises par le domaine pour récupérer des informations ou obtenir des services de tiers. Ces interfaces sont définies dans l’hexagone et implémentées du côté droit de l’infrastructure. Nous verrons que dans certaines circonstances, l’Hexagone peut également implémenter la SPI.

Il y a deux faits importants ici:

  • L’API et la SPI font partie de l’hexagone.
  • L’API et la SPI ne manipulent que les objets de domaine de l’hexagone, ce qui garantit l’isolement.

Dans une architecture en couches classique, l’objet métier ou le service crée généralement les objets DAO de la couche de persistance, comme expliqué ici . Dans HexArch, le domaine ne gère que les objets métier. La couche de persistance est chargée de traduire (adapter) les objets du domaine en objets techniques à persister (par le biais de DAO, de POJO JPA annotés ou autres).

Can you feel the force?

L’architecture hexagonale est également appelée architecture des ports et des adaptateurs. Cela vient de la puissance de la modularité de cette architecture. Comme tout est découplé, vous pouvez avoir des couches SOAP, REST et JMS devant votre domaine en même temps, sans impact. Du côté de la SPI, vous pouvez passer d’une implémentation de connectivité MongoDB à Cassandra si nécessaire. Comme la SPI ne changera pas car vous modifiez le module de persistance, le reste de votre logiciel ne sera pas impacté. L’API et la SPI sont les ports et les modules d’infrastructure qui les utilisent ou les implémentent sont les adapteurs.

Comment le mettre en œuvre?

Encore une règle ici: commencez toujours par l’intérieur de l’hexagone. Cela vous apportera beaucoup d’avantages:

  • Se focaliser sur la fonctionnalité au lieu des détails techniques. Parce que seule la fonctionnalité apporte de la valeur à votre entreprise. Un développeur travaillant sur un autre domaine est en mesure de mettre en place un contrôleur Spring. Mais la méthode d’amortissement dégressif à taux double ressemblera à du Wookiee pour lui à moins de travailler pour une société de comptabilité.
  • Retarder les choix sur l’implémentation technique. Parfois, il est vraiment difficile de savoir quelle implémentation technique vous avez vraiment besoin (comme Spring Data, JPA ou Mongo vs Cassandra vs Redis, etc.). Retarder ce choix vous aide à vous concentrer sur ce qui apporte vraiment de la valeur à votre entreprise: la fonctionnalité. De plus, après avoir implémenté les logiques métier, de nouveaux éléments peuvent vous aider à faire le meilleur choix concernant votre infrastructure (par exemple, plus de lectures que d’écritures ou le domaine est beaucoup plus relationnel que prévu).
  • Un corollaire est que l’ hexagone est autonome, j’ai déjà beaucoup parlé de l’isolement, c’est donc maintenant triviale. Puisque vous ne devez jamais écrire de code sans tests, cela signifie que l’hexagone est auto-testé. De plus, ceci nous apporte de véritables tests fonctionnels / d’acceptation axés uniquement sur le métier.

Mon conseil est d’écrire d’abord votre scénario fonctionnel / d’acceptation en BDD / ATDD. Ensuite, écrivez l’interface API qui sera le point d’entrée de votre fonctionnalité. Implémentez vos tests (TDD for the win!) ensuite implémentez votre logique métier. Vous devrez peut-être définir une SPI – pour récupérer certaines données de la base de données, par exemple – c’est très bien, allez-y! Et comme le côté droit n’est pas encore implémenté, créez une implémentation du SPI dans votre hexagone (par exemple une base de données en mémoire utilisant une HashMap).

hexagon implementation (2)

Vous pouvez choisir de conserver l’implémentation stubbée dans le scope de test de votre application, ou vous pouvez également la livrer si nécessaire. Par exemple, une fois que nous avons créé la première fonctionnalité sur l’hexagone, nous avions besoin de stubber un service tiers externe et la base de données. Comme notre client attendait un contrat d’interface, nous avons ensuite exporté le domaine via un contrôleur REST. Nous avons donc livré une première version avec des données mockées dans le côté droit de l’infrastructure, mais le client a pu voir la structure de nos messages et le comportement attendu de la fonctionnalité. Et c’était beaucoup plus fiable que de créer à la main des exemples en JSON de ce que seraient les entrées et les sorties de la fonctionnalité, car ici  les contraintes métier sont réellement prises en compte.

La prochaine étape consiste généralement à ouvrir le côté gauche en premier. De cette façon, vous pouvez mettre en place des tests d’intégration sur la fonctionnalité. À partir de maintenant vous pouvez fournir une documentation live et assurer un contrat d’interface avec vos clients.

hexagon implementation left

Enfin, ouvrez à droite en implémentant la SPI de votre fonctionnalité en profitant des tests d’intégration que vous avez effectués. Je recommande fortement que vos tests soient autonomes pour éviter toute instabilité pendant la construction. Vous devriez toujours vous affranchir de vos tiers lors de vos tests en utilisant quelque chose comme Wiremock pour des services externes ou Fongo pour simuler un MongoDB.

hexagon implementation with right

Puis faites de la même manière pour vos autres fonctionnalités.

HexArch en quelques mots

Il y a un réel avantage à dissocier la logique métier du code technique. Cela garantit que votre domaine métier est durable et robuste face à l’évolution continuelle des stacks techniques.

L’architecture hexagonale vous offre un véritable moyen d’y parvenir en:

  • Mettant tous les modèles et logiques métier au même endroit.
  • Le domaine (l’intérieur d’hexagone) est isolé et agnostique vis-à-vis de la partie technique (infrastructure hors de l’hexagone) car il ne dépend que delui-même. C’est pourquoi les dépendances vont toujours de l’extérieur vers l’intérieur de l’hexagone.
  • L’Hexagone est un module autonome. Il augmente la testabilité de votre domaine en écrivant des vrais tests fonctionnels qui ne doivent pas être impactés par des problèmes techniques.
  • Cette architecture offre une modularité puissante, qui vous permet d’écrire autant d’adaptateurs que vous le souhaitez avec un faible impact sur le reste du logiciel. Et comme le domaine est indépendant des framework, la stack technique peut être modifiée sans impact sur le métier.
  • En commençant toujours par l’intérieur de l’hexagone, vous vous assurez de créer rapidement de la valeur pour votre entreprise en mettant l’accent sur le développement des fonctionnalités. De cette façon, vous pouvez remettre à plus tard les choix sur l’implémentation technique afin que le meilleur choix puisse être fait au bon moment.

Quelques retours

L’architecture hexagonale ne doit pas être utilisée dans toutes les situations. Comme le DDD (et HexArch fonctionne très bien avec), cela est vraiment applicable si vous avez un vrai domaine métier. Pour une application qui ne fait que de la conversion de format pour des données, cela peut être overkill.

Pour finir, soyez toujours pragmatique lorsque vous adoptez une nouvelle technologie. Comme indiqué précédemment, l’Hexagone ne doit dépendre d’aucun framework technique, mais exceptionnellement vous pouvez. Par exemple, dans notre cas, l’hexagone comportait trois exceptions: Apache Commons Lang3 (StringUtils), SLF4J et JSR305 de Findbugs. Parce que nous ne voulions pas recréer la roue et nous avons estimé que ces frameworks avaient des impacts très faibles sur le domaine. Un bon effet de bord de HexArch est que vous n’arrêtez pas de vous challenger avant d’intégrer un nouveau framework. Avant HexArch, nous avions environ cinquante dépendances pour le domaine et maintenant elles ont été réduites à trois ou quatre. Et c‘est très bien d’un point de vue sécurité.

Liens externes

Vous pouvez également trouver ici un excellent article sur l’architecture hexagonale: https://softwarecampament.wordpress.com/portsadapters/

One Comment Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.