1 of 40

Architecture hexagonale

@pauline_io

2 of 40

Principes

@pauline_io

3 of 40

@pauline_io

4 of 40

@pauline_io

5 of 40

  • Techniquement
    • package (sans dépendance vers les autres packages)
    • module
  • Egoïste :
    • ne parle que son langage
    • ne connaît que lui même
    • independent des technos
  • Implémentation des règles de gestion : Modèle + Service
  • DAO
  • File gateway
  • Clients WS / API REST
  • Producer / Consumer mom (rabbitmq, kafka… )
  • Application (playframework, springboot, angular, framework d’injection de dépendence…)
  • ...
  • ...tout connecteur technique…
  • ...
  • Pas de règles de gestion

Business

Infra

6 of 40

Business : domaine, code métier

  • Le domaine ne connaît qui lui même : indépendant de toute technologie
  • Techniquement
    • Pourrait être un package qui ne dépend pas des autres packages de l’application
    • Ou un module
  • Le domaine est égoïste : ne parle que son langage
  • Implémentation des règles de gestion : Modèle + Service

@pauline_io

7 of 40

Infra : code technique

  • Accès base de données : DAO
  • File gateway
  • Client de web services / API REST
  • Producer / Consumer mom (rabbitmq, kafka… )
  • Application (playframework, springboot, angular, …)
  • Autres connecteurs techniques
  • ...
  • Ne doit contenir aucune règle de gestion

@pauline_io

8 of 40

PORTS

@pauline_io

9 of 40

DRIVER

DRIVEN

RIGHT SIDE

LEFT SIDE

  • User side
  • Acteurs qui pilotent le domaine
  • API exposant le métier
  • Tests
  • Application
  • Frontend
  • Server side
  • Acteurs pilotés par domaine
  • API consommées pour le business
  • Bases de données
  • File gateway
  • MOM (rabbitmq, kafka…)

@pauline_io

10 of 40

Rabbitmq

DRIVER

DRIVEN

RIGHT SIDE

Domaine

Modèle

Services

LEFT SIDE

REST

API

Adapteurs

Image WS

@pauline_io

11 of 40

Inversion de controle

  • L’infra dépend du business (coté user side)
  • Le business ne dépend de personne, le business est égoiste il ne parle que son langage (contrats d’interfaces)
  • Framework d’injection de dépendences (guice, CDI, spring…)
    • Fait la glue entre les ports et les adapteurs
    • Configuration coté application

@pauline_io

12 of 40

Ségrégation des interfaces (SOLID)

  • Représentent les ports
  • Définition des contrats métiers : la partie la plus délicate
  • Migration des technos sans impact sur le métier

@pauline_io

13 of 40

Catalogue de produits

@pauline_io

14 of 40

Rabbitmq

DRIVER

DRIVEN

LEFT SIDE

RIGHT SIDE

Domaine

Modèle

Services

byte[] getImage(String description)

Product getProduct(String ean)

List<Product> findAllProduct()

void sendEvent(ProductEvent productEvent)

Product showProductDetail(String ean)

List<Product> showCatalog()

@pauline_io

15 of 40

Pattern : Adapteurs

  • Implémentation des ports
  • Migration technique sans impact sur le business
  • Left side

  • Right side

Controller

“interface”

ProductService

ProductServiceImpl

ProductServiceImpl

“inteface”

ProductDAO

ProductMongodbDAO

@pauline_io

16 of 40

Pattern : “Anti corruption layer”

  • Pattern : DTO
  • Modèles intermédiaires
  • Possible duplication de champs au profit du découplage
  • Les DTO absorbent les changements

@pauline_io

17 of 40

Pattern : “Anti corruption layer”

Rabbitmq

Domaine

Modèle

Services

REST

api

Modèle appartenant à l’infra : DTO

Image WS

Modèle métier

M : Modèle métier

@pauline_io

M ->

M1

M ->

M2

M ->

M3

M ->M4

M ->M5

Mn

18 of 40

Livecoding

@pauline_io

19 of 40

Application de gestion d’un catalogue produit

Livecoding

H2

products

Product view, playframework application

GET /products/<ean>

GET /products

product details

Controllers

Règles métiers

Ebean

Modèle

product events

HTML

GET /events

@pauline_io

20 of 40

Livecoding

User story : consultation des événements d’un produit

Scénario : Un admin consulte un produit

Quand un Admin consulte un produit

Alors il peut voir tous les événements liés à ce produit

Scénario : Un gestionnaire consulte un produit

Quand un gestionnaire consulte un produit

Alors il peut voir tous les événements liés au produit qui ont été créés pendant sa session mais pas les événements techniques comme CHANGE_USER_ACCESS

Scénario : Un super gestionnaire consulte un produit

Quand un super gestionnaire consulte un produit

Alors il peut voir tous les événements liés au produit qui ont été générés par lui et les autres gestionnaires mais pas les événements techniques comme CHANGE_USER_ACCESS

@pauline_io

21 of 40

New feature :

Livecoding

User story : événement de connexion

Scénario : Un utilisateur accède à l’application

Quand un user accède au site

Alors alors un événement de connexion USER_CONNECTION est créé

Scénario : Un gestionnaire consulte un produit

Quand un gestionnaire consulte un produit

Alors il peut voir tous les événements liés au produit qui ont été créés pendant sa session mais pas les événements techniques comme CHANGE_USER_ACCESS et USER_CONNECTION

Scénario : Un super gestionnaire consulte un produit

Quand un super gestionnaire consulte un produit

Alors il peut voir tous les événements liés au produit qui ont été générés par lui et les autres gestionnaires mais pas les événements techniques comme CHANGE_USER_ACCESS et USER_CONNECTION

@pauline_io

22 of 40

Livecoding

Let’s go

@pauline_io

23 of 40

Application de gestion d’un catalogue produit

Livecoding

H2

products

Product view, playframework application

GET /products/<ean>

GET /products

product details

Controllers

Ebean

Modèle

events

HTML

GET /events

RG

RG

RG

Services

RG

@pauline_io

24 of 40

Code review

Le catalogue de produit hexagonalisée

@pauline_io

25 of 40

26 of 40

Microservices

MONOLITH

MONOLITH

HEXAGONALISES

  • Séparation en packages
  • Séparation en modules

MICROSERVICES

@pauline_io

27 of 40

Liens

28 of 40

Merci

@pauline_io

29 of 40

Questions

@pauline_io

30 of 40

Comment séparer le métier de l’infra

  • Modèle de données intermédiaire : anti corruption layer
  • Interfaces
    • Elles se trouvent dans la partie métier
    • Les contrats de méthodes sont métier : c’est le plus important : définir ce que doivent faire ces contrats. Que prennent-ils en entrée et en sortie
      • Exemple du Processor qui gère la stratégie de retry du call http dans le service métier
    • Le domaine est egoiste, il ne parle que son langage, il utilise les ports avec des contrats métiers pour communiquer avec l’exterieur
  • Revoir les packages
  • Pour les composants infra les plus compliqués : pattern strangler faire un nouveau module (pour ne pas polluer l’application avec des fichiers de configurations par exemple)
    • REX sur l’isolation d’un client d’une api prets/<id>/assurances WS service SOAP axis en java4, oui parceque pour l’appeler avec de l’angular ou du vuejs, c’est compliqué. Alors la solution était de mettre un endpoint REST par dessus qui était la première version du service. Mise en place de l’api prets : premier service : recupération des assurances rattachées à un pret : appeler un WS SOAP axis java4 + des règles de gestions (springboot)

31 of 40

Pourquoi ?

  • Centraliser le code métier
  • Répondre à la problématique de manque de découplage
  • Permet de réduire le code source
    • Ecrac avec le traitement des événements dupliqués dans chaque endpoint de la couche REST
  • Permet de tester plus facilement
  • Supporte les migrations (métier pas impacté par les migrations techniques)
  • Anticiper le remboursement de la dette technique (on est systématiquement amené à faire de la dette technique à un moment donné, et faire de la dette facile à rembourser est le plus difficile. Avec l’archi hexagonal, on peut prendre des raccourcis qui seront faciles à rembourser plus tard (exemple isoler une partie du modèle avec un autres modèle)
  • Un axe à suivre pour ne pas tomber dans la normalisation de la déviance
  • Diminue l’effet code toxique, pourriture logicielle
  • Lorsqu’une partie de notre système meurt (par ex on decomissione une base de données), on ne veut pas que l’ensemble de notre système meurt, si notre nouveau système doit communique avec du legacy, on ne veut pas qu’il soit contaminé par ce legacy)

32 of 40

Pourquoi c’est bien

  • App en phase de dev, on absorbe plus facilement les changements de spécifications (besoin pas encore très sec)
  • App en prod, le métier est stable, ce sont les technos qui changent
    • Exemple de migration de bases de données : on a juste un adapteur à réécrire
  • Centraliser le métier au coeur de l’application : on peut tester toutes les règles métier avec des tests unitaires !
    • Cool car on a pas à mettre en place un gros test d’intégration
  • Une fois que le monolithe est hexagonalisé, on peut facilement aller plus loin pour faire des microservice par example

33 of 40

Comment l’amener dans l’équipe

  • Pas facile à vendre car beaucoup de principes à première vue
  • Nécessite de faire adhérer l’équipe à ce pattern
  • Nécessite que l’équipe connaisse le métier
    • Ce qui n’est jamais le cas, sauf en fin de projet. Donc même si on part sur une archi hexa, on aura surement ce travail à faire de recentrer les règles métier dans le coeur tout au long d’un projet
  • REX : meme si compliqué car ce sont des principes théoriques à intégrer il vaut toujours mieux prendre le temps de mettre en place une archi hexagonale en faisant monter l’équipe dessus en début de projet, car on sera en mesure d’absorber des changements au fur et mesure facilement et eviter de sombrer petit à petit dans l’over-complexité
  • Quoiqu’il arrive, architecture hexagonale ou pas, si les pratiques d’équipe et la culture ne sont pas bonne, cela ne fonctionnera pas -> xtrem programming
    • Je n’ai pas pu le faire passer sur un projet avec des équipes offshore en Inde. Ce qui est logique car c’est vraiment difficile d’amener ce genre de pratique lorsqu’on est pas proche de l’équipe, que la communication est très difficile, très hierarchisée (l’équipe travaillant en boite noire par rapport aux développeurs on shore)

34 of 40

Architecture hexagonal vs code legacy

  • Est ce qu’on peut hexagonaliser une application legacy, un projet sur la fin des dev?
    • Oui mais....
    • Eviter les gros refactoring : hexagonaliser tout d’un coup = impossible
      • Comment gérer le modèle unique utilisé partout dans l’application ? On change un champs, ou une méthode et on a des centaines d’impacts dans le code source.
    • On peut attaquer petit à petit : un gros effort à fournir pour isoler une feature ou un client ou un DAO… Et même cette isolation peut (doit) se faire petit à petit. Le gros effort peut être d’ajouter un nouveau code sur une feature en cohabitation avec le legacy. Evidemment si la complexité du code à atteint le stade critique et qu’on ne peut plus rien modifier, c’est mort.
    • C’est en fait une problématique de découplage.
    • L’avantage c’est qu’à ce stade du projet, on connaît bien le métier, on a surmonté quelques écueils (ou pas :p)

35 of 40

Much better pattern

  • Faire un shema avec uniquement 2 hexagones séparés
    • Ex : Microservice api-communication, microservice api-fichiers

36 of 40

Mon REX à moi

  • Comment j’ai commencé avec l’archi hexagonale
    • Forte apétance sur le design de code sans pour autant réussir à en produire de bon
    • Gérer la duplication de code a longtemp été un pb
      • Dissocier infra et metier à résolu définitivement ma vision des choses la dessus
      • Ex: gestion des erreurs http dans une class REST externalisée dans une méthode -> nuit à l’expressivité du code (attention je ne parle pas de beauté mais bien d’expressivité)
      • Ex: d’Arnaud Lemaire conséquences mutualisation des produits d’un catalogues avec les produits liés aux factures : un user change le prix d’un produit dans le catalogue et PAF -> 8000 factures fausses !!! En prod !!!
  • Les premières tentatives : des echecs qui n’en étaient pas vraiment
    • Parceque je voulais hexagonaliser toute l’appli, ou tout le microservice -> chantier trop important. Meilleurs moyen de commencer : separer le métier de l’infra, sur la feature qu’on est en train de developper, sinon on court vers l’echec
  • Les premiers pas par petites touches
    • Autre grands changement dans ma façon de voir les choses
      • On est pas obligé, non on ne doit surtout pas refactorer entièrement un code. Il faut savoir se concentrer sur 1 seul pb, 1 seul feature, 1 seul client… savoir limiter la complexité de ses taches permet de les appliquer par petites touches mais efficacement. (qui a déjà vécu ça : se lancer dans un refactoring et au bout de trois jours se retrouver dans un chaos de modifications sans en voir la fin et donc se retrouver face à deux choix possibles : abandonner et faire le deuil des 3 jours perdus, ou continuer (pour echouer de toute façon soit en abandonnant plus tard, soit apportant le chaos dans le logiciel…)
  • De plus en plus facile
    • Parler de l’exemple de la couche de DTO sur Ecrac qu’on avait au debut, puis abandonné. Puis un pb de model de model s’est posé. Une demande de format differentes pour l’api est apparue (appli : on edit un document avec une pièce justificative alors que dans la requete de l’api le besoin est d’avoir la liste de toutes les pieces justificatives) -> On a resolu en ajoutant la couche de DTO manquante qui a pris en charge ce traitement au niveau de l’api. On cela aurait très bien pu impacter le projet jusqu’au modèle de base de données

37 of 40

Les pièges

  • Vouloir hexagonaliser toute une application : trop de risques
    • Plutôt saisir l’oportunité d’un bug fix pour appliquer les règles de l’archi hexagonale juste sur la feature impactée, quitte à mettre en place une nouvelle base de code en parallèle qui va prendre le dessus au fur et à mesure (accepter d’avoir une partie du code déprécié pendent un certain temps)
  • Les pratiques de l’équipe sont souvent la causes des gros problèmes de conceptions
    • Extreme programming

38 of 40

Sources

  • Alistaire Cockburn
  • Talk d’Alistaire Cockburn : Alistair in the hexagone
  • Arnaud Lemaire : voir tous ses talks
  • Martin Fowler
  • https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/

Importance d’avoir de bons modèles, orienter ses pistes de reflexion dans la bonne direction, aller vers plus de pragmatisme, no more technico technique

39 of 40

RESTE A FAIRE

  • Exemples : service image provider, meteo, pizza… cf Alistair in the hexagone
  • Aller plus loin avec DDD : isoler complétement l’application avec des DTO : expliquer pourquoi DTO vs domain vs entities vs value objects
  • Voir Avec Seb pour son exemple de modèle trop couplé
  • Clean Architecture, EBI, port and adapter
    • Peut etre faire un topo de tout ça sur le premier slide

40 of 40

FEEDBACK LUNATECH

  • Diagramme de séquence avant/apres
  • Base de code moins dense
  • Captures d’écran
  • On a pas vu les avantages, mais seulement que ça a un cout
  • Parler de la testabilité
  • Ne pas mettre la présentation niveau débutant mais au moins intermédiaire
  • Ajouter un slide Alistair Cockburn
  • Schéma du pattern strangler avec un petit hexagone
  • Rassembler les autres feedbacks de google keep
  • Peut-être ne garder qu’un migration de base de données en livecoding : h2 vers postgresql (la base est prête mais vide) ajouter les nouveau DAO en livecoding avec des snipets.
  • Bonne pratique : commencer par un monolithe, séparer après (on a moins de chance de se tromper dans la définition des bounded contexts)