Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 39

Architecture en couches avec Spring

Recommended resources

Bonjour ! Dans la leçon précédente, nous avons terminé notre exploration de la sécurité des API REST en analysant la pertinence de la protection CSRF, même dans un contexte stateless.

Aujourd'hui, nous ouvrons un nouveau chapitre crucial pour la qualité professionnelle de vos applications : l'Architecture Logicielle et les Design Patterns. Nous allons prendre de la hauteur par rapport au code pur pour nous concentrer sur la manière de l'organiser.

L'objectif de cette première leçon du module est de vous apprendre à structurer une application en couches (Présentation, Métier, Données) avec Spring. Cette organisation est la pierre angulaire de la plupart des applications d'entreprise modernes. Pour vous qui avez déjà une expérience en développement full-stack avec Laravel, ce concept ne sera pas étranger. Il s'agit d'une approche similaire au pattern MVC, mais spécifiquement adaptée à la construction d'un backend robuste et maintenable.

Maîtriser cette structure est fondamental pour créer des applications qui peuvent évoluer, être testées efficacement et comprises par d'autres développeurs, des compétences indispensables sur les marchés européens et américains que vous ciblez.

1. L'Architecture en Couches : Un Aperçu Théorique

Une application bien structurée sépare les différentes responsabilités dans des "couches" logiques distinctes. L'architecture la plus courante est l'architecture à 3 couches (ou N-Tiers).

Pour une introduction textuelle claire et concise à ce concept, je vous invite à lire la section suivante.

Une application multi-couches (N-Tiers)

L'article "Les applications Web avec Spring Web MVC" de David Gayerie explique parfaitement le principe de l'architecture N-Tiers et comment elle s'applique dans un projet Spring.

Lisez la section intitulée "Une application multi-couches (N-Tiers)". Concentrez-vous sur la définition des trois couches : Présentation, Métier (ou Service), et Accès aux données. Notez également comment Spring facilite cette structure grâce aux stéréotypes @Service et @Repository.

Pour résumer et visualiser les responsabilités de chaque couche :

  1. La couche Présentation (Presentation Layer)

    • Rôle : C'est la porte d'entrée de votre application. Elle reçoit les requêtes HTTP, les route vers le bon gestionnaire, valide les données entrantes (DTOs) et retourne une réponse HTTP (souvent en JSON).
    • Composants Spring : Essentiellement les classes annotées avec @RestController.
  2. La couche Métier (Business/Service Layer)

    • Rôle : C'est le cerveau de l'application. Elle contient toute la logique et les règles spécifiques à votre domaine (par exemple, "un utilisateur ne peut pas s'inscrire deux fois avec le même email", "le calcul du prix total d'une commande doit inclure la TVA"). Elle orchestre les opérations en faisant appel à la couche de données.
    • Composants Spring : Les classes annotées avec @Service.
  3. La couche Données (Data Layer)

    • Rôle : C'est la seule couche qui communique directement avec la base de données. Sa responsabilité est la persistance des données : créer, lire, mettre à jour, et supprimer des entités (CRUD).
    • Composants Spring : Les interfaces annotées avec @Repository, qui étendent généralement JpaRepository ou MongoRepository.

Le flux d'une requête est toujours le même : la couche Présentation reçoit la requête, appelle la couche Métier pour exécuter la logique, qui à son tour appelle la couche Données pour interagir avec la base de données.

Layered Architecture in a Spring Boot Application
Ce diagramme illustre parfaitement le flux des interactions : le client communique avec la couche Présentation (RestController), qui délègue à la couche Service (logique métier), laquelle s'appuie sur la couche Persistance (Repository) pour accéder à la base de données.

Pour une explication plus dynamique de ces concepts, la vidéo suivante est excellente.

Apprendre Spring Boot #2 HTTP POST & DTO : Controller → Service → JPA (RequestBody)

La vidéo "Apprendre Spring Boot #2" de la chaîne JirAWS détaille le rôle de chaque couche avec des exemples concrets et aborde les différentes terminologies que vous pourriez rencontrer.

Regardez le segment de 01:31 à 10:02. L'auteur y explique en détail les trois couches, leurs responsabilités, et des exemples de ce qui constitue la "logique métier".


2. Mise en Pratique : Du Contrôleur "Fourre-tout" à une Structure Propre

La théorie est une chose, mais la meilleure façon de comprendre est de pratiquer. Nous allons simuler une tâche très courante : refactoriser un contrôleur qui fait trop de choses (un "fat controller") pour adopter une architecture en couches propre.

Dans les leçons précédentes, pour simplifier, nous avons parfois mis de la logique directement dans les contrôleurs. C'est un anti-pattern dans une application réelle. Un contrôleur doit être "maigre" : son seul travail est de gérer le trafic HTTP et de déléguer le travail à la couche de service.

La suite de la vidéo de JirAWS que vous venez de commencer montre exactement comment effectuer cette refactorisation.

Étape 1 : Créer la Couche Service

La première étape consiste à créer une classe de service qui hébergera notre logique métier.

Apprendre Spring Boot #2 HTTP POST & DTO : Controller → Service → JPA (RequestBody)

Cette partie de la vidéo montre comment créer une classe de service et la marquer avec l'annotation @Service pour que Spring la reconnaisse.

Regardez de 13:35 à 18:18. Observez comment la logique de vérification (si un livre existe déjà) est déplacée du BookRestController vers une nouvelle méthode createBook dans la classe BookService.

Le code clé est la création de la classe de service :

import org.springframework.stereotype.Service;

@Service // Indique à Spring que cette classe est un composant de la couche métier.
public class BookService {

    // Injection du Repository (la couche Données)
    private final BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    // Méthode contenant la logique métier
    public String createBook(String bookName, int bookPages) {
        // Logique : vérifier si le livre existe avant de le créer
        if (bookRepository.findByNameAndPages(bookName, bookPages).isPresent()) {
            return "Le livre existe déjà.";
        }
        
        Book newBook = new Book();
        newBook.setName(bookName);
        newBook.setPages(bookPages);
        bookRepository.save(newBook);
        
        return "Le livre a bien été créé.";
    }
}

Étape 2 : Connecter la Présentation au Service

Maintenant que la logique est dans le service, le contrôleur doit l'utiliser. Pour cela, on injecte le service dans le contrôleur. L'injection via le constructeur, comme ci-dessous, est la meilleure pratique.

Regardez comment le "câblage" est effectué.

Apprendre Spring Boot #2 HTTP POST & DTO : Controller → Service → JPA (RequestBody)

Ce segment finalise la refactorisation en montrant comment injecter le BookService dans le BookRestController et comment l'appeler.

Regardez de 22:02 à 26:11. Portez une attention particulière à l'injection de BookService dans le constructeur du contrôleur et à la simplification de la méthode du contrôleur, qui se contente désormais d'appeler bookService.createBook().

Le contrôleur devient alors beaucoup plus simple et lisible :

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;

@RestController
public class BookRestController {

    // Injection du Service (la couche Métier)
    private final BookService bookService;

    public BookRestController(BookService bookService) {
        this.bookService = bookService;
    }

    @PostMapping("/books")
    public String createBookEndpoint(@RequestParam String name, @RequestParam int pages) {
        // Le contrôleur ne fait plus de logique, il délègue !
        return bookService.createBook(name, pages);
    }
}

La séparation est maintenant claire : le RestController gère le point d'accès /books, et le BookService gère la logique de création d'un livre.


3. Organisation des Packages

Pour que votre projet reste organisé à mesure qu'il grandit, il est conventionnel de placer chaque type de composant dans son propre package.

com.votreentreprise.votresuperprojet
├── controller   // ou 'web' ou 'api'
│   └── BookRestController.java
├── service
│   ├── BookService.java
│   └── impl
│       └── BookServiceImpl.java // (Si vous utilisez des interfaces pour les services)
├── repository   // ou 'dao'
│   └── BookRepository.java
├── model        // ou 'domain' ou 'entity'
│   └── Book.java
└── dto
    └── BookDto.java

Cette structure est une convention forte dans l'écosystème Java/Spring. Elle permet à n'importe quel développeur de comprendre rapidement où trouver les différents éléments de l'application.

L'article de Developpez.com que je vous propose en lecture complémentaire suit cette structure de manière très rigoureuse.

Springboot RestAPI - Developpez.com

Cet article, bien que long, est une excellente référence sur la mise en place d'une API REST complète avec Spring Boot. Il illustre parfaitement la création des différentes couches dans des packages dédiés.

Parcourez la section I-B-2. Création des couches. Vous n'avez pas besoin de lire tout le code en détail. L'objectif est de voir comment l'auteur crée les sous-packages model, dao (repository), et service, et y place les classes correspondantes. C'est un bon exemple de la structure de projet que nous venons de discuter.


4. Pourquoi cette structure est-elle si importante ?

Adopter cette architecture peut sembler ajouter de la complexité sur un petit projet. Cependant, ses bénéfices sur le long terme sont immenses et non négociables dans un contexte professionnel.

Apprendre Spring Boot #2 HTTP POST & DTO : Controller → Service → JPA (RequestBody)

Pour conclure, cette dernière section de la vidéo de JirAWS résume parfaitement les avantages de cette architecture, en la reliant notamment au principe de responsabilité unique (Single Responsibility Principle).

Regardez de 27:27 à 33:40. L'auteur y explique pourquoi cette organisation est vitale pour la maintenance et l'évolution d'un projet à grande échelle.

Les avantages clés sont :

  • Maintenabilité : Quand un bug survient dans la logique de création d'un livre, vous savez qu'il faut regarder dans BookService, pas dans le contrôleur.
  • Testabilité : Vous pouvez tester votre logique métier (BookService) de manière isolée, sans avoir besoin de lancer un serveur web. C'est beaucoup plus rapide et fiable.
  • Réutilisabilité : Si demain vous avez besoin d'un autre moyen de créer un livre (par exemple, via une tâche planifiée ou un autre type d'API), vous pouvez réutiliser le même BookService.
  • Clarté : Le code est plus facile à lire et à comprendre, car chaque classe a une seule et unique responsabilité.

Conclusion

Félicitations ! Vous avez maintenant les bases pour structurer n'importe quelle application Spring Boot de manière professionnelle.

Les points clés à retenir :

  • Une application Spring est typiquement structurée en 3 couches : Présentation (@RestController), Métier (@Service), et Données (@Repository).
  • Le flux est unidirectionnel : Controller -> Service -> Repository.
  • Les couches communiquent entre elles via l'injection de dépendances, de préférence par constructeur.
  • Cette architecture sépare les responsabilités, ce qui rend l'application plus maintenable, testable, et évolutive.

Dans la prochaine leçon, nous approfondirons ces concepts en nous penchant sur deux principes fondamentaux du design logiciel : le Principe de Responsabilité Unique (SRP), que nous venons d'effleurer, et le Principe d'Inversion de Dépendances (DIP). Vous verrez comment ils s'appliquent concrètement dans un projet Spring Boot pour écrire un code encore plus propre et flexible.