Aller au contenu

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.

Architecture en couches - Exemple de fonctionnement avec la validation d'une commande

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.