Étude de cas

Application E-Commerce Mono-Module

Code source
  • Mono-module Maven, Java 17, Spring Boot 3.2.5.
  • 50 classes réparties dans 9 packages techniques.
  • 10 anti-patterns typiques d'un découpage par couche technique.
Legacy

L'application legacy

Cette application e-commerce illustre un anti-pattern courant : le découpage horizontal par couche technique.
Chaque package correspond à un rôle technique (controller, service, model, repository) plutôt qu'à un domaine métier. Le résultat est une application qui semble organisée mais où le domaine reste invisible, noyé sous JPA et Spring.
#Anti-pattern
1Couplage domaine/persistance
2Services sans distinction de rôle
3Aucune inversion de dépendance
4Modèle anémique
5Absence de typage métier
6Références directes entre agrégats
7Héritage technique imposé
8Dépendance au framework pour les événements
9Fuite de responsabilité
10Aucune séparation des couches
Structure

Organisation des packages

L'application suit un découpage purement technique : controller, service, model, repository, dto, config, exception, event et util.
Il n'existe aucun package domain, aucun port, aucun agrégat : la frontière entre métier et infrastructure est inexistante.
com.acme.shop/
├── ShopApplication.java
├── controller/ (5 classes)
├── service/ (8 classes)
├── model/ (11 classes)
├── repository/ (6 interfaces)
├── dto/ (7 records)
├── config/ (2 classes)
├── exception/ (4 classes)
├── event/ (1 classe)
└── util/ (2 classes)

Code métier et code technique imbriqués dans les mêmes classes.

  • Les 11 classes model/ sont à la fois des entités JPA et des objets du domaine : le domaine dépend directement de l'infrastructure
  • Les 8 classes service/ mélangent orchestration, logique métier et accès aux repositories Spring Data
  • Changer de framework ou migrer l'infrastructure implique de réécrire le domaine entier
Code legacy

Exemple : Order.java

La classe Order telle qu'elle existe dans le projet : annotations JPA, héritage de BaseEntity, primitives pour les montants et adresses, référence directe à Customer au lieu d'un identifiant typé.
C'est exactement ce que HexaGlue va analyser et signaler dans le rapport d'audit initial.
Order.java
@Entity
@Table(name = "orders")
public class Order extends BaseEntity {
@Column(nullable = false, unique = true)
private String orderNumber;
// Anti-pattern : référence directe à l'entité au lieu d'un identifiant typé
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderLine> lines = new ArrayList<>();
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private OrderStatus status = OrderStatus.DRAFT;
@Column(precision = 10, scale = 2)
private BigDecimal totalAmount;
private String currency;
private String shippingStreet;
private String shippingCity;
private String shippingZipCode;
private String shippingCountry;
// getters, setters...
}
  • Domaine invisible sous les annotations JPA (@Entity, @Table, @ManyToOne)
  • Couplage fort : Order référence l'entité Customer au lieu d'un identifiant typé CustomerId
  • Absence de typage métier : BigDecimal pour le montant, String pour la devise et l'adresse éclatée en primitives
  • Héritage technique imposé par BaseEntity (@MappedSuperclass) avec Long id auto-généré
  • Aucun comportement métier : uniquement des getters/setters, la logique vit dans les services
Premier diagnostic

Brancher HexaGlue sur le projet

Pour obtenir un diagnostic architectural, on ajoute le plugin HexaGlue au pom.xml et on déclare le package racine à analyser.
En mode mono-module, HexaGlue s'intègre au cycle de vie Maven et produit un rapport d'audit complet en une seule commande mvn verify.
pom.xml
<plugin>
<groupId>io.hexaglue</groupId>
<artifactId>hexaglue-maven-plugin</artifactId>
<version>6.1.1</version>
<extensions>true</extensions>
<configuration>
<basePackage>com.acme.shop</basePackage>
<failOnError>false</failOnError>
</configuration>
<dependencies>
<dependency>
<groupId>io.hexaglue.plugins</groupId>
<artifactId>hexaglue-plugin-audit</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
</plugin>
  • extensions=true : HexaGlue s'intègre au cycle de vie Maven et déclenche automatiquement la classification à la phase compile et l'audit à la phase verify
  • basePackage : toutes les classes sous com.acme.shop seront analysées et classifiées par HexaGlue
  • failOnError=false : le build ne sera pas bloqué par les violations, utile pour un premier diagnostic non intrusif

Rapport d'audit

Résultat de la première exécution de l'audit HexaGlue sur les 50 classes du projet e-commerce.

Verdict

Verdict de l'audit initial

Le score global, la note et les violations sont affichés en tête du rapport. Ce premier verdict donne une photographie chiffrée de l'état architectural avant toute modification.
13
/100
Grade F
FAILED
43
violations
19
critical
24
major

Le grade F confirme que l'architecture ne respecte aucun principe DDD ni hexagonal. L'application n'a ni ports, ni identifiants typés, ni séparation domaine/infrastructure. Les sections suivantes détaillent la décomposition du score et les violations par catégorie.

Score

Décomposition du score

Le score de 13/100 est calculé à partir de 5 dimensions pondérées. Ce tableau montre la contribution de chaque dimension et son écart par rapport au seuil attendu.
DimensionScoreStatus
DDD Compliance0%
Hexagonal Architecture0%
Dependencies0%
Coupling30%
Cohesion58%
TOTAL13.20
  • DDD Compliance et Hexagonal Architecture à 0% : ces deux dimensions représentent 50% du score total. Aucun agrégat, aucun port et aucun identifiant typé n'existe dans le code
  • Dependencies à 0% : les dépendances vont du domaine vers l'infrastructure, l'inverse de ce qu'attend l'architecture hexagonale
  • Coupling et Cohesion contribuent légèrement : l'organisation en packages techniques apporte un minimum de découplage structurel
Violations

Violations détectées

Chaque violation correspond à une règle architecturale enfreinte par le code. Elles sont classées par sévérité : Critical pour les problèmes structurels fondamentaux, Major pour les écarts significatifs qui bloquent la progression vers une architecture hexagonale.
Contrainte Nb Sév.
ddd:domain-purity10 CRIT
ddd:entity-identity9 CRIT
hexagonal:port-direction6 MAJ
hexagonal:port-coverage6 MAJ
hexagonal:layer-isolation12 MAJ

Les 19 violations Critical ont toutes la même cause racine : les annotations JPA dans le modèle de domaine.

  • ddd:domain-purity : le domaine importe jakarta.persistence, il dépend structurellement de la couche de persistance
  • ddd:entity-identity : les 9 entités JPA utilisent un Long id auto-généré, pas un identifiant métier typé

Les 24 violations Major signalent l'absence de structure hexagonale. La prochaine étape commence par configurer les exclusions pour éliminer le bruit d'analyse, puis restructure le code en couches hexagonales.