Ce template utilise l'approche Domain-Driven Design (DDD), une philosophie de conception logicielle qui met l'accent sur la modélisation du domaine métier et la collaboration entre experts techniques et experts métier.
Le domaine métier est au cœur de l'architecture. Toutes les décisions de conception sont guidées par la compréhension approfondie des besoins métier.
Un langage commun partagé entre les développeurs et les experts métier. Les termes utilisés dans le code doivent correspondre exactement aux termes utilisés dans les discussions métier.
Exemple dans ce projet :
Product- Entité représentant un produitCreateProductUseCase- Cas d'utilisation pour créer un produitProductRepository- Repository pour accéder aux produits
Le projet est organisé en couches distinctes pour séparer les préoccupations :
┌─────────────────────────────────────┐
│ WebApi (Présentation) │ ← Interface utilisateur / API
├─────────────────────────────────────┤
│ Application (UseCases) │ ← Logique applicative
├─────────────────────────────────────┤
│ Domain (Entités) │ ← Logique métier pure
├─────────────────────────────────────┤
│ Infrastructure │ ← Accès aux données, services externes
└─────────────────────────────────────┘
Emplacement : src/TemplateCleanArchi/Domain/
Le domaine contient :
- Entités : Objets métier avec identité (
Product) - Interfaces : Contrats pour les repositories (
IProductRepository) - Value Objects : Objets immuables sans identité (à ajouter selon les besoins)
Caractéristiques importantes :
- ✅ Aucune dépendance vers les autres couches
- ✅ Logique métier pure et testable
- ✅ Entités avec encapsulation forte (propriétés privates)
Exemple - Product Entity :
public class Product
{
public Guid Id { get; set; }
public string Name { get; private set; } = null!;
public decimal Price { get; private set; }
private Product() { } // Pour EF Core
public Product(string name, decimal price)
{
Id = Guid.NewGuid();
Name = name;
Price = price;
}
}Emplacement : src/TemplateCleanArchi/Application/
La couche application contient :
- UseCases : Scénarios d'utilisation métier
- DTOs : Objets de transfert de données
- Interfaces : Contrats pour les services (
IUseCase,IUnitOfWork) - Exceptions : Exceptions métier personnalisées
Pattern UseCase :
Chaque action métier est représentée par un UseCase distinct qui implémente IUseCase<TInput, TResult>.
public interface IUseCase<in TInput, TResult>
{
Task<TResult> Execute(TInput input);
}Exemple - CreateProductUseCase :
public class CreateProductUseCase : IUseCase<CreateProductRequest, Guid>
{
private readonly IProductRepository _repository;
public CreateProductUseCase(IProductRepository repository)
{
_repository = repository;
}
public async Task<Guid> Execute(CreateProductRequest request)
{
var product = new Product(request.Name, request.Price);
await _repository.AddAsync(product);
return product.Id;
}
}Emplacement : src/Infrastructure/
L'infrastructure contient :
- Repositories : Implémentations concrètes des repositories
- DbContext : Contexte Entity Framework Core
- Services externes : Intégrations avec APIs, systèmes de fichiers, etc.
Caractéristiques :
- ✅ Implémente les interfaces définies dans le domaine
- ✅ Contient les détails techniques (EF Core, SQL, etc.)
- ✅ Peut être remplacée sans affecter le domaine
Emplacement : WebApi/
La couche présentation contient :
- Controllers : Points d'entrée API
- Configuration : Injection de dépendances, middleware
- Models de requête/réponse : Spécifiques à l'API
Chaque couche a une responsabilité claire :
- Le domaine gère la logique métier
- L'application orchestre les cas d'utilisation
- L'infrastructure gère les détails techniques
- La présentation gère l'interface utilisateur
- Les entités du domaine sont pures et facilement testables
- Les UseCases peuvent être testés avec des mocks des repositories
- Les tests d'intégration peuvent utiliser des repositories en mémoire
- Le code métier est isolé des détails techniques
- Les changements dans l'infrastructure n'affectent pas le domaine
- Facile d'ajouter de nouveaux cas d'utilisation
- Nouvelle fonctionnalité = Nouveau UseCase
- Nouveau système de stockage = Nouvelle implémentation du repository
- Nouvelle API = Nouveau controller
Les dépendances vont toujours de l'extérieur vers l'intérieur :
WebApi → Application → Domain
↓ ↓
Infrastructure
- ✅ L'application peut dépendre du domaine
- ✅ L'infrastructure peut dépendre du domaine et de l'application
- ✅ La présentation peut dépendre de toutes les couches
- ❌ Le domaine NE DOIT PAS dépendre de l'application ou de l'infrastructure
Les interfaces sont définies dans le domaine, mais implémentées dans l'infrastructure :
// Domain/Interfaces/IProductRepository.cs
public interface IProductRepository { }
// Infrastructure/Repositories/ProductRepository.cs
public class ProductRepository : IProductRepository { }- Définir le DTO de requête (Application/DTOs)
public record UpdateProductRequest(Guid Id, string Name, decimal Price);- Créer le UseCase (Application/UseCases)
public class UpdateProductUseCase : IUseCase<UpdateProductRequest, bool>
{
private readonly IProductRepository _repository;
public UpdateProductUseCase(IProductRepository repository)
{
_repository = repository;
}
public async Task<bool> Execute(UpdateProductRequest request)
{
var product = await _repository.GetAsync(request.Id);
if (product == null) return false;
// Mise à jour via méthode du domaine
product.UpdateDetails(request.Name, request.Price);
await _repository.UpdateAsync(product);
return true;
}
}- Utiliser dans un Controller (WebApi)
[HttpPut("{id}")]
public async Task<IActionResult> Update(Guid id, UpdateProductRequest request)
{
var useCase = new UpdateProductUseCase(_productRepository);
var result = await useCase.Execute(request);
return result ? Ok() : NotFound();
}Ce template utilise DDD avec UseCases plutôt que CQRS (Command Query Responsibility Segregation).
| Aspect | DDD avec UseCases | CQRS |
|---|---|---|
| Séparation | Par cas d'utilisation métier | Par commande/requête |
| Complexité | Plus simple | Plus complexe |
| Use Cases | CreateProductUseCase, GetProductUseCase |
CreateProductCommand, GetProductQuery |
| Handlers | Un par UseCase | CommandHandler et QueryHandler séparés |
| Adapté pour | Projets de taille petite à moyenne | Projets complexes avec lecture/écriture intensive |
- Domain-Driven Design par Eric Evans
- Clean Architecture par Robert C. Martin
- Documentation Microsoft sur DDD
L'approche DDD dans ce template vous permet de :
- 🎯 Modéliser le métier de façon claire et précise
- 🧪 Écrire du code hautement testable
- 🔧 Maintenir facilement votre code
- 📈 Faire évoluer votre application sereinement
Le code métier reste pur et indépendant des détails techniques, ce qui facilite grandement la compréhension, les tests et la maintenance de l'application.