Architecture en couches
Introduction
L’architecture en couches organise une application selon les responsabilités de son code : recevoir les demandes, exécuter les traitements métier et accéder aux données. Chaque couche possède un rôle défini et communique avec les autres selon des règles établies.
Cette organisation est courante dans les applications .NET. Elle peut rendre le code plus facile à comprendre et à faire évoluer, à condition que les couches correspondent à de vraies responsabilités. Elle ne détermine toutefois pas, à elle seule, la manière dont l’application est déployée.
Qu’est-ce que l’architecture en couches ?
Une application en couches distingue généralement :
- La présentation, qui reçoit les requêtes HTTP et produit les réponses : contrôleurs ASP.NET Core, endpoints, modèles d’entrée et de sortie.
- L’application, qui coordonne les cas d’utilisation et leurs résultats.
- Le domaine, qui porte les règles métier et les invariants.
- L’infrastructure, qui fournit les accès techniques : EF Core, fichiers, messagerie ou services externes.
Par exemple, lorsqu’un client valide une commande, l’API reçoit la demande, la couche application organise l’opération, le domaine vérifie les règles métier et l’infrastructure enregistre le résultat.
Ce découpage décrit des responsabilités dans le code. Toutes les couches peuvent être exécutées dans un même processus et déployées ensemble. Une architecture en couches peut donc faire partie d’une application monolithique, sans que les deux notions soient équivalentes.
Comment les couches communiquent-elles ?
Il faut distinguer le parcours d’une demande du sens des dépendances dans le code. Une demande peut traverser plusieurs couches, tandis que les références entre projets suivent les règles choisies pour l’application.
Dans une organisation classique, chaque couche appelle la couche suivante. Dans une organisation où le domaine doit rester indépendant des détails techniques, l’application définit les contrats dont elle a besoin et l’infrastructure les implémente. ASP.NET Core associe ces contrats à leurs implémentations lors du démarrage.
Le nombre de couches et leur emplacement ne sont pas figés : deux responsabilités peuvent cohabiter dans un projet si les séparer n’apporte pas de clarté.
Les avantages
Des responsabilités identifiables
Chaque partie du code possède un rôle clair, ce qui facilite la lecture et la recherche d’un traitement.
Des règles métier mieux protégées
Les décisions métier peuvent rester indépendantes des contrôleurs et des détails de persistance.
Des tests ciblés
Les règles, les cas d’utilisation et les accès aux données peuvent être vérifiés selon leurs responsabilités.
Des évolutions techniques mieux circonscrites
Une modification de l’API ou de la persistance peut rester localisée si les frontières sont respectées.
Les limites
Du code de passage superflu
Des services et interfaces qui ne font que transmettre les mêmes données ajoutent du code sans clarifier le comportement.
Des changements transversaux
Une fonctionnalité peut nécessiter des modifications dans plusieurs couches, ce qui ralentit le travail si leurs frontières sont trop rigides.
Des frontières faciles à contourner
Des endpoints qui portent les règles métier ou accèdent directement aux données peuvent rendre le découpage incohérent.
Une organisation insuffisante pour les grands domaines
Regrouper toutes les fonctionnalités dans les mêmes dossiers par couche peut rendre leurs parcours difficiles à retrouver.
Quand cette architecture est-elle un choix pertinent ?
L’architecture en couches convient lorsque l’application possède des responsabilités suffisamment distinctes pour justifier leur séparation : une API, plusieurs cas d’utilisation, des règles métier et des accès aux données qui évoluent à des rythmes différents.
Elle est également utile lorsqu’une équipe souhaite fixer des conventions simples sur l’emplacement du code et sur les dépendances autorisées. Pour une petite application CRUD, une structure plus légère peut suffire. Le découpage peut ensuite évoluer avec la complexité du métier.
Si les fonctionnalités deviennent nombreuses, il peut être utile de les regrouper par module ou par cas d’utilisation, tout en conservant des frontières entre présentation, métier et infrastructure là où elles apportent de la clarté.
Bonnes pratiques avec .NET
Définir le sens des dépendances
Établir les références autorisées entre projets et éviter les dépendances circulaires.
Placer les décisions métier au bon endroit
Confier les règles au domaine et réserver à l’API la traduction des demandes et des réponses HTTP.
Créer des abstractions utiles
Définir les contrats là où ils répondent à un besoin, puis associer leurs implémentations avec l’injection de dépendances ASP.NET Core.
Séparer les contrats publics de la persistance
Éviter d’exposer directement les entités EF Core lorsque les données et les règles de l’API ont des rôles différents.
Préserver les frontières fonctionnelles
Regrouper les traitements liés à une même capacité métier lorsque l’application grandit.
Tester selon le rôle de chaque couche
Vérifier les règles isolément, les accès EF Core par des tests d’intégration et les parcours essentiels de bout en bout.
