Architecture : SOLID et injection de dépendances

Se connecter pour s'inscrire

Votre progression

Continuez pour débloquer la suite !
0 / 0 étapes complétées 0
%

Syllabus

  1. Description

  2. Objectifs

  3. Validations de compétences

  4. Public cible

    Aucun public cible spécifié pour ce module.

  5. Besoins techniques

  6. Prérequis

    • Aucun prérequis
  7. Niveau

  8. Historique du module

    Aucune action enregistrée

Architecture : principes SOLID et injection de dépendances

  1. Les principes SOLID, et ce qu'ils valent vraiment

    Les principes SOLID sont des critères de conception, pas des recettes à cocher. Savoir les nommer ne sert à rien ; savoir à quel défaut d'architecture chacun répond, oui.

    Chaque principe masque un symptôme

    PrincipeLe symptôme qu'il traite
    Responsabilité unique une classe qui change pour trois motifs non liés ; c'est elle qu'on ouvre a chaque nouvelle demande
    Ouvert/fermé chaque nouveau cas oblige à modifier un code existant qui fonctionnait
    Substitution une hiérarchie où la sous-classe casse l'attente de la classe mère
    Interface segregation un client forcé d'implémenter des méthodes qu'il n'utilise pas
    Inversion des dépendances un composant de haut niveau qui dépend d'un composant de détail

    L'erreur d'application

    Le symptôme le plus cité est « la classe trop grosse ». Le vrai problème n'est pas sa taille : c'est qu'elle change pour des raisons sans rapport. Une classe de six cents lignes qui gère une seule chose est un bon candidat ; une classe de quatre-vingts lignes dont la moitié des méthodes ne sert à personne est un mauvais.

    Le test de la responsabilité unique

    Une formulation courte : « Cette classe changerait-elle si l'exigence changeait ? » Si oui, la raison du changement est une responsabilité distincte. Appliquée à un service qui valide, calcule, enregistre et envoie un e-mail, elle isole les quatre en une réponse, sans diagramme.

    Quand ne pas appliquer le principe

    Découper systématiquement produit ce que la littérature appelle la dispersion conceptuelle : vingt fichiers pour une fonctionnalité, et plus personne ne sait où chercher. Le découpage se justifie quand la séparation correspond à deux notions qui changent pour deux raisons différentes. Sinon, on a ajouté de la complexité d'injection sans aucun bénéfice.

  2. L'injection de dépendances : inversion du contrôle

    L'injection de dépendances est le mécanisme technique qui rend possible l'inversion des dépendances. Le principe dit qu'un composant de haut niveau ne doit pas créer lui-même ce dont il dépend ; le mécanisme dit comment on lui fournit.

    Le service localisé est déjà une dépendance

    Écrire new HttpClient() dans une méthode n'est pas « utiliser une dépendance », c'est créer la dépendance sur place. Le composant est alors lié à un type concret et à son cycle de vie, et il devient impossible à tester sans déclencher un accès réseau réel.

    Le conteneur d'inversion de contrôle fourni avec l'écosystème résout ce cas : la dépendance est déclarée dans le constructeur, et le conteneur fournit l'instance. Le service ignore tout du cycle de vie, et un test lui passe une doublure.

    Portée des instances

    • transitoire : une nouvelle instance par résolution. Par défaut, et rarement justifié ;
    • avec portée : une instance partagée par demande HTTP. C'est la portée à utiliser par défaut, car elle garantit qu'un état de requête ne fuit pas vers la requête suivante ;
    • simple instance : partagée par toute l'application. À réserver aux services sans état et thread-safe — un piège classique est d'y stocker une propriété par utilisateur.

    La fuite d'état entre requêtes est le bug le plus coûteux de ce mécanisme, et il est invisible en développement mono-utilisateur. Il apparaît en production avec un second utilisateur, puis devient impossible à reproduire en recette.

  3. Du modèle métier à l'API

    Une application se lit en couches. L'erreur classique est de les confondre : le modèle métier qui connaît le format JSON, ou le contrôleur qui contient une règle de gestion.

    Le sens de la dépendance

    Les dépendances pointent toujours vers l'intérieur. La couche API connaît le service, le service connaît le domaine, le domaine ne connaît personne. Cette règle Unique et simple rend le cœur métier testable sans base de données, sans réseau et sans framework — ce qui est la définition même d'un code testable rapidement.

    L'exception qui prouve la règle

    Le domaine a besoin d'un concept externe : un identifiant unique, un horodatage, une unité monétaire. Il ne doit pas pour autant importer la bibliothèque qui le fournit. On déclare une abstraction dans le domaine, on fournit l'implémentation par injection. La règle reste respectée, et le domaine compilera seul.

    Le modèle ne doit pas exposer son stockage

    Un objet entité repris tel quel dans une réponse JSON va exposer ce qu'il ne devrait pas : un identifiant technique interne, une date de mise à jour, parfois un hash de mot de passe ou un numéro de sécurité sociale si le mapping est baclé. La séparation entre modèle de persistance et modèle d'échange n'est pas de la sur-ingénierie : c'est ce qui évite qu'une migration de base de données casse une API publique.

    Où s'arrêtent les couches

    Une couche de plus n'est pas automatiquement mieux. Trois couches — API, application, domaine — suffisent à la quasi-totalité des cas. Le critère de découpage n'est jamais le nombre de couches, mais le fait qu'une couche puisse être remplacée indépendamment : un jour où la base change, seul le dépôt doit bouger.

Exercices, examens et projets

Exercice

Atelier ASP.NET Core

Écrire une API avec transaction, annulation et tests de cas limites.

Obligatoire Consulter
Examen

Examen C# et .NET

Évaluer conception, concurrence, requêtes et déploiement.

Obligatoire Consulter