DDD ne commence pas par un dossier `domain`
Eric Evans présente DDD comme un ensemble de patterns et de définitions pour travailler avec des modèles de domaine. Martin Fowler insiste sur la modélisation d'un domaine complexe et sur un langage commun entre développeurs et experts métier. [1][2][4]
Une structure `domain/application/infrastructure` ne suffit donc pas à faire du DDD. Un projet peut avoir des dossiers parfaitement nommés tout en restant composé de DTO et de logique procédurale. Le DDD stratégique peut aussi être appliqué sans structure de couches canonique.
DDD stratégique et DDD tactique se situent à des niveaux différents
Le DDD stratégique traite la décomposition d'une grande domaine en sous-domaines et Bounded Contexts ainsi que leurs relations. Microsoft décrit l'analyse de domaine comme l'identification des sous-domaines et contextes, tandis que Fowler place Bounded Context au centre du DDD stratégique. [3][7]
Le DDD tactique agit à l'intérieur d'un contexte donné et comprend notamment Entities, Value Objects, Aggregates et Domain Services. Microsoft sépare explicitement analyse stratégique et modélisation tactique. [8]
Dans le frontend, il est souvent plus pertinent de commencer par le stratégique puis de décider quels contextes nécessitent réellement un modèle tactique riche.
Un Bounded Context n'est pas une couche technique
Fowler décrit un Bounded Context comme une frontière dans laquelle un modèle reste cohérent et les termes gardent un sens non ambigu. Le même concept, comme `Customer` ou `Product`, peut légitimement avoir une autre signification ailleurs. [3]
Dans une architecture frontend, `frontend`, `backend`, `React app`, `route` ou `micro-frontend` ne sont donc pas automatiquement des Bounded Contexts. Les frontières viennent du modèle et du langage métier, pas de la technologie. Des praticiens du DDD frontend rappellent la même distinction. [15][16]
Quand DDD dans le frontend a du sens
| Signal | Direction | Pourquoi |
|---|---|---|
| Nombreuses règles métier changeantes | DDD | Un modèle de domaine évite la dispersion des règles |
| Les mêmes concepts ont des sens différents dans le produit | DDD | Les Bounded Contexts maintiennent plusieurs modèles cohérents |
| Plusieurs équipes et experts métier collaborent | DDD | Ubiquitous Language réduit l'ambiguïté |
| CRUD simple et formulaires | Modularité plus simple | Le coût du DDD tactique peut dépasser son bénéfice |
| Le frontend reflète surtout une API | Modularité plus simple | Peu de logique métier propre au client à modéliser |
| Petite application avec une seule domaine cohérente | Modularité plus simple | Des frontières et couches supplémentaires peuvent apporter peu de valeur |
Le signal le plus fort est la présence de règles métier complexes et changeantes côté client : configurateurs, processus multi-étapes, tarification, permissions, transitions d'état, workflows ou plusieurs modèles d'un même concept dans différentes zones du produit.
DDD est aussi utile lorsque plusieurs équipes développent un grand produit et que les mêmes mots ont des sens différents selon les zones. Les Bounded Contexts servent précisément à gérer plusieurs modèles cohérents et plusieurs équipes. [3]
DDD Crew recommande d'abord de comprendre le domaine, d'identifier les sous-domaines stratégiques, puis de définir les responsabilités des Bounded Contexts avant de coder le modèle. [10]
Quand DDD devient de la surarchitecture
Si le frontend récupère surtout des données, les affiche, gère des formulaires et envoie des commandes CRUD simples sans règles métier importantes côté client, l'ensemble des patterns tactiques DDD résout rarement un problème réel.
Microsoft indique explicitement qu'un contexte CRUD simple peut se contenter d'un modèle de données anémique et que des patterns DDD plus complexes ne sont pas toujours justifiés. Un modèle riche devient plus pertinent lorsqu'il existe de nombreuses règles métier changeantes. [9]
Le même principe s'applique au frontend : la sophistication de l'architecture doit suivre la complexité métier, pas l'ambition technique de l'équipe.
Ubiquitous Language doit aussi apparaître dans le code UI
Ubiquitous Language est un langage commun et rigoureux construit par les développeurs et les experts métier autour du modèle. Fowler souligne qu'il doit évoluer avec la compréhension de le domaine. [4]
Dans le frontend, les noms des cas d'utilisation, actions, types, modules, écrans et états devraient donc utiliser le vocabulaire métier lorsqu'ils décrivent un comportement de domaine.
Si le métier parle de `approveApplication` mais que le code n'utilise que `setFlag2` ou `handleData`, le code cesse d'être une représentation claire du langage de le domaine.
Organiser un grand frontend par domaines, pas seulement par types de fichiers
Fowler indique qu'une organisation racine `view/model/data` peut convenir à un petit système, mais qu'en grandissant il est souvent préférable d'avoir des modules de haut niveau orientés domaine, chacun possédant ses propres couches internes. [5]
La documentation actuelle de Nx suit une idée similaire : les dossiers peuvent devenir des frontières d'ownership par domaine et les bibliothèques internes être classées comme `feature`, `ui`, `data-access` et `util`. [12]
Une structure pratique peut donc être `libs/orders/...`, `libs/billing/...`, `libs/identity/...` plutôt qu'un arbre global `components/`, `services/`, `models/`.
Séparer comportement de présentation et comportement métier
Fowler présente la séparation entre présentation, logique de domaine et accès aux données comme une modularisation efficace. Il note aussi que l'UI est généralement plus difficile à tester, ce qui rend utile le déplacement de la logique de domaine hors de la présentation. [5][6]
Un composant frontend devrait principalement afficher, gérer les événements UI et déléguer les opérations. Des règles comme l'annulation d'une commande, le calcul d'une remise ou la validité d'une transition d'état devraient avoir un emplacement explicite hors JSX, template ou classe de composant.
Cela n'interdit pas la logique de présentation dans les composants. Validation de vue, visibilité, focus local et animation ne sont pas des règles métier.
Des couches pratiques dans un contexte frontend
| Couche | Responsabilité | Exemples |
|---|---|---|
| presentation / ui | Rendu et comportement d'interface | components, routes, view state |
| application | Coordination des cas d'utilisation | commands, use cases, orchestration |
| domain | Règles, concepts et invariants métier | entities, value objects, policies |
| infrastructure / data-access | Intégrations techniques | HTTP, storage, SDKs, mappers |
DDD n'impose aucune structure de dossiers obligatoire. Séparer `presentation`, `application`, `domain` et `infrastructure` est une interprétation pratique de la séparation des responsabilités, pas une règle formelle d'Evans. [1][5]
La couche domain peut contenir règles, concepts et comportements indépendants du framework ; application coordonne les cas d'utilisation ; infrastructure adapte HTTP, stockage et SDK externes ; presentation contient composants, routage et état purement UI.
Le modèle API et le modèle de domaine frontend n'ont pas besoin d'être identiques
Un Bounded Context peut avoir son propre modèle d'un concept et différents contextes peuvent mapper différentes représentations. Fowler cite `Customer` et `Product` comme exemples classiques de termes dont le sens varie selon le contexte. [3]
Un DTO backend n'a donc pas besoin de traverser directement chaque composant. Un mapper ou adapter peut convertir le contrat de transport vers le modèle utilisé dans un contexte frontend.
Cette frontière est surtout utile lorsqu'une API sert plusieurs clients, est héritée, combine plusieurs domaines ou évolue séparément. Pour un endpoint CRUD simple, une couche de mapping supplémentaire peut être inutile.
Entities, Value Objects et Aggregates : les utiliser sélectivement
DDD distingue notamment Entities, Value Objects, Services et Aggregates. Fowler les présente comme partie du vocabulaire d'Evans, tandis que Microsoft décrit les agrégats comme un pattern tactique de cohérence du modèle. [2][8]
Le frontend ne devrait pas copier le modèle backend à l'identique seulement pour avoir les mêmes classes. Un Value Object est pertinent pour `Money`, `DateRange` ou `Email` s'il protège de vrais invariants. Un Aggregate est utile si le client doit réellement garantir des règles de cohérence.
Si un type ne sert qu'à afficher une ligne de tableau, un simple type TypeScript peut être préférable à Entity, Factory, Repository et Service.
L'état UI n'est pas l'état de domaine
React traite l'organisation de l'état comme un problème de conception et recommande d'éviter l'état redondant ou dupliqué. C'est une bonne base technique, mais reducers, stores ou signals ne créent pas à eux seuls un modèle de domaine. [14]
Un état comme `isModalOpen`, l'onglet actif ou la position de scroll appartient à la présentation. Le cycle de vie d'une commande, les transitions autorisées ou les règles d'un configurateur peuvent appartenir au modèle de domaine.
Séparer ces catégories évite les stores globaux qui mélangent données serveur, comportement métier et détails UI.
Les frontières doivent être imposées, pas seulement documentées
Nx permet de définir des tags de projet et des contraintes de dépendances déclaratives, par exemple pour interdire des imports entre scopes ou types de bibliothèques. La règle `@nx/enforce-module-boundaries` peut vérifier les imports pendant le lint. [11]
Nx prend aussi en charge plusieurs dimensions de tags, ce qui permet de modéliser séparément `scope`, type de bibliothèque, stabilité ou séparation client/server. [13]
Les décisions DDD peuvent ainsi devenir des règles CI : `billing` n'importe pas les internes de `identity`, `ui` ne dépend pas de `data-access` et `domain` reste indépendant du framework.
Frontend et backend peuvent partager le domaine sans partager un modèle identique
Un Bounded Context est une frontière de modèle et de langage, il ne devrait donc pas être tracé automatiquement sur la frontière réseau entre navigateur et serveur. Des guides pratiques du DDD frontend soulignent que les contextes peuvent traverser les couches techniques et être réalisés conjointement côté frontend et backend. [15][16]
La représentation cliente peut néanmoins différer de la représentation serveur, car interaction, état local et présentation ont d'autres besoins. L'essentiel est de préserver la sémantique et de mapper explicitement plutôt que de copier les classes.
Un micro-frontend ne doit pas non plus être créé simplement parce qu'un Bounded Context existe. Frontière métier et frontière de déploiement sont deux décisions différentes.
La testabilité est un argument fort pour isoler la logique de domaine
Fowler cite la testabilité comme bénéfice de la séparation entre présentation et domaine. Une logique hors UI peut être testée sans rendu de composants ni dépendance aux détails de l'interface. [5][6]
Dans le frontend, cela permet des tests rapides des règles, Value Objects, cas d'utilisation et transitions d'état en TypeScript ou JavaScript ordinaire. Les tests de composants restent utiles, mais ne doivent pas être le seul endroit où vérifier les règles métier.
Un signal d'alerte apparaît lorsque chaque changement de règle exige de monter un composant complet et de mocker routeur, store, HTTP et APIs navigateur.
Introduire DDD dans un frontend existant sans grand rewrite
DDD Crew recommande une démarche itérative : comprendre le domaine, identifier les sous-domaines importants, définir les responsabilités des Bounded Contexts, puis coder le modèle. [10]
Dans un frontend existant, il est plus sûr de choisir une zone métier douloureuse, nommer son langage, fixer une frontière, séparer présentation et règles, définir l'API publique du module puis migrer progressivement d'autres fonctionnalités.
Toute l'application n'a pas besoin d'être migrée. DDD peut être utilisé là où la complexité métier rembourse le coût de modélisation, tandis que les zones simples restent des modules fonctionnels légers.
- Commencer par un problème métier, pas par les dossiers.
- Identifier termes, règles et concepts ambigus.
- Définir un Bounded Context et son contrat public.
- Séparer règles métier, composants et DTO de transport.
- Ajouter uniquement les patterns tactiques qui résolvent une complexité réelle.
- Transformer les frontières en règles de lint ou CI.
- Mesurer dépendances, cycles, régressions et coût des changements transversaux.
- Ne pas migrer les zones CRUD simples uniquement pour la symétrie architecturale.

