Résultat final

Infrastructure générée,
application fonctionnelle.

  • Plugins JPA et REST configurés en mono-module.
  • ~55 fichiers d'infrastructure générés automatiquement.
  • Score final 63/100, grade D, 1 violation majeure.
Configuration

Configuration HexaGlue

Le fichier hexaglue.yaml à la racine du projet configure les trois plugins actifs et déclare les exclusions de classification.
La configuration mono-module est plus simple : aucun targetModule n'est nécessaire, tout le code généré atterrit dans le même module Maven.
hexaglue.yaml
classification:
exclude:
- "com.acme.shop.infrastructure.**"
- "com.acme.shop.exception.**"
plugins:
io.hexaglue.plugin.jpa:
entitySuffix: "JpaEntity"
repositorySuffix: "JpaRepository"
adapterSuffix: "RepositoryAdapter"
generateRepositories: true
generateAdapters: true
generateEmbeddables: true
enableAuditing: false
io.hexaglue.plugin.rest:
flattenValueObjects: true
generateExceptionHandler: true
generateConfiguration: false
io.hexaglue.plugin.livingdoc:
outputDir: "living-doc"
  • Pas de targetModule : en mono-module, tout le code généré (entités JPA, repositories, adapters, controllers REST, DTOs) est produit dans le même module. HexaGlue n'a pas besoin d'instruction de routage
  • generateExceptionHandler: true : le plugin génère un @RestControllerAdvice global qui couvre IllegalArgumentException, les erreurs de validation Bean et les exceptions génériques. Il remplace le handler d'exceptions manuel qu'il n'est plus nécessaire de maintenir
  • generateConfiguration: false : la configuration Spring manuelle (ApplicationServiceConfig) est conservée car elle gère des dépendances inter-services. Par exemple, OrderApplicationService dépend d'InventoryUseCases (un driving port), pas seulement de driven ports. Le générateur ne câble que les dépendances directes vers les driven ports
  • Exclusions : infrastructure.** et exception.** sont explicitement exclus du périmètre DDD. HexaGlue ne classifie que les packages domaine, ports et application
Génération

Code généré automatiquement

Les plugins JPA et REST analysent le modèle domaine pur et génèrent toute la couche infrastructure à la compilation.
Aucun de ces fichiers n'est écrit à la main : entités JPA, repositories, mappers, adapters, controllers REST et DTOs sont tous produits au compile-time.

Plugin JPA → src/main/java

Entités JPA

CustomerJpaEntity, InventoryJpaEntity, OrderJpaEntity, PaymentJpaEntity, ProductJpaEntity, ShipmentJpaEntity

6 fichiers
Embeddables

AddressEmbeddable, MoneyEmbeddable, QuantityEmbeddable

3 fichiers
Spring Data Repositories

CustomerJpaRepository, InventoryJpaRepository, OrderJpaRepository, PaymentJpaRepository, ProductJpaRepository, ShipmentJpaRepository

6 fichiers
MapStruct Mappers

CustomerMapper, InventoryMapper, OrderMapper, PaymentMapper, ProductMapper, ShipmentMapper

6 fichiers
Repository Adapters

CustomerRepositoryAdapter, InventoryRepositoryAdapter, OrderRepositoryAdapter, PaymentRepositoryAdapter, ProductRepositoryAdapter, ShipmentRepositoryAdapter

6 fichiers

Plugin REST → src/main/java

REST Controllers

CustomerController, InventoryController, OrderController, PaymentController, ProductController, ShipmentController, NotificationController

7 fichiers
DTOs (request / response)

Objets de transfert aplatis depuis les value objects domaine (flattenValueObjects: true)

~18 fichiers
Exception Handler

GlobalExceptionHandler : gestionnaire global des erreurs domaine

1 fichier
Configuration Spring

ApplicationServiceConfig : configuration manuelle conservée avec generateConfiguration: false (dépendances inter-services)

manuelle
Total généré ~55 fichiers
  • ~55 fichiers générés remplacent le code infrastructure manuel : 27 fichiers JPA (entités, embeddables, repositories, mappers, adapters) et environ 9 fichiers REST de base (controllers, exception handler), auxquels s'ajoutent les ~18 DTOs
  • La configuration Spring reste manuelle : generateConfiguration: false parce que ApplicationServiceConfig gère des dépendances inter-services (OrderUseCasesInventoryUseCases). Le générateur ne câble que les driven ports directs. En mono-module simple (sans dépendances inter-services), generateConfiguration: true génère la config automatiquement
  • Dépendance springdoc-openapi : les controllers générés utilisent les annotations @Operation et @Tag de Swagger. Le POM doit déclarer springdoc-openapi-starter-webmvc-ui dans une version compatible avec Spring Boot (2.4.0 pour Spring Boot 3.2.5)
  • Synchronisation garantie : si le domaine évolue, toute la couche infrastructure est régénérée automatiquement à la compilation suivante, sans intervention manuelle

Rapport d'audit

Rapport d'audit final après génération automatique JPA et REST, migration des identifiants et refactoring fonctionnel.

Verdict

Verdict de l'audit

Le score final est de 63/100, grade D, statut PASSED_WITH_WARNINGS. L'architecture hexagonale atteint 100% et le DDD 95%. Une seule violation majeure subsiste, liée à une limitation du classificateur sur OrderLine.
63
/100
Grade D
PASSED (warnings)
1
violations
0
critical
1
major
+50 pts
-42 viol.

Le statut PASSED_WITH_WARNINGS reflète l'absence de violation Blocker ou Critical, avec une seule violation Major résiduelle qui ne compromet pas la conformité hexagonale.

  • Statut PASSED_WITH_WARNINGS : aucune violation Blocker ou Critical. La violation aggregate-boundary sur OrderLine est de sévérité Major : elle relève d'une limitation du classificateur (absence d'identifiant explicite), pas d'un défaut d'architecture
  • Grade D (score ≥ 60) : DDD Compliance (95%) et Hexagonal Architecture (100%) sont proches du maximum, mais Dependencies (0%) et Coupling (36%) plafonnent le score. Ces dimensions mesurent les cycles de dépendances et le couplage entre packages, indépendamment de la conformité hexagonale
Score

Décomposition du score

Le score final de 63/100 reflète l'état de chaque dimension architecturale.
DDD Compliance et Hexagonal Architecture sont proches du maximum. Dependencies et Coupling, qui mesurent les cycles inter-packages, concentrent les points perdus.
DimensionScoreStatusDelta
DDD Compliance95%+95
Hexagonal Architecture100%+100
Dependencies0%=
Coupling36%+6
Cohesion65%+7
TOTAL63.90
  • DDD Compliance à 95% : la quasi-totalité des patterns tactiques DDD sont en place (6 agrégats avec identifiants typés, 7 value objects, 2 entités, 1 domain event, ports correctement séparés). Les 5% manquants correspondent à la violation aggregate-boundary sur OrderLine
  • Hexagonal Architecture à 100% : les services applicatifs sont des POJOs purs, chaque port dispose d'un adaptateur généré, les couches sont isolées sans aucune dépendance croisée
  • Dependencies à 0% : cette dimension pénalise les cycles de dépendances entre packages. Des cycles inter-packages subsistent dans la base de code mono-module, indépendamment de la qualité de l'architecture hexagonale
  • Coupling à 36% : le couplage inter-packages est élevé car plusieurs bounded contexts partagent des types dans un mono-module. La migration vers une structure multi-module résoudrait cette dimension
  • Cohesion à 65% : la concentration fonctionnelle des packages est satisfaisante mais pourrait progresser en regroupant les types par bounded context
Inventaire

Inventaire architectural

L'inventaire recense les composants du modèle domaine classifiés par HexaGlue à l'issue de la migration complète.
Il montre la répartition finale entre agrégats, entités, value objects, ports et services applicatifs.
ComposantNombre
Aggregate Roots6
Entities2
Value Objects7
Identifiers6
Domain Events1
Application Services7
Driving Ports7
Driven Ports8
  • 6 Aggregate Roots : Customer, Inventory, Order, Payment, Product, Shipment. Chaque entité métier principale est un agrégat avec identifiant typé UUID et frontières définies
  • 7 Value Objects : Email, Address, Money, OrderStatus, Quantity, PaymentStatus, Category. Le domaine exprime ses concepts sans primitives exposées
  • 1 Domain Event : OrderPlacedEvent. Premier pas vers un modèle événementiel ; les abonnés potentiels (notification, stock) sont déjà câblés via les driven ports
  • 7 Driving Ports et 8 Driven Ports : l'hexagone est complet. Chaque driven port dispose d'un adaptateur généré par HexaGlue ; les driving ports exposent les use cases aux contrôleurs REST générés
Violations

Violations détectées

Une seule violation majeure subsiste après toutes les corrections effectuées lors des étapes précédentes.
Elle est liée à une limitation du classificateur sur OrderLine, et non à un défaut d'architecture.
Contrainte Nb Sév.
ddd:aggregate-boundary1 MAJ
  • ddd:aggregate-boundary (1 MAJOR) : OrderLine n'a pas d'identifiant explicite, donc le classificateur ne le reconnaît pas comme Entity membre de l'agrégat Order. Il est perçu comme accessible hors de la frontière de l'agrégat. Ajouter un OrderLineId résoudrait cette violation
  • Pas de violation Blocker ou Critical : toutes les violations d'isolation (layer-isolation), de couverture des ports (port-coverage) et de pureté applicative (application-purity) ont été résolues au fil des étapes précédentes
Qualité

Métriques de qualité

Les métriques de qualité mesurent l'adhérence du code aux principes DDD et hexagonaux.
La pureté du domaine atteint 100% et la complexité reste très basse, mais le boilerplate technique est élevé en raison du volume de code généré.
MétriqueValeurStatus
Domain purity100.00%
Domain coverage50.00%
Aggregate boundary0.00%
Code boilerplate80.20%
Code complexity1.12
Adapter independence100.00%
  • domain.purity à 100% : le domaine ne contient aucune dépendance technique. Les annotations JPA, Spring et MapStruct sont toutes dans la couche infrastructure générée
  • domain.coverage à 50% : la moitié des types du projet sont des types domaine classifiés. L'autre moitié correspond aux types infrastructure générés, ce qui est attendu
  • aggregate.boundary à 0% : entièrement lié à la limitation du classificateur sur OrderLine (absence d'identifiant explicite). Pas un défaut d'architecture
  • code.boilerplate à 80.20% (CRITICAL) : ce ratio élevé reflète le volume de code infrastructure généré par HexaGlue. Les entités JPA, mappers, repositories et DTOs sont techniques par nature ; le seuil de 50% est conçu pour le code domaine pur
  • adapter.independence à 100% : les adaptateurs générés ne dépendent pas les uns des autres et respectent le principe d'isolation des couches externes
Packages

Stabilité des packages

L'analyse de stabilité positionne chaque package sur le graphe Abstractness / Instability.
Elle révèle les packages en Zone of Pain (stables mais concrets) et ceux bien positionnés sur la Main Sequence.
PackageCaCeIADZone
com.acme.shop.application0281.000.000.00Main Sequence
com.acme.shop.domain.order4020.050.000.95Zone of Pain
com.acme.shop.domain.product2210.040.000.96Zone of Pain
com.acme.shop.infrastructure.persistence0281.000.340.34Main Sequence
com.acme.shop.ports.in15130.461.000.46Main Sequence
com.acme.shop.ports.out16170.521.000.52Main Sequence
Ca = Afferent Coupling (dépendants)
Ce = Efferent Coupling (dépendances)
I = Instability (0 = stable, 1 = instable)
A = Abstractness (0 = concret, 1 = abstrait)
D = Distance (0 = optimal, > 0.7 = problème)
Zone = Position sur le graphe A/I
  • domain.order et domain.product en Zone of Pain : ces packages sont très stables (40 et 22 dépendances afférentes, presque aucune dépendance efférente) mais totalement concrets (A=0.00). Position attendue pour des modèles domaine denses en mono-module ; la résoudre implique de découper par bounded context ou de migrer vers un multi-module
  • ports.in et ports.out sur la Main Sequence : les ports sont abstraits (A=1.00) et correctement positionnés. Ils constituent l'hexagone au sens strict, stables et abstraits
  • application et infrastructure.persistence : ces packages sont instables (I=1.00 et Ca=0). Aucun package ne dépend d'eux. C'est la position correcte pour les couches externes : elles dépendent du domaine et ne sont pas dépendées
Remédiation

Plan de remédiation

Une seule action de remédiation est identifiée à l'issue de la migration.
Elle concerne la violation aggregate-boundary sur OrderLine, estimée à 2 jours de travail manuel.
ContrainteViolationsManuelAvec
HexaGlue
ddd:aggregate:boundary
Route all access to internal entities through the aggregate root
12 j2 j
Total1
2 j
1 000 €
2 j
1 000 €
CRITICAL
MAJOR
Automatisé par HexaGlue
  • 2 jours de remédiation pour corriger la violation aggregate-boundary : ajouter un OrderLineId typé permet au classificateur de reconnaître OrderLine comme Entity membre de l'agrégat Order, et de router tous les accès via la racine d'agrégat
  • 0 jour HexaGlue : cette correction est purement domaine. HexaGlue ne peut pas corriger automatiquement une frontière d'agrégat manquante. Une fois la correction appliquée, les adaptateurs générés s'adapteront automatiquement
Bilan

Avant vs Après

Comparaison entre l'application legacy (étape 0) et l'architecture hexagonale finale.
Les chiffres montrent ce que la migration apporte concrètement : suppression de la dette technique, ajout des patterns DDD, et génération automatique de l'infrastructure.
CritèreLegacyHexagonal
Classes manuelles5044
Infrastructure générée0~55 (JPA + REST)
JPA dans le domaine9 classes0
Value Objects07
Identifiants typés06
Domain Events01
Driving Ports07
Driven Ports08
Score architecturalN/A63/100
Retours

Enseignements

Les leçons clés tirées de cette migration, issues directement des rapports HexaGlue et des observations à chaque étape.

Le domaine doit être pur

La suppression des 9 classes JPA du domaine est le point d'inflexion. Tant que le domaine contient du code technique, HexaGlue ne peut pas générer l'infrastructure correctement.

Mono-module : configuration adaptée

Sans dépendance inter-services, generateConfiguration: true génère le câblage automatiquement. Avec des dépendances inter-services (ici OrderUseCasesInventoryUseCases), generateConfiguration: false et la config manuelle est conservée.

Convention reconstitute()

La factory method reconstitute() est indispensable pour que les mappers générés puissent restaurer les agrégats depuis la persistance, sans compromettre l'encapsulation du domaine.

Migration incrémentale

Chaque étape compile. Les rapports d'audit guident l'étape suivante. Pas de Big Bang : le score progresse de 13 à 63/100 de manière incrémentale.

Le score est un indicateur fidèle

63/100 avec 1 violation signale une architecture hexagonale bien structurée. Dependencies (0%) et Coupling (36%) indiquent le prochain axe d'amélioration : la séparation des bounded contexts.

Infrastructure sans code manuel

~55 fichiers générés remplacent l'infrastructure manuelle. Le coût de l'architecture hexagonale est absorbé par la génération automatique : entités JPA, repositories, mappers, adapters, controllers et DTOs.

Une architecture hexagonale opérationnelle.
Un socle solide pour aller plus loin.

L'application e-commerce mono-module est passée de 13/100 à 63/100, avec Hexagonal Architecture à 100% et ~55 fichiers générés automatiquement.