Architecture Hexagonale
Ports, Adapters et inversion de dépendances.
L'architecture hexagonale (Ports & Adapters) isole votre domaine métier de l'infrastructure technique. Ce guide couvre les principes fondamentaux, la distinction Driving/Driven, l'inversion de dépendances et la comparaison avec l'architecture en couches, avec des exemples Java concrets.
Pourquoi l'architecture hexagonale ?
L'architecture hexagonale, proposée par Alistair Cockburn en 2005 sous le nom de "Ports and Adapters", résout ce problème en inversant les dépendances : le domaine définit ses besoins via des interfaces (ports), et l'infrastructure fournit des implémentations (adapters). Le domaine ne sait pas qui l'appelle ni où il persiste.
En 2026, avec l'essor du cloud, des architectures modulaires et du déploiement continu, ce pattern est devenu un standard pour les applications Java d'entreprise. Il permet de tester le domaine sans infrastructure, de remplacer une technologie sans toucher au métier, et de raisonner clairement sur les responsabilités de chaque couche.
Hexagonal n'est pas microservices
L'architecture hexagonale est un pattern d'organisation du code au sein d'une application. Elle ne préjuge pas du style de déploiement : monolithe, modulaire, microservices. Un monolithe bien structuré en hexagonal est souvent préférable à des microservices mal découpés.
Le domaine au centre
Le domaine
Le domaine contient la logique métier pure : agrégats, entités, value objects, domain events, domain services. Il n'a aucune dépendance vers l'extérieur : pas de framework, pas de base de données, pas de HTTP. C'est le modèle DDD au centre de l'architecture.
Les ports
Les ports sont les interfaces que le domaine expose (ports entrants) ou dont il dépend (ports sortants). Un port entrant définit un cas d'usage : PlaceOrderUseCase. Un port sortant définit un besoin : OrderRepository. Le domaine ne connaît que ces interfaces.
Les adapters
Les adapters sont les implémentations concrètes des ports. Un adapter REST appelle un port entrant. Un adapter JPA implémente un port sortant. Ils traduisent entre le monde technique et le domaine. On peut les remplacer sans toucher au domaine.
Le domaine ne sait pas QUI l'appelle (un contrôleur REST ? un test ? une CLI ?) ni OÙ il persiste (PostgreSQL ? MongoDB ? un fichier ?). Cette ignorance est précisément ce qui le rend testable, portable et maintenable.

Driving vs Driven : deux directions, un même principe
| Direction | Côté | Ports | Adapters | Exemples |
|---|---|---|---|---|
| Driving (entrant) | Gauche | Cas d'usage | Contrôleurs | PlaceOrderUseCase → REST Controller |
| Driven (sortant) | Droite | Dépendances | Implémentations | OrderRepository → JPA Adapter |
Driving Port : le cas d'usage
Un Driving Port définit un cas d'usage exposé par le domaine. C'est l'interface que les adapters entrants (REST, CLI, event listener) appellent pour déclencher une action métier.
/** Port entrant : cas d'usage "passer une commande". */public interface PlaceOrderUseCase {
OrderConfirmation placeOrder(PlaceOrderCommand command);}
/** Commande portant les données nécessaires. */public record PlaceOrderCommand( CustomerId customerId, List<OrderLineRequest> lines) {}Driven Port : la dépendance du domaine
Un Driven Port déclare une dépendance du domaine vers l'extérieur. Le domaine définit l'interface, l'infrastructure fournit l'implémentation.
/** Port sortant : persistance des commandes. */public interface OrderRepository {
void save(Order order);
Optional<Order> findById(OrderId id);
List<Order> findByCustomer(CustomerId customerId);}
/** Port sortant : notification de paiement. */public interface PaymentGateway {
PaymentResult authorize(OrderId orderId, Money amount);}
Le domaine définit, l'infrastructure implémente
/** Service applicatif : orchestre le cas d'usage. */public class PlaceOrderService implements PlaceOrderUseCase {
// Le domaine DÉFINIT les interfaces (ports) private final OrderRepository orderRepository; private final PaymentGateway paymentGateway; private final PricingService pricingService;
// L'infrastructure IMPLÉMENTE via injection de dépendances public PlaceOrderService( OrderRepository orderRepository, PaymentGateway paymentGateway, PricingService pricingService) { this.orderRepository = orderRepository; this.paymentGateway = paymentGateway; this.pricingService = pricingService; }
@Override public OrderConfirmation placeOrder(PlaceOrderCommand command) { var order = Order.create(command.customerId()); command.lines().forEach(line -> order.addLine(line.product(), line.quantity()) );
Money total = pricingService.calculate(order); PaymentResult payment = paymentGateway.authorize(order.id(), total);
if (payment.isAuthorized()) { OrderPlaced event = order.confirm(); orderRepository.save(order); return OrderConfirmation.success(order.id(), event); } return OrderConfirmation.paymentDeclined(order.id()); }}/** Driven Adapter : implémentation JPA du port OrderRepository. */@Repositorypublic class JpaOrderRepository implements OrderRepository {
private final SpringDataOrderRepository springRepo; private final OrderMapper mapper;
@Override public void save(Order order) { var entity = mapper.toJpaEntity(order); springRepo.save(entity); }
@Override public Optional<Order> findById(OrderId id) { return springRepo.findById(id.value()) .map(mapper::toDomainObject); }}Tester sans infrastructure
Grâce à l'inversion de dépendances, le PlaceOrderService peut être testé avec des mocks des ports sortants : un OrderRepository en mémoire et un PaymentGateway stub. Aucune base de données, aucun service externe, aucune configuration Spring : le test vérifie la logique métier pure en quelques millisecondes.
Hexagonal vs Couches : quand choisir ?
| Critère | Architecture en couches | Architecture hexagonale |
|---|---|---|
| Couplage | Fort : le métier dépend de la persistance | Faible : le domaine ne dépend de rien |
| Testabilité | Tests souvent liés à l'infra (DB, Spring Context) | Domaine testable sans infrastructure |
| Remplacement d'infra | Difficile : changements en cascade | Simple : changer un adapter suffit |
| Complexité initiale | Faible : structure familière | Modérée : plus d'interfaces et de packages |
| Cas d'usage idéal | CRUD simple, prototypage rapide | Logique métier riche, évolution long terme |
L'architecture hexagonale n'est pas toujours nécessaire. Pour une application CRUD avec peu de logique métier, l'architecture en couches est plus simple et suffit. L'hexagonal prend tout son sens lorsque le domaine est complexe, que les règles métier évoluent et que vous avez besoin de tester le métier indépendamment de l'infrastructure.
Tester sans infrastructure
Tests du domaine
Le domaine se teste en logique pure. Les ports sortants sont mockés ou stubés. Pas de base de données, pas de framework : les tests vérifient les invariants métier, les transitions d'état et les événements émis. Ils s'exécutent en millisecondes.
Tests d'intégration
Chaque adapter se teste séparément. Un test d'intégration pour JpaOrderRepository utilise une base de données réelle (H2 ou Testcontainers). Un test pour le contrôleur REST utilise MockMvc. Un adapter à la fois, avec son infrastructure réelle.
Tests end-to-end
Les tests end-to-end traversent le pipeline complet : un appel via le driving adapter (REST), à travers le domaine, jusqu'aux driven adapters (JPA, messaging). Ils sont peu nombreux, ciblent les scénarios critiques et valident l'assemblage des composants.
De la théorie à l'automatisation
| Ce que fait HexaGlue | Fonctionnalité | En savoir plus |
|---|---|---|
| Détecte les Driving et Driven Ports | Classification automatique | Classification |
| Génère les Driven Adapters JPA | Génération de code | Génération JPA |
| Vérifie les dépendances entre couches | Audit d'architecture | Audit |
| Documente la topologie | Living Documentation | Living Doc |
Détection, génération, audit
HexaGlue détecte automatiquement les ports (Driving et Driven), génère les adapters JPA à partir du modèle de domaine, et audite la conformité de l'architecture hexagonale à chaque build. Les violations sont signalées dans le rapport d'audit avec leur sévérité et des pistes de remédiation.

L'architecture hexagonale protège le modèle DDD des détails d'infrastructure. HexaGlue automatise la partie technique : vous écrivez le domaine, il génère l'infrastructure et vérifie que les frontières architecturales sont respectées. Vous pouvez voir ces principes appliqués à un projet réel dans l'étude de cas e-commerce.
Votre domaine est au centre.
HexaGlue protège ses frontières.
Voyez l'architecture hexagonale appliquée sur un projet réel ou commencez avec le tutoriel.