Domaines et cycles de vie - 10 - Features vs Domaine : la bonne decoupe

Comment découper les features autour du cycle de vie. Relation entre feature et domaine DDD, séparation des responsabilités en architecture logicielle.

10 - Features vs Domaine : la bonne decoupe

Ce que tu vas apprendre

  • La relation entre une feature et le domaine
  • Pourquoi une feature se mappe a des transitions, pas a des entités
  • Pourquoi les features ne s'appellent pas entre elles
  • Comment découper les features correctement

Prerequisites


Une feature n'est pas un domaine

Quand on debute, on confond souvent feature et domaine. "La feature d'ajout de Place" semble etre un domaine en soi. Mais non.

Une feature est un point d'entree utilisateur qui déclenché une ou plusieurs transitions dans le cycle de vie. Le domaine, lui, est le socle : le cycle de vie, les états, les invariants, les guards.

Analogie : le domaine est la voie ferree. Les features sont les gares. Les trains (les entités) roulent sur la voie ferree, et les gares permettent d'y acceder. Mais les gares ne definissent pas les rails.

Une feature se mappe a des transitions

Voici comment les features du domaine Place se mappent aux transitions du cycle de vie :

Feature Transitions gerees Rôle
add-place -> DRAFT -> ENRICHED -> READY_FOR_IMAGES Saisie + enrichissement
image-processing READY_FOR_IMAGES -> IMAGES_PROCESSING -> IMAGES_PROCESSED Pipeline images
image-validation IMAGES_PROCESSED -> READY_FOR_PUBLICATION Review humaine
publication READY_FOR_PUBLICATION -> PUBLISHED Mise en ligne

Chaque feature gere un sous-ensemble du cycle de vie. Aucune feature ne gere tout le cycle de vie. Et aucune feature ne "saute" des états.

Representation visuelle

Feature: add-place         Feature: image-processing
|                          |
v                          v
+-------+   +----------+  +-----------------+   +-------------------+
| DRAFT |-->| ENRICHED |->| READY_FOR_IMAGES|-->| IMAGES_PROCESSING |
+-------+   +----------+  +-----------------+   +-------------------+
                                                         |
                           Feature: image-validation     |
                           |                             v
+-----------+   +------------------------+   +------------------+
| PUBLISHED |<--| READY_FOR_PUBLICATION  |<--| IMAGES_PROCESSED |
+-----------+   +------------------------+   +------------------+
      ^
      |
      Feature: publication

Les features ne s'appellent pas entre elles

C'est une regle fondamentale. La feature add-place ne doit jamais appeler directement la feature image-processing. Pourquoi ?

Si les features s'appellent

typescript// Mauvais : couplage direct entre features
async function addPlace(data: PlaceData) {
  const place = await createPlace(data);
  await enrichPlace(place.id);
  // Appel direct a une autre feature
  await imageProcessing.startProcessing(place.id); // couplage !
}

Problèmes :

  • add-place doit connaître image-processing
  • Si image-processing change son API, add-place casse
  • On ne peut pas supprimer image-processing sans modifier add-place
  • Le cycle de vie est cache dans les appels entre features

Le bon modèle

Chaque feature avance l'entité dans le cycle de vie. Le prochain "consommateur" est un worker ou un cron qui reagit a l'état de l'entité :

typescript// Feature: add-place -- elle fait son travail et s'arrete
async function addPlace(data: PlaceData) {
  const place = await createPlace(data); // status = DRAFT
  const enriched = await transition(place, "ENRICH"); // status = ENRICHED
  await transition(enriched, "REQUEST_IMAGES"); // status = READY_FOR_IMAGES
  // Stop. L'entite est dans son etat final pour cette feature.
}

// Worker: image-processing -- il se declenche tout seul
// Ce worker tourne en permanence et traite les Places en READY_FOR_IMAGES
async function imageProcessingWorker() {
  const places = await db.findByStatus("READY_FOR_IMAGES");
  for (const place of places) {
    await transition(place, "PROCESS_IMAGES");
  }
}

Les deux features ne se connaissent pas. Elles sont reliees par le cycle de vie, pas par des appels directs. C'est exactement le type d'architecture qu'on met en place sur paltemps.fr pour decoupler les différentes parties du système.

Le pipeline de domaine est partage

Les transitions, les guards, les invariants -- tout ca est défini dans le domaine, pas dans les features. Les features sont des consommateurs du domaine.

   Domaine (partage)
   |-- transitions.ts     // toutes les transitions
   |-- guards.ts          // tous les guards
   |-- invariants.ts      // tous les invariants
   +-- types.ts           // PlaceStatus, PlaceEntity

   Features (points d'entree)
   |-- add-place/         // utilise transitions DRAFT -> ENRICHED -> READY_FOR_IMAGES
   |-- image-processing/  // utilise transitions READY_FOR_IMAGES -> IMAGES_PROCESSED
   |-- image-validation/  // utilise transition IMAGES_PROCESSED -> READY_FOR_PUBLICATION
   +-- publication/       // utilise transition READY_FOR_PUBLICATION -> PUBLISHED

Le test : supprimer une feature

Un domaine est bien decoupe quand supprimer une feature ne casse pas la définition du domaine.

Si tu supprimes la feature image-validation, le cycle de vie existe toujours. Les états IMAGES_PROCESSED et READY_FOR_PUBLICATION existent toujours. La transition entre eux existe toujours. Il n'y a juste plus personne pour la déclencher.

Si supprimer une feature casse le domaine, c'est que la logique métier est dans la feature au lieu d'etre dans le domaine. C'est un signal d'alarme.

Decouper par rôle, pas par ecran

On est tente de découper les features par ecran ou par page. "L'ecran de création" = une feature. "L'ecran de validation" = une autre. C'est un bon début, mais le vrai critère est le rôle :

  • Qui utilise cette feature ? (un opérateur, un admin, un worker automatise ?)
  • Quelles transitions elle déclenché ?
  • Quel sous-ensemble du cycle de vie elle gere ?

Une feature = un rôle = un sous-ensemble de transitions.


Résumé

  • Une feature est un point d'entree, pas un domaine. Elle se mappe a des transitions du cycle de vie.
  • Les features ne s'appellent pas entre elles. Elles sont reliees par le cycle de vie.
  • Le domaine (transitions, guards, invariants) est partage. Les features le consomment.
  • Supprimer une feature ne doit pas casser la définition du domaine.
  • Decouper par rôle et par transitions, pas par ecran.

Article précédent : 09 - La dette technique Article suivant : 11 - Glossaire complet

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.