Bounded Context

Comprendre comment découper un système en contextes cohérents quand un même terme ou une même règle métier n’a pas le même sens partout.

Le problème

Beaucoup de systèmes deviennent confus non pas parce qu’ils manquent de code, mais parce qu’ils mélangent plusieurs modèles métier dans le même espace.

On retrouve souvent les mêmes symptômes :

  • un même mot veut dire plusieurs choses selon l’équipe
  • une entité grossit jusqu’à représenter plusieurs réalités différentes
  • des règles métier se contredisent selon le cas
  • des champs s’ajoutent juste pour “couvrir aussi” un autre usage
  • les intégrations entre modules finissent en bricolage de mapping implicite

Exemple classique : Customer.

Selon le contexte, Customer peut vouloir dire :

  • un prospect dans le CRM
  • un acheteur dans la facturation
  • un titulaire de contrat dans un système de souscription
  • un compte support dans un helpdesk

Le mot est le même. Le modèle ne l’est pas.

Quand on force tout dans une seule définition, on finit avec un modèle flou, instable et difficile à maintenir.

Le bounded context sert à éviter ça.

L’idée simple

Un bounded context est une frontière dans laquelle un modèle garde un sens précis.

À l’intérieur d’un contexte :

  • les mots ont une définition claire
  • les règles métier sont cohérentes
  • les objets du modèle appartiennent à la même logique

À l’extérieur, ces mêmes mots peuvent exister avec un autre sens.

Le point important est simple :

on n’essaie pas d’imposer un modèle unique à tout le système.

On accepte qu’un système réel contienne plusieurs modèles, chacun valide dans sa propre frontière.

Comment ça fonctionne

Le bounded context est d’abord un outil de découpage du système.

1. Un mot n’a pas forcément le même sens partout

Dans un projet réel, les équipes utilisent souvent les mêmes mots pour parler de choses différentes.

Exemple avec Order :

  • dans le checkout, une commande en cours de création
  • dans la logistique, un colis à préparer
  • dans la facturation, un document lié à un paiement
  • dans le support, un historique consultable

Forcer un seul modèle Order pour tout le monde produit souvent :

  • trop de champs
  • trop de statuts
  • trop de branches conditionnelles
  • trop de couplage entre équipes

Le bounded context dit : chaque partie garde le modèle dont elle a besoin.

2. La frontière protège le sens

Un contexte n’est pas juste un dossier. C’est une frontière explicite :

  • du vocabulaire
  • des règles
  • des objets
  • des cas d’usage

À l’intérieur d’un contexte, on cherche la cohérence. Entre contextes, on accepte la traduction.

C’est ce qui évite qu’un modèle externe vienne déformer un modèle local.

3. Les relations entre contextes doivent être explicites

Deux contextes peuvent collaborer. Mais ils ne doivent pas fusionner par accident.

Quand un contexte a besoin d’informations d’un autre, il faut rendre l’échange visible :

  • API
  • événements
  • mapping
  • couche de traduction
  • contrat d’intégration

Le pire scénario est le plus courant : un contexte commence à importer directement les structures internes d’un autre.

À partir de là, la frontière est déjà cassée.

Schéma

Bounded Contexts et intégration

Lecture utile :

  • chaque contexte a son propre modèle
  • les échanges passent par des frontières explicites
  • on évite le partage direct de structures internes

Exemple concret

Prenons une plateforme SaaS.

Au début, tout semble simple : on crée une entité Customer.

Puis le système grandit.

Dans le contexte Sales

Le sujet principal est la conversion commerciale.

Customer signifie plutôt :

  • une entreprise en discussion
  • une étape de pipeline
  • une source d’acquisition
  • un owner commercial
  • une probabilité de conversion

Ici, les statuts utiles ressemblent à :

  • lead
  • qualified
  • proposal_sent
  • won
  • lost

Dans le contexte Billing

Le sujet principal est la facturation.

Customer signifie plutôt :

  • un compte facturable
  • un identifiant de facturation
  • un pays fiscal
  • une devise
  • un statut de paiement

Ici, les préoccupations utiles sont :

  • moyen de paiement
  • facture en retard
  • TVA
  • suspension du compte

Dans le contexte Support

Le sujet principal est l’assistance.

Customer signifie plutôt :

  • une organisation cliente
  • un plan de support
  • un niveau de priorité
  • un historique d’incidents
  • des contacts autorisés

Ici, les préoccupations utiles sont :

  • SLA
  • niveau d’escalade
  • incidents ouverts
  • dernier contact

Le mauvais design

Vouloir tout mettre dans une seule entité :

export type Customer = {
  id: string;
  salesOwnerId?: string;
  leadSource?: string;
  pipelineStage?: string;
  billingEmail?: string;
  vatNumber?: string;
  paymentStatus?: string;
  supportPlan?: string;
  escalationLevel?: string;
  lastIncidentAt?: Date;
};

Ce type est un signal d’alarme :

  • trop de champs optionnels
  • plusieurs responsabilités
  • aucun sens métier stable

Le bon design

Chaque contexte porte son propre modèle.

Sales

export type SalesCustomer = {
  id: string;
  companyName: string;
  pipelineStage: "lead" | "qualified" | "proposal_sent" | "won" | "lost";
  salesOwnerId: string;
};

Billing

export type BillingCustomerAccount = {
  id: string;
  legalName: string;
  billingEmail: string;
  vatNumber?: string;
  paymentStatus: "ok" | "late" | "suspended";
  currency: string;
};

Support

export type SupportCustomer = {
  id: string;
  organizationName: string;
  supportPlan: "standard" | "premium";
  escalationLevel: 1 | 2 | 3;
};

Chaque modèle devient plus simple parce qu’il parle d’un seul problème.

Comment reconnaître un bounded context

En pratique, il y a plusieurs signaux utiles.

Le vocabulaire diverge

Si deux équipes utilisent le même mot avec des sens différents, il y a souvent plusieurs contextes.

Les règles changent selon la zone du système

Si la même entité doit respecter des règles très différentes selon l’usage, le modèle est probablement trop large.

Les champs deviennent artificiels

Quand on multiplie les champs optionnels, les sous-types implicites et les statuts fusionnés, on masque souvent plusieurs contextes sous un seul nom.

Les échanges demandent déjà de la traduction

Si une équipe transforme systématiquement les données d’une autre avant de les utiliser, c’est souvent qu’elle travaille déjà dans un autre contexte.

Exemple d’intégration saine

Un contexte Sales peut notifier Billing qu’un contrat est gagné.

Événement émis par Sales

export type CustomerContractWon = {
  customerId: string;
  companyName: string;
  billingEmail: string;
  planCode: string;
};

Traitement côté Billing

export class CreateBillingAccountFromWonContract {
  async handle(event: CustomerContractWon): Promise<void> {
    // Traduction vers le modèle Billing
  }
}

Le point important :

  • Billing ne réutilise pas le modèle interne de Sales
  • Billing traduit l’événement dans son propre langage
  • la frontière reste claire

Points importants

  • Un bounded context protège le sens d’un modèle.
  • Il évite de forcer un vocabulaire unique sur tout le système.
  • Le même mot peut exister dans plusieurs contextes avec des sens différents.
  • Le but n’est pas de séparer pour séparer.
  • Le but est d’éviter un modèle global flou et contradictoire.
  • Les échanges entre contextes doivent être explicites.

Erreurs fréquentes

Chercher un modèle unique pour tout le système

C’est l’erreur la plus classique.

Un modèle global paraît propre au début, puis devient un point de couplage massif.

Confondre bounded context et microservice

Un bounded context est une frontière de modèle, pas forcément un service déployé séparément.

On peut avoir plusieurs contextes dans un monolithe. On peut aussi avoir un microservice qui contient un mauvais mélange de contextes.

Découper par équipe ou par table

Le bounded context ne se décide ni par organigramme ni par schéma SQL.

La vraie question est : où le modèle garde-t-il un sens cohérent ?

Partager directement les objets internes

Si un contexte importe les classes, DTO ou entités internes d’un autre, la frontière devient théorique.

Les échanges doivent passer par des contrats explicites.

Utiliser le mot sans clarifier le vocabulaire

Nommer un dossier bounded-context n’aide pas si personne ne sait :

  • quels mots appartiennent à ce contexte
  • quelles règles y vivent
  • ce qui entre et ce qui sort

Conclusion

Le bounded context sert à découper un système quand un seul modèle ne suffit plus.

Il permet de garder des mots clairs, des règles cohérentes et des frontières lisibles.

Le réflexe le plus utile est simple :

si un mot change de sens selon la zone du système, il y a probablement plusieurs contextes.