Tous les quelques années, l'industrie s'attache à un pattern et l'applique partout. Les microservices en 2018. L'architecture événementielle en 2020. Le Domain-Driven Design occupe cette position depuis un moment, et les symptômes sont familiers : des agrégats sans invariants, des value objects qui encapsulent une simple chaîne de caractères, des événements de domaine déclenchés pour un appel updateUser basique.

Le code a l'air sérieux. Le diagramme d'architecture a l'air impressionnant. Et un ingénieur compétent qui rejoint l'équipe met encore trop de temps à comprendre pourquoi une simple modification de contenu traverse quatre couches d'abstraction.

C'est du DDD cargo cult. Les équipes l'appliquent pour signaler de la séniorité, pas pour résoudre un problème. Le pattern devient l'objectif au lieu de rester un outil.

Ce qu'est réellement le DDD

Avant de parler des cas où il ne faut pas l'utiliser, il faut être précis sur ce qu'il est.

Le DDD n'est pas une architecture. Ce n'est pas une structure de dossiers. Ce n'est pas une collection de patterns à appliquer pour donner une impression de sophistication.

Le DDD est un investissement dans la conversation. Son vrai rôle est de créer un langage partagé entre les personnes qui comprennent le métier et celles qui construisent le logiciel, afin que tout le monde parle bien de la même chose autour de la table. Le langage omniprésent n'est pas un artefact technique. C'est la preuve que la conversation a eu lieu.

Les patterns tactiques - agrégats, value objects, événements de domaine, repositories - sont des outils pour protéger cette compréhension partagée dans le code. Ils ne sont pas le sujet. La conversation est le sujet.

Si votre équipe n'a pas cette conversation avec le métier, le DDD ne vous sauvera pas. Les patterns sans dialogue ne sont que du boilerplate.

Le problème du CRUD

Prenons deux systèmes e-commerce.

Le premier est un catalogue produit basique. Les produits ont un nom, un prix, une description et un niveau de stock. Les utilisateurs parcourent le catalogue, ajoutent au panier, puis passent commande. Les règles sont simples et stables. Pas de logique conditionnelle, pas d'invariant métier spécifique que le code doit protéger, pas de concept qui nécessite une négociation entre l'équipe engineering et le métier.

Ce système a un domaine, mais pas assez de complexité métier pour justifier du DDD tactique. Appliquer le DDD ici revient à introduire des agrégats qui ne protègent aucun invariant, des value objects qui ajoutent de la cérémonie sans protection, et des événements de domaine que personne ne consomme.

Le second système vend de la nutrition vétérinaire. Les règles de prix dépendent de la race, de l'âge, du poids et de l'état de santé de l'animal. Les promotions s'appliquent différemment selon que le client est une clinique vétérinaire, une animalerie ou un consommateur final. Certains produits ne peuvent être recommandés que par des professionnels certifiés. Les règles sont complexes, elles changent souvent, et se tromper a de vraies conséquences.

J'ai travaillé sur une plateforme de ce type au sein d'une équipe de conseil. Les règles métier n'étaient pas simples. Les conversations entre produit, experts vétérinaires et engineering étaient réellement difficiles. Les mêmes termes prenaient des sens différents selon les interlocuteurs jusqu'à ce que nous forcions l'alignement. Cette friction est exactement l'endroit où le DDD justifie son coût.

La différence entre ces deux systèmes n'est pas la technologie. C'est la complexité du domaine et le coût d'une mauvaise compréhension.

Les trois signaux qui justifient le DDD

Après suffisamment de projets, certains signaux deviennent reconnaissables.

Le premier signal : le métier répond souvent "ça dépend". Les systèmes simples ont des règles simples. Les domaines complexes ont des règles conditionnelles : des règles qui dépendent du contexte, de l'état, de l'historique ou de la combinaison de plusieurs facteurs. Quand la réponse métier à presque chaque question commence par "ça dépend de...", le domaine mérite probablement d'être modélisé explicitement.

Le deuxième signal : les conversations entre technologie et métier se cassent régulièrement. Quand un product manager décrit un besoin et que l'équipe engineering construit autre chose, non par manque d'exécution mais par vraie incompréhension, le langage partagé manque. Le langage omniprésent du DDD existe précisément pour réduire cet écart. Si cet écart n'existe pas, le besoin non plus.

Le troisième signal : vous devez protéger l'intégrité métier, pas seulement l'intégrité de la base de données. Une contrainte de clé étrangère protège l'intégrité référentielle. Un agrégat protège l'intégrité métier : l'invariant qui dit qu'une certaine combinaison d'états ne doit jamais exister. Si vos règles peuvent être exprimées entièrement par des contraintes de base de données et des schémas de validation, vous n'avez probablement pas besoin d'agrégats.

La checklist du cargo cult

Voici les signes que le DDD a été appliqué sans justification :

  • Des agrégats qui contiennent une seule entité et ne protègent aucun invariant.
  • Des value objects qui existent seulement pour encapsuler un primitif sans logique de validation.
  • Des événements de domaine déclenchés pour des opérations que personne ne consomme.
  • Un UserDomainService qui fait exactement ce qu'une fonction ferait.
  • De nouveaux développeurs qui passent leurs premières semaines à comprendre l'architecture au lieu de comprendre le produit.
  • Le mot "domaine" partout dans le code, alors que personne ne peut expliquer ce qu'est réellement le domaine.

Aucun de ces problèmes n'est un problème du DDD. Ce sont des problèmes liés à l'application du DDD dans un contexte qui n'en avait pas besoin.

Le DDD n'a pas besoin d'être tout ou rien

C'est la position pragmatique que beaucoup d'articles oublient.

Vous n'êtes pas obligé d'appliquer le DDD à tout votre système. Un bounded context est, par définition, une frontière. Certains contextes de votre système peuvent porter une vraie complexité métier. D'autres peuvent être du CRUD à peine glorifié. Les deux peuvent coexister.

Sur Fleet, la plateforme SaaS que je construis, j'ai commencé avec du CRUD simple. Véhicules, utilisateurs, affectations : des données directes, avec des opérations directes. Pas d'invariant à protéger, pas de règle qui méritait une modélisation explicite.

À mesure que le produit évoluait, une partie du domaine a commencé à résister à cette simplicité. Les règles d'affectation de flotte sont devenues conditionnelles. La logique de disponibilité a accumulé des exceptions. Les conversations avec les parties prenantes sont devenues plus difficiles. Nous utilisions les mêmes mots pour désigner des choses différentes.

C'était le signal. J'ai introduit le DDD tactiquement dans ce bounded context seulement. Le reste du système est resté simple. Les parties CRUD ne sont pas devenues plus complexes parce qu'une partie du produit avait besoin de structure.

Le chemin honnête est celui-ci : commencer simple, introduire de la structure là où le problème l'exige, laisser le reste tranquille.

Le coût dont on parle peu

Le coût en boilerplate du DDD est bien documenté. Le coût humain l'est beaucoup moins.

Quand un nouveau développeur rejoint un projet où le DDD complet a été appliqué à un domaine simple, ses premières semaines sont consacrées à comprendre l'architecture plutôt qu'à comprendre le métier. Il apprend le vocabulaire des patterns avant d'apprendre ce que fait le produit. L'abstraction devient l'obstacle.

Dans un domaine réellement complexe, cet investissement finit par payer. L'architecture aide le développeur à naviguer une complexité qu'il n'aurait pas pu garder entièrement en tête. Dans un domaine simple, l'investissement ne revient jamais. Le développeur a appris une abstraction qui ne protège rien.

C'est un vrai coût pour les engineering managers et les CTO. Il apparaît dans le temps d'onboarding, dans la frustration de développeurs capables qui travaillent contre une friction inutile, et dans l'attrition de personnes venues résoudre des problèmes métier mais qui se retrouvent à maintenir du code cérémoniel.

Quand l'introduire — et comment

N'appliquez pas le DDD au démarrage d'un projet sauf si vous avez des preuves fortes que le domaine est déjà complexe. Une preuve signifie : vous avez fait de la discovery avec le métier, les règles ont des conditions et des exceptions, et les conversations sont réellement difficiles.

Introduisez-le progressivement quand les signaux apparaissent. Refactorer vers le DDD dans un bounded context précis est gérable. Retirer le DDD d'un système qui n'en a jamais eu besoin est douloureux.

Le déclencheur n'est ni la taille du projet ni la taille de l'équipe. C'est le moment où les règles métier commencent à résister à une modélisation simple : quand une fonction ordinaire ou une contrainte de base de données n'est plus le bon outil pour exprimer ce que le métier veut réellement dire.

L'idée à garder

Le DDD est un investissement dans la conversation, pas dans le code.

Si la conversation entre votre équipe engineering et vos parties prenantes métier fonctionne, si tout le monde autour de la table comprend la même chose quand il utilise le même mot, alors les patterns tactiques sont une façon de protéger cette compréhension partagée dans le code.

Si la conversation ne fonctionne pas, les patterns ne la répareront pas.

Commencez là. Réparez d'abord la conversation. L'architecture suivra.