Aller au contenu

Architectures Spring Boot : tour d'horizon

Controller, Service, Repository : l'architecture en couches règne encore sur la majorité des projets Spring Boot. Mais est-elle toujours adaptée ? De l'hexagonale au modular monolith, tour d'horizon de cinq approches architecturales, de leurs forces, de leurs limites et de leurs cas d'usage.

Architectures Spring Boot : tour d'horizon

Quand on démarre un projet Spring Boot, l'architecture en couches (controller / service / repository) s'impose presque par défaut : c'est celle des tutoriels, celle de Spring Initializr implicitement, celle qu'on a toujours connue.
Elle fonctionne, et c'est bien le problème : elle fonctionne assez bien pour qu'on ne se pose jamais la question de ses limites, jusqu'à ce qu'un projet grossisse, qu'une équipe change, ou qu'un test unitaire du domaine métier traîne une demi-douzaine de mocks d'infrastructure.

Il existe d'autres façons d'organiser un code Spring Boot, chacune avec ses propres arbitrages.
Cet article fait un tour d'horizon de cinq architectures :

  • Layered
  • Hexagonale
  • Clean
  • Onion
  • Modular monolith

Sans chercher à désigner une "meilleure" approche.
Le bon choix dépend du contexte : taille d'équipe, complexité métier, durée de vie attendue du projet.

Layered architecture (Controller / Service / Repository)

Layered architecture

Principe

Chaque couche communique avec la couche immédiatement inférieure : le Controller appelle le Service, le Service appelle le Repository, le Repository parle à la base de données. C'est l'architecture par défaut de Spring Boot, elle correspond directement aux stéréotypes @RestController, @Service, @Repository.

Le sens de dépendance global reste descendant, jamais l'inverse. Mais à l'intérieur de la couche Service, les appels horizontaux entre services sont courants : un OrderService peut appeler un InventoryService ou un NotificationService pour orchestrer une opération métier. La règle stricte n'est donc pas "chaque couche ne dépend que de la couche immédiatement inférieure", mais plutôt : aucune couche ne dépend d'une couche supérieure, avec des dépendances horizontales possibles au sein d'une même couche.

Avantages

  • Très faible courbe d'apprentissage, tout développeur Spring la reconnaît immédiatement
  • Convention native du framework, aucun outillage supplémentaire requis
  • Adaptée aux CRUD simples et aux petites équipes

Inconvénients

  • Le Service devient souvent un fourre-tout, sans frontière claire entre logique métier et orchestration technique
  • Le domaine métier dépend directement de l'infrastructure (JPA, frameworks) au lieu de l'inverse, ce qui rend les tests unitaires du métier dépendants de mocks d'infrastructure
  • Tendance à l'anémie du domaine : les entités ne portent que des données, toute la logique se retrouve dans les services

Architecture hexagonale (Ports & Adapters)

Architecture hexagonale (Ports & Adapters)

Principe

Le domaine métier est isolé au centre, sans aucune dépendance vers la technique. Il expose des ports : des interfaces définies par le domaine lui-même, pas par l'infrastructure. Un port d'entrée décrit ce que le domaine permet de faire (un cas d'usage), un port de sortie décrit ce dont le domaine a besoin (persister une donnée, envoyer un événement). Les adapters implémentent ces ports : un contrôleur REST est un adapter entrant, une implémentation JPA d'un port de sortie est un adapter sortant. La dépendance va toujours des adapters vers le domaine, jamais l'inverse, c'est l'inversion de dépendance.

Avantages

  • Le domaine est testable unitairement sans aucune dépendance technique (pas de mock Spring, pas de base de données)
  • Changer de technologie d'infrastructure (passer de JPA à MongoDB, ou de REST à GraphQL) n'impacte que l'adapter concerné
  • Force une frontière explicite entre métier et technique, contrairement au layered où cette frontière est une convention informelle

Inconvénients

  • Verbosité accrue : chaque cas d'usage nécessite une interface (port) en plus de son implémentation
  • Sur-ingénierie pour des projets à faible complexité métier ou de courte durée de vie
  • Demande une discipline d'équipe pour ne pas laisser des types techniques (entités JPA, DTO Spring) fuiter dans le domaine

Clean Architecture

Clean Architecture

Principe

Proposée par Robert C. Martin, la Clean Architecture organise le code en cercles concentriques régis par une seule règle, la "Dependency Rule" : le code source ne peut dépendre que de l'intérieur, jamais vers l'extérieur. Les Entities et Use Cases au centre ne savent rien des Interface Adapters ni des Frameworks & Drivers en périphérie.
Contrairement à l'hexagonale qui parle de ports et d'adapters de façon plus générique, la Clean Architecture impose un découpage plus prescriptif : les Use Cases sont des classes explicites représentant chaque action métier, distinctes des Entities qui portent les règles invariantes du domaine.

Avantages

  • La règle de dépendance est plus explicite et didactique que l'hexagonale, elle laisse moins de place à l'interprétation
  • Chaque cas d'usage devient une classe identifiable et testable isolément
  • Facilite l'onboarding sur un projet déjà structuré ainsi, le découpage est documenté par construction

Inconvénients

  • Plus de classes et de couches qu'une architecture hexagonale équivalente, donc plus de boilerplate
  • La frontière entre Use Case et Entity peut devenir floue sur des règles métiers transverses, source de débats d'équipe
  • Comme pour l'hexagonale, le bénéfice n'est perceptible que si la complexité métier le justifie

Onion Architecture

Onion Architecture

Principe

Proposée par Jeffrey Palermo, l'Onion Architecture repose sur la même règle de dépendance que la Clean Architecture et l'hexagonale : tout pointe vers le centre, jamais l'inverse. Dans sa formulation originale, celle-ci distingue quatre couches (Domain Model, Domain Services, Application Services, Infrastructure/UI), mais la frontière entre les deux premières est rarement marquée en pratique, on les regroupe en un "Domaine" unique.

Onion, Hexagonale, Clean : où sont les vraies différences ?

Les trois partagent le même principe fondamental d'inversion de dépendance et isolent un cœur métier des préoccupations techniques. Les différences tiennent surtout au vocabulaire et à l'emphase :

  • L'hexagonale met l'accent sur les ports et adapters comme mécanisme explicite d'inversion (interfaces définies côté domaine)
  • La Clean Architecture met l'accent sur la distinction Use Case / Entity comme unités de découpage
  • L'Onion met l'accent sur la structure en couches concentriques elle-même, sans imposer de vocabulaire de ports

En pratique, un projet "hexagonal" et un projet "onion" bien faits sont souvent indiscernables dans leur organisation de code. Le choix du nom relève davantage de la culture d'équipe ou de la littérature qui a influencé l'architecte que d'un choix technique radicalement différent.

Avantages

  • Vocabulaire pédagogique simple (le cœur isolé, "comme un oignon"), facile à expliquer à une équipe
  • Mêmes bénéfices de testabilité et d'indépendance technique que l'hexagonale et la Clean Architecture

Inconvénients

  • Moins de littérature et d'outillage dédié que l'hexagonale ou la Clean Architecture, qui ont chacune des conventions Spring plus documentées
  • Le flou entre Domain Model et Domain Services dans la pratique réintroduit une partie de l'ambiguïté que ces architectures cherchent à éliminer

Modular Monolith

Modular Monolith

Principe

Le Modular Monolith reste un déployable unique (un seul JAR Spring Boot, un seul process), mais le code est organisé en modules métier explicites avec des frontières fortes. Chaque module expose une API publique restreinte (classes, interfaces) et garde le reste de son implémentation privée. Les modules n'accèdent jamais directement à leurs détails internes, uniquement via leur API publique, ce qui se traduit en Java par des packages bien délimités (package-private par défaut, exposition explicite) et se vérifie avec des tests d'architecture comme ArchUnit.

Contrairement aux quatre architectures précédentes qui structurent le code par type technique (controller, service, repository, ou domaine/adapter), le Modular Monolith structure par domaine métier. Les deux approches ne s'excluent pas : chaque module peut très bien être organisé en interne selon un style hexagonal ou layered.

Avantages

  • Prépare une éventuelle extraction en microservices sans payer immédiatement le coût de la distribution (réseau, cohérence, observabilité distribuée)
  • Les frontières entre domaines métier sont vérifiables automatiquement (ArchUnit, tests de dépendances), contrairement à une convention informelle
  • Un seul déployable : pas de complexité opérationnelle supplémentaire (orchestration, déploiement, monitoring multi-services)

Inconvénients

  • Demande une vraie discipline d'équipe pour ne pas céder à la tentation d'un accès direct entre modules quand un raccourci semble plus rapide
  • Le découpage en modules métier n'est pas toujours évident à définir dès le départ, un mauvais découpage initial coûte cher à corriger
  • Reste un déploiement monolithique : un module en panne ou en boucle infinie peut affecter l'ensemble de l'application

Tableau récapitulatif

Architecture Axe de découpage Courbe d'apprentissage Testabilité du domaine Contexte adapté
Layered Technique (couches) Faible Faible (dépend de l'infra) Petite équipe, projet simple, CRUD
Hexagonale Technique (ports/adapters) Moyenne Élevée Domaine métier complexe, besoin d'indépendance technique
Clean Architecture Technique (use cases/entities) Moyenne à élevée Élevée Équipe habituée à un découpage prescriptif
Onion Technique (couches concentriques) Moyenne Élevée Équivalent fonctionnel de l'hexagonale, choix culturel
Modular Monolith Métier (modules) Moyenne Dépend de l'organisation interne de chaque module Plusieurs domaines métier, trajectoire vers une décomposition future

Conclusion

Ces cinq architectures partagent un même objectif : limiter le couplage entre logique métier et détails techniques. Elles diffèrent surtout par le degré de rigueur qu'elles imposent et par l'axe de découpage retenu (technique pour layered/hexagonale/clean/onion, métier pour le modular monolith).

Aucune n'est universellement supérieure. Le layered reste pertinent pour un projet simple, une équipe réduite, ou une durée de vie courte, là où l'investissement dans une frontière de domaine ne se rentabilise pas. L'hexagonale, la Clean Architecture et l'Onion deviennent intéressantes dès que la logique métier gagne en complexité et justifie d'être testée indépendamment de l'infrastructure, le choix entre ces trois tient alors davantage à la culture d'équipe et au vocabulaire préféré qu'à une différence technique fondamentale.

Le Modular Monolith répond à une question différente : comment organiser un système qui couvre plusieurs domaines métier distincts, en gardant une trajectoire ouverte vers une décomposition future sans s'imposer le coût d'une architecture distribuée dès le premier jour.

Le critère décisif reste contextuel : taille et maturité de l'équipe, complexité réelle du domaine métier, horizon de vie attendu du projet, et tolérance de l'organisation à l'investissement initial que ces structures demandent.

Késaco : Spring Boot
Dans le monde Java, quand on veut développer une application, il est indispensable d’avoir un bon framework. Parmi eux, Spring Boot se place comme un incontournable. Mais qu’est-ce que c’est ?
Pourquoi utiliser Spring Boot ?
Pourquoi utiliser Spring Boot pour votre application Java ? La réponse dans cet article.

Dernier