← Back to Insights
/ Engineering Insights

Comment je structure des backends multicouches pour favoriser la séparation des responsabilités, la testabilité et la maintenabilité

Après des années à refactoriser des backends .NET, un schéma d'architecture résiste toujours à la pression : la véritable séparation en couches. Voici exactement comment je la structure, et pourquoi chaque limite de couche est une décision délibérée.

Comment je structure des backends multicouches pour favoriser la séparation des responsabilités, la testabilité et la maintenabilité
Emile Ndagijimana
Emile Ndagijimana
August 4, 2026
/
Architecture & Design

Le problème des architectures plates

Chaque projet commence simplement. Un contrôleur appelle un service. Un service appelle la base de données. Ça fonctionne, jusqu'au jour où ça ne fonctionne plus. Six mois plus tard, vous avez des contrôleurs qui contiennent de la logique métier, des services qui accèdent directement à la base de données, et une suite de tests qui nécessite une connexion SQL Server active pour exécuter une seule assertion.

J'ai refactorisé ce schéma plus de fois que je ne saurais compter. La solution est toujours la même : une véritable séparation en couches, imposée par la structure du projet et pas seulement par des conventions de nommage.

Les quatre couches que j'utilise dans chaque projet .NET

Ma structure standard correspond directement au modèle d'architecture en oignon (Onion Architecture), adapté aux réalités du développement .NET en entreprise.

1. Domain — le noyau pur

Aucune dépendance. Aucune. Cette couche contient vos entités, vos objets de valeur, vos événements de domaine et vos interfaces de dépôt. Elle définit ce que le système modélise — des contrats sans implémentation. Si ce projet référence un ORM, un logger ou un client HTTP, quelque chose ne va pas.

2. Application — l'orchestration sans infrastructure

Les cas d'usage, les commandes, les requêtes (façon CQRS avec MediatR), les validateurs et les DTO vivent ici. La couche Application ne dépend que de Domain. Elle orchestre le travail — elle appelle des méthodes du domaine, déclenche des événements — mais elle ne parle jamais directement à une base de données. Elle fait confiance aux interfaces définies dans Domain.

3. Infrastructure — la couche d'adaptation

Les dépôts EF Core, les clients Azure Blob, les services SMTP, les wrappers d'API externes — tout est ici. Infrastructure implémente les interfaces déclarées dans Domain. C'est la seule couche qui devrait jamais importer un package NuGet pour des entrées/sorties. Remplacer un dépôt SQL Server par Cosmos DB ne devrait nécessiter des changements que dans un seul projet.

4. Presentation — HTTP comme mécanisme de livraison

Contrôleurs, middlewares, validateurs de requêtes, mappeurs de réponses. La couche Presentation traduit le HTTP en commandes Application. Elle ne connaît rien de votre base de données ni de vos règles métier — elle mappe et transmet.

Pourquoi cela porte ses fruits dans la vraie vie

Chez ADENES, nous avons hérité d'un système où la logique de traitement des sinistres d'assurance était directement intégrée dans les contrôleurs de l'API. Extraire cela vers une structure Domain + Application correcte a pris trois mois — mais a réduit le temps nécessaire pour tester une nouvelle règle de sinistre, passant d'heures à quelques minutes. Les tests unitaires s'exécutent sans base de données. Les nouveaux développeurs sont opérationnels en quelques jours, pas en semaines.

« L'objectif n'est pas une architecture propre pour le principe. L'objectif est une base de code où le coût du changement reste faible à mesure que le système grandit. »

La règle moins évidente : le sens des dépendances est primordial

Les dépendances pointent toujours vers l'intérieur. Domain ne connaît rien. Application connaît Domain. Infrastructure connaît Domain et Application. Presentation connaît Application. Imposez cela via les références de projet .NET — pas via des conventions de nommage. Si une référence crée une dépendance circulaire ou pointe dans le mauvais sens, la compilation échoue. C'est votre architecture qui s'applique elle-même.

Un conseil pratique pour les bases de code existantes

N'essayez pas de tout refactoriser d'un coup. Commencez par un seul concept de domaine. Extrayez l'interface. Déplacez l'implémentation. Écrivez un test unitaire qui s'exécute sans base de données. Ce premier test est une preuve de concept — et c'est généralement suffisant pour convaincre le reste de l'équipe.

Ce sont les mêmes principes de séparation en couches qui régissent le backend de Contractly Pro — devis, contrats, facturation et paiements vivent chacun dans leur propre couche testable plutôt que dans un service monolithique enchevêtré. Essayer Contractly Pro gratuitement →

/ My SaaS

I write about building Contractly Pro

Real decisions, real tradeoffs, real architecture — from solo founder to production SaaS. Read the Founder Journal or try the app.