Slide 1

Slide 1 text

#mixit19 D’une architecture N-Tiers à une architecture Clean Hexagonale - Céline Gilet - 23 mai 2019

Slide 2

Slide 2 text

#mixit19 Faisons connaissance 2 Céline Gilet ๏ Tribu Software Craftsmanship à OCTO Technology ๏ Développeuse depuis + de 10 ans ๏ Conseil & accompagnement sur les pratiques de qualité logicielle ๏ Formation (Test Driven Development, Clean Code, Legacy Code...) @celinegilet Céline Gilet

Slide 3

Slide 3 text

#mixit19 Objectifs de la session ๏ Les limites d’un design applicatif basé sur une organisation en couches techniques ๏ Les principes de l’architecture hexagonale et de la clean architecture pour simplifier la maintenabilité et l’évolutivité ๏ Une projection sur une base de code > Isoler le coeur métier de tout le reste (outils, frameworks, briques d’infrastructure) > S’abstraire des accès à une base de données / un système de fichiers / un serveur de mail 3

Slide 4

Slide 4 text

#mixit19 01 02 03 04 05 Happy Town - Installation & découverte du sujet Maintenabilité et évolutivité du code Vers une architecture clean hexagonale Table des matières Clean Architecture - Step by Step Hexagonale Architecture 4

Slide 5

Slide 5 text

MiXiT Happy Town Installation & découverte du sujet 01

Slide 6

Slide 6 text

#mixit19 Prise en main du sujet Installation du projet : https://github.com/celinegilet/happy-town 6 A la découverte de notre fil rouge “Happy Town” Pour accueillir dignement ses nouveaux habitants, le conseil municipal de HappyTown a décidé d’offrir un cadeau à tous ses habitants qui soufflent leur première bougie dans la commune. Le rôle de notre application est donc : ๏ De sélectionner les habitants éligibles à l’obtention d'un cadeau (ils ont emménagés depuis plus de 1 an) ๏ Pour chacun des habitants éligibles : > Trouver le cadeau approprié en fonction de son âge : il y a des cadeaux différents par tranche d’âge > Envoyer un mail annonçant l'attribution du cadeau ๏ Envoyer un mail récapitulatif au service cadeau de la mairie avec tous les cadeaux attribués de la journée

Slide 7

Slide 7 text

#mixit19 Prise en main du sujet 7 Une représentation graphique de “Happy Town” Attribuer un cadeau aux habitants de HappyTown fêtant leur 1er anniversaire dans la commune Base de données H2 contenant les habitants Fichier des cadeaux par tranche d’âge Base de données H2 contenant les habitants + cadeaux Mails envoyés aux habitants Mail récapitulatif des cadeaux par jour User Interface Terminal API Tâche automatique Entrée Sortie Déclencheurs Application

Slide 8

Slide 8 text

#mixit19 Prise en main du sujet 8 Schéma de l’architecture actuelle : 3-Tiers Base de données H2 Données Métier Présentation User Interface Terminal API Tâche automatique Controller MVC Service Repository HabitantController HappyTownController HabitantService HappyTownService HabitantRepository Domain Habitant Cadeau TrancheAge Configuration Spring Swagger Schedule Task

Slide 9

Slide 9 text

MiXiT Maintenabilité et évolutivité du code 02

Slide 10

Slide 10 text

#mixit19 Maintenabilité et évolutivité du code 10 Revue collective de code

Slide 11

Slide 11 text

#mixit19 Maintenabilité et évolutivité du code 11 Limites actuelles ๏ Du code centré autour des frameworks ๏ Un découpage et une architecture par responsabilité technique (controller / service / repository) ๏ Le modèle métier est à la fois le modèle de stockage et le modèle de présentation ๏ Une perte de la logique métier et des services de l’application ๏ Un fort couplage et une adhérence aux composants d’infrastructure (serveur de mail, système de fichiers) ๏ Des difficultés à écrire des tests rapidement qui représentent le métier ๏ Des tests écrits à posteriori avec une stratégie de couverture de code (absence de TDD / design émergent) ๏ Évolutions de + en + difficile (en durée et complexité)

Slide 12

Slide 12 text

#mixit19 Maintenabilité et évolutivité du code 12 Une pyramide de tests sans base solide ๏ Une pyramide de tests dont la base démarre au niveau “Intégration” ๏ Des tests avec un caractère aléatoire ๏ Une nécessité de démarrer un serveur de mail pour tester les règles métiers ๏ Une stratégie de tests basée sur le fonctionnement de frameworks Unitaire Intégration Fonctionnel Coût Temps d’exécution Précision / Fiabilité Rapidité Quantité de tests

Slide 13

Slide 13 text

MiXiT Vers une architecture clean hexagonale 03

Slide 14

Slide 14 text

#mixit19 Vers une architecture clean hexagonale 14 Dans quel but ? ๏ La valeur d’une application réside dans ses cas d’utilisation et ses services métiers ๏ Isoler et protéger cette valeur des changements et évolutions techniques ๏ Le domaine métier d’une application n’ évolue pas au même rythme que les éléments connexes ๏ Une prise en compte des aspects techniques à posteriori ๏ Pas de dispersion de la logique métier dans plusieurs couches ๏ Des tests ciblés sur une problématique précise : rapidité, fiabilité et robustesse ๏ Un découpage par responsabilité pour favoriser les évolutions et accélérer le cycle des déploiements ๏ Des mises à jour de dépendances techniques plus régulières

Slide 15

Slide 15 text

#mixit19 Vers une architecture clean hexagonale 15 Clean Architecture / Hexagonale Architecture Clean Architecture - Uncle Bob Martin - L’élément clé d’une application ne réside pas dans sa base de données et les frameworks utilisés. Les use-cases d’une application sont l’élément central Hexagonale Architecture - Alistair Cockburn - Permettre à une application d’être pilotée aussi bien par des utilisateurs que par des programmes, des tests automatisés ou des scripts batchs, et d’ être développée et testée en isolation de ses éventuels systèmes d’exécution et bases de données

Slide 16

Slide 16 text

#mixit19 Vers une architecture clean hexagonale 16 Clean Architecture Principes ๏ Un centre contenant la logique métier sans framework ni annotation > Entities - Objets du domaine > Use Cases - Services applicatifs ๏ Des points d’entrée (Entrypoints) pour déclencher les use cases : API Rest, interface graphique, jobs ๏ Des fournisseurs de données (DataProviders) pour récupérer et stocker les données : BDD, périphériques réseau, fichiers, systèmes externes ๏ Les éléments de configuration (Configuration) Source : http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

Slide 17

Slide 17 text

#mixit19 Vers une architecture clean hexagonale 17 Hexagonale Architecture Principes ๏ Intérieur vs Extérieur ๏ Découpage en 3 zones distinctes > Application - les moyens d’interactions pour piloter / déclencher le métier > Domain - la logique métier > Infrastructure - les besoins et dépendances nécessaires au métier (BDD, Systèmes extérieurs, File System) ๏ Sens des dépendances uniquement vers l’intérieur : le “Domain” ๏ Isolation des frontières par des Ports et Adapters (Interfaces) DOMAIN INFRASTRUCTURE APPLICATION INTÉRIEUR EXTÉRIEUR Adapter Adapter Port Port Logique Métier Sens des dépendances

Slide 18

Slide 18 text

MiXiT Clean Architecture Step by Step 04

Slide 19

Slide 19 text

#mixit19 Clean Architecture - Step by step 19 Cartographie et projection Use-Cases ๏ Récupérer les informations des habitants de HappyTown ๏ Attribuer un cadeau aux habitants de HappyTown Déclencheurs ๏ Un terminal console (CURL endpoint) ๏ Une interface graphique (swagger-ui.html) ๏ Une tâche automatisée ๏ Des tests Fournisseurs de données ๏ Base de données H2 contenant les habitants ๏ Fichier contenant les cadeaux par tranche d’âge ๏ Serveur de mail

Slide 20

Slide 20 text

#mixit19 Clean Architecture - Step by step 20 Migration de l’architecture actuelle 3-Tiers Base de données H2 Données Métier Présentation User Interface Terminal API Tâche automatique Controller MVC Service Repository HabitantController HappyTownController HabitantService HappyTownService HabitantRepository Domain Habitant Cadeau TrancheAge Configuration Spring Swagger Schedule Task

Slide 21

Slide 21 text

#mixit19 Clean Architecture - Step by step 21 Schéma cible entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants CadeauRandom rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa file CadeauxByTrancheAgeFileProvider mail NotificationMailProvider Application Habitant Provider N otification Provider Exception CadeauxBy TrancheAge Provider Exception

Slide 22

Slide 22 text

#mixit19 Clean Architecture - Step by step 22 Un programme en 8 étapes Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 23

Slide 23 text

#mixit19 Clean Architecture - Step by step 23 Step 01 : Réorganisation du code Step 01 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 24

Slide 24 text

#mixit19 Clean Architecture - Step by step 24 Step 01 : Réorganisation du code entrypoints core dataproviders entities Cadeau | Habitant TrancheAge use_cases Application Step 01

Slide 25

Slide 25 text

#mixit19 Clean Architecture - Step by step 25 Step 01 : Réorganisation du code ❏ Création de la nouvelle structure de packages ❏ core (entities + use_cases) ❏ entrypoints ❏ dataproviders ❏ Déplacement des objets de domain vers entities ❏ Suppression des frameworks / annotations (Lombok, Javax Validation) Step 01

Slide 26

Slide 26 text

#mixit19 Clean Architecture - Step by step 26 Step 02 : Récupération des habitants Step 02 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 27

Slide 27 text

#mixit19 Clean Architecture - Step by step 27 Step 02 : Récupération des habitants entrypoints core dataproviders entities Cadeau | Habitant TrancheAge use_cases GetAllHabitants database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa Application Habitant Provider Step 02

Slide 28

Slide 28 text

#mixit19 Clean Architecture - Step by step 28 Step 02 : Récupération des habitants ❏ Ajout d’un use case pour récupérer tous les habitants : GetAllHabitants ❏ Nécessité d’avoir un nouveau fournisseur de données pour les habitants : HabitantProvider ❏ Implémentation du fournisseur de données des habitants en base de données : HabitantDatabaseProvider ❏ Séparation entre les objets du domaine métier : Habitant et le modèle de stockage : HabitantJpa ❏ Suppression du package repository Step 02

Slide 29

Slide 29 text

#mixit19 Clean Architecture - Step by step 29 Step 03 : Visualisation des habitants Step 03 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 30

Slide 30 text

#mixit19 Clean Architecture - Step by step 30 Step 03 : Visualisation des habitants entrypoints core dataproviders entities Cadeau | Habitant TrancheAge use_cases GetAllHabitants rest HabitantEndpoint HabitantApi database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa Application Habitant Provider Step 03

Slide 31

Slide 31 text

#mixit19 Clean Architecture - Step by step 31 Step 03 : Visualisation des habitants ❏ Ajout d’un entrypoint rest pour récupérer la liste des habitants : HabitantEndpoint ❏ Séparation entre les objets du domaine métier : Habitant et le modèle de présentation : HabitantApi ❏ Suppression de HabitantController et HabitantService ❏ L’objet Habitant est maintenant agnostique de tout framework technique (présentation, persistence) Step 03

Slide 32

Slide 32 text

#mixit19 Clean Architecture - Step by step 32 Step 04 : Attribution des cadeaux Step 04 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 33

Slide 33 text

#mixit19 Clean Architecture - Step by step 33 Step 04 : Attribution des cadeaux entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa Application Habitant Provider Step 04

Slide 34

Slide 34 text

#mixit19 Clean Architecture - Step by step 34 Step 04 : Attribution des cadeaux ❏ Ajout d’un use case pour attribuer les cadeaux : AttribuerCadeaux ❏ Ajout d’un entrypoint rest pour attribuer les cadeaux : AttributionCadeauxEndpoint ❏ Suppression de HappyTownService ❏ Le comparateur des tranches d’âge TrancheAgeComparator rejoint le package des entities ❏ Suppression du package de service Step 04

Slide 35

Slide 35 text

#mixit19 Clean Architecture - Step by step 35 Step 05 : Job d’attribution des cadeaux Step 05 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 36

Slide 36 text

#mixit19 entities Cadeau | Habitant TrancheAge TrancheAgeComparator Clean Architecture - Step by step 36 Step 05 : Job d’attribution des cadeaux entrypoints core use_cases AttribuerCadeaux GetAllHabitants CadeauRandom dataproviders rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa Application Habitant Provider Step 05

Slide 37

Slide 37 text

#mixit19 Clean Architecture - Step by step 37 Step 05 : Job d’attribution des cadeaux ❏ Ajout d’un entrypoint jobs pour la tâche automatique d’attribution de cadeaux : AttributionCadeauxJob ❏ Déplacement de la classe de configuration SwaggerConfig dans le package rest des entrypoints ❏ Suppression du package de configuration ❏ Mise en place d’un mécanisme de vérification du respect de la clean architecture (sens des dépendances) : tools/check-cleanArchi.sh Step 05

Slide 38

Slide 38 text

#mixit19 Clean Architecture - Step by step 38 Step 06 : Notification par mail Step 06 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 39

Slide 39 text

#mixit19 Clean Architecture - Step by step 39 Step 06 : Notification par mail entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa mail NotificationMailProvider Application Habitant Provider N otification Provider Exception Step 06

Slide 40

Slide 40 text

#mixit19 Clean Architecture - Step by step 40 Step 06 : Notification par mail ❏ Sortie de la partie concernant les mails ❏ Nouveau Provider + Exception Métier : NotificationProvider + NotificationException ❏ Implémentation d’un mail provider : NotificationMailProvider avec les infos de config : smtpHost + smtpPort ❏ Suppression de la config du serveur de mail dans les use cases + entrypoints ❏ Tests unitaires du use case : AttribuerCadeaux (plus de lancement de serveur de mail) : rapidité, fiabilité ❏ Changement de la librairie de mail pour les tests unitaires : FakeSmtpRule Step 06

Slide 41

Slide 41 text

#mixit19 Clean Architecture - Step by step 41 Step 07 : Récupération des cadeaux par tranche d’âge Step 07 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 42

Slide 42 text

#mixit19 Clean Architecture - Step by step 42 Step 07 : Récupération des cadeaux par tranche d’âge entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa file CadeauxByTrancheAgeFileProvider mail NotificationMailProvider Application Habitant Provider N otification Provider Exception CadeauxBy TrancheAge Provider Exception Step 07

Slide 43

Slide 43 text

#mixit19 Clean Architecture - Step by step 43 Step 07 : Récupération des cadeaux par tranche d’âge ❏ Sortie de la partie concernant la récupération des cadeaux par tranche d’âge ❏ Nouveau Provider + Exception Métier : CadeauxByTrancheAgeProvider + CadeauxByTrancheAgeException ❏ Implémentation d’un file provider : CadeauxByTrancheAgeFileProvider avec les informations de config : fileName ❏ Suppression des infos de config du fichier dans les use cases + entrypoints ❏ Suppression des infos de dateCourante dans les use cases et les entrypoints avec injection d’une Clock Step 07

Slide 44

Slide 44 text

#mixit19 Clean Architecture - Step by step 44 Step 08 : Refactoring Step 08 Step 01 Réorganisation du code Step 02 Use Case “Récupération des habitants” Step 03 Visualisation des habitants Step 04 Use Case “Attribution des cadeaux” Step 05 Job d’attribution des cadeaux Step 06 Notification par mail Step 07 Récupération des cadeaux par tranche d’âge Step 08 Refactoring

Slide 45

Slide 45 text

#mixit19 Clean Architecture - Step by step 45 Step 08 : Refactoring entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants CadeauRandom rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa file CadeauxByTrancheAgeFileProvider mail NotificationMailProvider Application Habitant Provider N otification Provider Exception CadeauxBy TrancheAge Provider Exception Step 08

Slide 46

Slide 46 text

#mixit19 Clean Architecture - Step by step 46 Step 08 : Refactoring ❏ Mise en place de templates de messages pour les mails ❏ Ajout d’un use case d’attribution de cadeau aléatoire : CadeauRandom ❏ Ajout de fixtures pour simplifier l’ écriture des tests ❏ Refactoring divers Step 08

Slide 47

Slide 47 text

#mixit19 Clean Architecture - Step by step 47 Schéma final entrypoints core dataproviders entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants CadeauRandom rest AttributionCadeauxEndpoint HabitantEndpoint HabitantApi SwaggerConfig jobs AttributionCadeauxJob database HabitantDatabaseProvider HabitantJpaRepository HabitantJpa file CadeauxByTrancheAgeFileProvider mail NotificationMailProvider Application Habitant Provider N otification Provider Exception CadeauxBy TrancheAge Provider Exception

Slide 48

Slide 48 text

MiXiT Hexagonale Architecture 05

Slide 49

Slide 49 text

#mixit19 Hexagonale Architecture 49 Schéma final application domain infrastructure entities Cadeau | Habitant TrancheAge TrancheAgeComparator use_cases AttribuerCadeaux GetAllHabitants CadeauRandom rest AttributionCadeauxAdapter HabitantAdapter HabitantApi SwaggerConfig jobs AttributionCadeauxJobAdapter database HabitantDatabaseAdapter HabitantJpaRepository HabitantJpa file CadeauxByTrancheAgeFileAdapter mail NotificationMailAdapter Application Habitant Port N otification Port Exception CadeauxBy TrancheAge Port Exception

Slide 50

Slide 50 text

#mixit19 Debrief et conclusions 50 Les apports dans notre quotidien ● Isolation et protection du métier ● Totale indépendance vis à vis des frameworks avec un métier clair et explicite ● Meilleure testabilité orientée sur le comportement métier ● Une pyramide de tests saine pour les évolutions et la maintenance ● Séparation claire des problèmes Discuter en équipe de votre choix d’architecture : clean architecture, hexagonale architecture ou un mix des deux ou une autre… L’important est de redonner sa place au métier et de sortir des architectures à découpage technique

Slide 51

Slide 51 text

#mixit19 MERCI ! :) - Céline Gilet - @celinegilet

Slide 52

Slide 52 text

#mixit19 Références ๏ https://github.com/celinegilet/happy-town ๏ https://blog.octo.com/architecture-hexagona le-trois-principes-et-un-exemple-dimplementati on/ ๏ https://github.com/damienbeaufils/clean-arc hitecture-demo ๏ https://blog.cleancoder.com/uncle-bob/2012 /08/13/the-clean-architecture.html ๏ https://github.com/mattia-battiston/clean-arc hitecture-example 52