Spring Boot : le standard des développeurs coréens et l’inversion de contrôle

La Corée du Sud est-elle une « république Spring » ?

Si vous voulez être recruté comme développeur backend en Corée, il y a une question à laquelle vous échapperez difficilement : « Vous savez utiliser Spring ? »

Sur les sites d’emploi, neuf offres sur dix mentionnent explicitement « expérience avec Spring Boot » dans les prérequis. Au point qu’on parle même de « république Spring ». À l’université, je pensais que ce n’était qu’une mode.

« Pourquoi ne pas simplement coder en Java ? Pourquoi s’embêter avec un Spring aussi lourd ? » « Node.js ou Python (Django), ce n’est pas plus simple ? »

Mais une fois confronté à la réalité des grands projets, j’ai compris. Spring n’était pas une simple tendance, mais un établi standard façonné au fil du temps par d’innombrables développeurs expérimentés afin de construire des systèmes d’entreprise immenses et complexes de manière sûre et rapide.

Cette série raconte justement comment construire, sur cet établi standard, un château qui ne s’effondre pas : un Monolith.

Framework : pourquoi on ne peut pas tout faire à sa manière

Avant d’entrer dans le vif du sujet technique, il faut clarifier un point. Qu’est-ce qu’un framework, exactement ? Et en quoi diffère-t-il d’une bibliothèque ?

Je l’avais brièvement évoqué dans la série Re: Booting, mais la différence décisive entre les deux tient en une question : qui garde l’initiative ?

  • Bibliothèque (Library) : c’est un « outil ». Quand j’en ai besoin, je sors le marteau, je prends la scie. Je peux construire la maison comme je l’entends. (ex. : React, jQuery)
  • Framework : c’est un « cadre » (Frame). Une maison témoin dont les piliers et les murs sont déjà en place. Je ne fais que choisir la couleur du papier peint ou disposer les meubles selon des règles établies ; je ne peux pas arracher les piliers à ma guise.

Spring est un framework. Utiliser Spring, c’est donc presque signer une promesse : « Je vais mettre un peu de côté ma façon personnelle de coder et suivre les règles imposées par Spring. » Le cœur de ce « faire comme Spring le demande », c’est justement le sujet du jour : l’inversion de contrôle (IoC).

« S’il vous plaît, arrêtez d’utiliser new partout »

La première règle de cette promesse m’avait choqué. Elle disait en substance : n’utilisez plus new, pourtant l’un des fondamentaux les plus basiques de Java.

À l’université, si j’avais besoin d’un objet, j’écrivais naturellement MemberService service = new MemberService();. Si j’ai besoin de quelque chose, je le crée moi-même et je l’utilise. Quoi de plus logique ?

Mais après mon entrée dans le monde professionnel, quand j’ai ouvert un projet Spring Boot, impossible de trouver le mot-clé new dans le code. À la place, il y avait partout des annotations comme @Autowired ou @RequiredArgsConstructor.

« Attendez, si personne ne crée l’objet, comment la méthode est-elle appelée ? Ce truc fonctionne vraiment ? »

Quand j’ai posé la question à un développeur senior, sa réponse m’a semblé terriblement floue : « Le Spring Container l’injecte automatiquement, donc on n’a pas besoin de le créer nous-mêmes. Au contraire, si tu utilises directement new, le code sera bien plus difficile à maintenir plus tard. »

Je n’arrivais pas à l’accepter. J’étais le propriétaire du code que j’écrivais, alors pourquoi ne pouvais-je même pas créer librement un objet ? J’avais l’impression de subir une dictature de Spring.

Est-ce que je le fabrique moi-même, ou est-ce que j’utilise ce que quelqu’un d’autre a préparé ?

Le chef et le responsable des ingrédients (IoC & DI)

Pour comprendre pourquoi cette règle qui ressemble à une forme d’autorité est nécessaire, changeons de métaphore et passons dans la cuisine d’un restaurant.

1. La méthode traditionnelle (c’est moi qui décide)

Je suis un chef, donc une Class. Pour cuisiner, j’ai besoin d’un couteau, donc d’une Dependency.

  • Action : je vais moi-même au supermarché acheter un couteau. Knife knife = new Knife();
  • Problème : et si j’ai acheté un « couteau japonais », mais que le menu passe soudain à la cuisine chinoise et qu’il me faut un « couperet chinois » ? Je dois alors modifier ma propre main (le code) qui tient le couteau. Chaque fois que l’outil change, le chef en subit les conséquences. (couplage fort)

2. La méthode Spring (c’est Spring qui décide)

Je suis toujours le chef. Mais cette fois, il y a un gestionnaire des ingrédients et des outils : le Spring Container.

  • Action : je me contente de lancer « Un couteau, s’il vous plaît ». Peu m’importe la marque du couteau.
  • DI (Dependency Injection) : le gestionnaire me met le couteau dans la main (Inject). Aujourd’hui, il peut me donner un couteau japonais, et demain un couperet chinois.
  • Avantage : même si le couteau change, je n’ai pas besoin de modifier mon code. Je n’ai qu’à cuisiner avec le couteau qu’on me met dans la main. (couplage faible)

Autrement dit, au lieu de gérer moi-même les ressources dont j’ai besoin, une entité extérieure les gère et me les fournit. C’est exactement cela, l’inversion de contrôle (IoC: Inversion of Control), et la technique concrète qui permet de le faire s’appelle l’injection de dépendances (DI).

Recevoir une injection, c’est laisser à quelqu’un d’autre le souci de choisir et de préparer les outils.

[Code Verification] Pourquoi new est-il dangereux ?

En rester aux mots ne suffit pas pour bien le sentir. Comparons-le directement dans du code. Imaginons que nous construisions un système de paiement par carte.

1. Mauvais exemple : instanciation directe (couplage fort)

public class PaymentService {
    // Jai choisi et cree moi-meme une Samsung Card (avec new)
    private final SamsungCard card = new SamsungCard();

    public void pay() {
        card.payment(); // Paiement possible uniquement avec Samsung Card
    }
}

Le problème : un jour, le patron dit : « Passons à Hyundai Card, les frais sont moins élevés ! » À ce moment-là, il faut ouvrir le code de PaymentService et remplacer partout SamsungCard par HyundaiCard. Et si ce code existe à cent endroits différents ? Les heures sup sont garanties.

2. Bon exemple : injection de dépendances (couplage faible)

public class PaymentService {
    private final Card card; // Ne pas specifier de fournisseur concret (utiliser linterface)

    // Injection par constructeur : faire confiance au fait que quelquun fournira la carte de lexterieur
    public PaymentService(Card card) {
        this.card = card;
    }

    public void pay() {
        card.payment();
    }
}

Désormais, PaymentService se moque de l’implémentation concrète de carte qu’on lui fournit.

  • Il suffit de modifier une seule ligne dans la configuration Spring (Configuration), du genre « injecte-moi une Hyundai Card », pour changer de moyen de paiement, et cela sans toucher au code de PaymentService, pas même d’une seule ligne.

C’est précisément le cœur de ce qu’on appelle en pratique un « code facile à maintenir », ou le principe OCP. Et c’est exactement pour cette souplesse qu’on utilise Spring Boot.

Spring Container : un hôtel pour les objets

Alors qui est ce « gestionnaire » qui crée les objets et les distribue ? C’est précisément le Spring Container.

Au moment où l’on démarre un serveur Spring Boot avec run, énormément de choses se passent en interne.

  1. Scan (Component Scan) : Spring passe tout au peigne fin pour trouver les classes annotées avec @Component, @Service ou @Repository.
  2. Enregistrement (Bean Registration) : pour chaque classe trouvée, il crée un seul et unique objet (Singleton) et le range dans son propre entrepôt (Container). Ces objets sont appelés des « Beans ».
  3. Injection (Auto Wiring) : il détermine de quels objets chacun a besoin et les associe les uns aux autres.

Notre rôle consiste seulement à coller une étiquette sur la classe qui dit en substance : « merci de gérer ceci », avec par exemple @Service. Pour le reste, Spring s’en charge, comme l’immense directeur d’un hôtel qui organise tous ses clients.

Conseil pratique : utilisez l’injection par constructeur

Spring propose plusieurs manières d’injecter des dépendances : injection de champ avec @Autowired, injection par setter ou injection par constructeur. Mais dans les projets réels, on recommande presque toujours l’injection par constructeur. C’est le modèle souvent utilisé avec @RequiredArgsConstructor de Lombok.

@Service
@RequiredArgsConstructor // Cela genere automatiquement linjection par constructeur.
public class OrderService {
    // final peut etre utilise, donc cest sur
    private final PaymentService paymentService;
}

Pourquoi ?

  1. Immutabilité (Final) : une fois injectée, une dépendance ne peut plus être changée. Une pièce ne devrait jamais être remplacée en cours d’exécution de l’application.
  2. Prévention des références circulaires : la situation d’« attente infinie », où A a besoin de B et B a besoin de A, est détectée dès le démarrage du serveur.
  3. Facilité de test : quand on écrit des tests unitaires en Java pur, sans Spring, on peut injecter soi-même des objets factices (Mock).

Pour conclure : pas un magicien, mais un chef d’orchestre

Au début, Spring me rebutait parce que j’avais l’impression qu’il manipulait mon code à sa guise. Aujourd’hui, je le vois autrement. Spring n’est pas un dictateur qui me complique la vie, mais un chef d’orchestre compétent qui organise des relations complexes entre les objets.

Grâce à cela, je passe moins de temps à me demander « quel objet dois-je créer ? » et davantage à réfléchir à « comment construire la logique métier avec cet objet ? ». C’est probablement pour cela que tant de développeurs en Corée continuent de faire confiance à Spring.

Nous avons maintenant confié la gestion des objets à Spring. Le serveur est prêt à démarrer. Mais une application web ne tourne pas seule : elle doit dialoguer avec le frontend. À l’époque de PHP, c’était pratique parce que HTML et code cohabitaient dans un seul fichier. Alors pourquoi sépare-t-on aujourd’hui le frontend, avec Vue ou React, du backend ? Et pourquoi une erreur CORS en rouge apparaît-elle dès qu’on essaie de relier les deux ?

La prochaine fois, nous examinerons l’évolution de l’architecture web, SSR vs CSR, ainsi que la véritable nature de CORS, ce mur qui se dresse entre les deux.

Laisser un commentaire