Échelle du DDD dans ASP.NET : défis au-delà de 30 agrégats
Lorsqu’un projet dépasse 30 agrégats dans ASP.NET avec Entity Framework Core, le principe « une requête — un agrégat » entraîne des problèmes de performance critiques. Chaque agrégat nécessite un chargement complet avec ses objets imbriqués, générant des requêtes SQL riches en JOINs. Ce phénomène devient particulièrement problématique dans les systèmes ERP ou les plateformes marchandes où les graphes d’objets atteignent 5 à 6 niveaux d’imbrication.
Une requête typique sur l’agrégat Order ressemble à ceci :
var orders = await context.Orders
.Include(o => o.Customer)
.ThenInclude(c => c.Address)
.Include(o => o.Customer)
.ThenInclude(c => c.Contacts)
.Include(o => o.Items)
.ThenInclude(i => i.Product)
.ThenInclude(p => p.Category)
.Include(o => o.Items)
.ThenInclude(i => i.Discount)
.ToListAsync();
La requête SQL résultante contient des dizaines de LEFT JOIN, ralentissant considérablement son exécution. Mettre à jour un seul champ dans l’en-tête de commande oblige à charger tous les OrderItems comme partie intégrante de l’agrégat, amplifiant ainsi la charge de performance.
Croissance exponentielle des spécifications et leurs limites
Le patron Specification encapsule la logique de requête, mais avec plus de 30 agrégats, la collection de classes Specification peut s’étendre à plusieurs centaines de fichiers. La composition via And/Or produit des SQL inefficaces en raison de la dépendance IQueryable d’EF Core.
Problèmes clés :
- Spécifique à l’ORM : Les Specifications ne fonctionnent pas avec Dapper ou gRPC sans reprise complète.
- Composition complexe : Des scénarios réels impliquant rôles, statuts et fuseaux horaires deviennent ingérables.
- Surcharge d’abstraction : Le temps passé à concevoir des abstractions excède celui consacré à la logique métier réelle.
Transactions inter-agrégats et surcharge infrastructurelle
Le DbContext étendu fonctionne bien pour le modèle Unit of Work dans les petits projets. Dans les systèmes complexes, les workflows métier exigent souvent des mises à jour simultanées sur 5+ agrégats : passer une commande, traiter un paiement, réserver le stock et créer une tâche centre d’appel.
Les solutions disponibles contredisent les principes du DDD :
- Transaction unique sur base de données — crée des services God et viole les frontières des agrégats.
- Sagas distribuées ou modèle Outbox — augmentent la complexité jusqu’à 10 fois.
Résultat : 70 % du codebase deviennent du glue infrastructurel pour synchronisation, pas de logique métier.
Navigation dans le code : milliers de fichiers, itérations ralenties
La structure DDD (API/Application/Domain/Infrastructure + Features) génère plus de 1 000 fichiers avec 30+ agrégats. Modifier un champ d’une entité affecte :
- L’entité domaine
- La configuration Fluent API
- La migration
- La commande
- Le validateur (FluentValidation)
- Le gestionnaire
- Le DTO
- Le mapper (AutoMapper)
- La spécification
- Les tests
Cela ralentit drastiquement le développement, complique l’onboarding et nuit à la maintenance à long terme.
Ce qui compte vraiment
- Performance : Les opérations Include/ThenInclude lourdes produisent des SQL inefficaces, faisant croître les temps de réponse de l’API de façon exponentielle.
- Spécifications : Ne se scalent pas, sont liées à EF Core, et leur composition mène à des erreurs.
- Transactions : Les opérations inter-agrégats imposent des compromis entre idéaux DDD et besoins métiers réels.
- Taille du codebase : Plus de 1 000 fichiers ralentissent les itérations de 50 à 70 %.
- Approche hybride : Appliquer DDD uniquement au cœur ; utiliser CQRS et Slices verticales pour les préoccupations périphériques.
Recommandations pour la migration
Pour les projets avec 30+ agrégats, adoptez des architectures hybrides :
- CQRS : Séparer commandes et requêtes ; utiliser des modèles de lecture sans clauses Include.
- Slices verticales : Regrouper le code par fonctionnalité, minimisant la complexité des couches.
- Conception par slices fonctionnels : Obtenir une modularité sans architecture rigide type oignon.
Ces approches préservent les principes DDD dans les domaines complexes tout en simplifiant le reste.
— Editorial Team
Aucun commentaire pour le moment.