Pattern

Carte Context Mapping #1 : Open-host Service

📇 Carte #1 : Open-host Service

Vue Rapide

🎯 Objectif : Un contexte expose une interface commune à plusieurs clients

👥 Relation d’équipe : Upstream/Downstream (asymétrique)

📊 Couplage : Moyen → Bas (dépend de la stabilité de l’interface)


Concept

L’équipe upstream expose une interface (API, événements, etc.) ouverte et publique que tous les clients downstream peuvent utiliser.

L’interface évolue pour accommoder de nouveaux besoins mais reste cohérente et documentée.

Upstream (Open-host Service)
        ↓ (API publique stable)
    Downstream 1
    Downstream 2
    Downstream 3 (clients multiples)

Quand l’Utiliser ? ✅

  • Plusieurs clients downstream avec des besoins similaires
  • ✅ L’upstream peut réussir indépendamment des clients
  • ✅ Vous avez une équipe dédiée pour maintenir l’interface
  • ✅ Les besoins des clients sont génériques et prévisibles
  • ✅ Vous voulez une approche scalable (ajouter de nouveaux clients facilement)

Exemples

  • Stripe API : Interface publique pour les paiements
  • Système de catalogue : Expose une API de consultation
  • Service d’authentification : Interface standardisée pour login

Quand l’Éviter ? ❌

  • ❌ Besoin très spécifique d’un seul client
  • ❌ L’interface change constamment (domaine trop exploratoire)
  • ❌ Les besoins des clients sont radicalement différents
  • ❌ Pas de ressource pour maintenir l’interface

Questions Clés à se Poser 💭

  1. Y a-t-il plusieurs clients qui consomment ce service ?
  2. L’interface peut-elle être stable et générique ?
  3. L’upstream peut-il investir dans la maintenance de l’interface ?
  4. Les clients acceptent-ils de se conformer à l’interface publique ?
  5. Comment versionnez-vous l’API pour ne pas casser les clients ?

Implications pour l’Équipe Upstream

Responsabilités

  • ✓ Concevoir une interface générique et réutilisable
  • Documenter l’interface publique clairement
  • Maintenir la compatibilité (versioning, backward compatibility)
  • Supporter les clients : comprendre leurs besoins
  • Évoluer l’interface pour accueillir de nouveaux cas

Avantages

  • Scale facilement : ajouter de nouveaux clients sans recoder
  • Faible coupling : les clients n’impactent pas la logique upstream
  • Autonomie des clients : ils peuvent évoluer indépendamment

Risques

  • ⚠️ L’interface devient un goulot d’étranglement
  • ⚠️ Les besoins des clients créent une interface trop générique ou trop complexe
  • ⚠️ Maintenance : gérer plusieurs versions de l’API
  • ⚠️ Les clients sont limités à ce que l’interface propose

Implications pour l’Équipe Downstream

Responsabilités

  • Utiliser l’interface telle qu’elle est (pas de négociation)
  • Adapter votre domaine à l’interface upstream
  • Respecter les contrats (versioning, breaking changes)

Avantages

  • Simple d’intégration : pas de traduction complexe
  • Fiabilité : interface bien documentée et stable
  • Pas de dépendance forte : vous pouvez changer sans affecter l’upstream

Risques

  • ⚠️ L’interface ne vous convient pas parfaitement
  • ⚠️ Adapter votre logique à l’interface plutôt que l’inverse
  • ⚠️ Si l’API change, vous devez vous adapter rapidement

Exemple Concret : Système de Paiement

Contexte Upstream : Payment Service

Interface publique (API REST) :
- POST /payments → créer un paiement
- GET /payments/{id} → récupérer le statut
- POST /refunds → effectuer un remboursement
- Events : PaymentCreated, PaymentSucceeded, PaymentFailed

Contextes Downstream

  • Order Service : Utilise l’API de paiement
  • Subscription Service : Utilise l’API de paiement
  • Invoicing Service : Reçoit les événements PaymentSucceeded

Décisions

  • Une seule interface pour tous les cas
  • Versionning : /v1/payments, /v2/payments si breaking change
  • Documentation : Swagger/OpenAPI pour chaque version

Intégration avec Context Mapping

Relations d’Équipe

Payment Team (Upstream - Open-host Service)
        ↓ (API publique)
    Order Team (Downstream - Conformist)
    Subscription Team (Downstream - Conformist)
    Invoicing Team (Downstream - Conformist)

Patterns Downstream Associés

  • Conformist : Les clients adoptent l’interface telle qu’elle
  • Anticorruption Layer : Un client crée une couche de traduction (optionnel)

Checklist de Mise en Place ✓

  • Vous avez identifié plusieurs clients potentiels
  • L’interface est générique et peut servir plusieurs cas
  • Vous avez une équipe dédiée pour la maintenir
  • L’interface est documentée (Swagger, wiki, etc.)
  • Vous avez une stratégie de versioning claire
  • Les clients savent à quoi s’attendre

Ressources et Lectures


Notes de Facilitation pour l’Atelier

Animation

  • Demandez : “Combien de clients potentiels avez-vous ?”
  • Explorez : “L’interface peut-elle rester stable ?”
  • Validez : “Quelqu’un d’autre que vous peut-il la comprendre et l’utiliser ?”

Pièges Communs

  • ⚠️ Penser que tout est OpenAPI → certains domaines n’y sont pas adaptés
  • ⚠️ Négliger la maintenance → les interfaces dégénèrent
  • ⚠️ Trop générique → personne ne la comprend

Questions Provocatrices

  • “Et si vous aviez 10 clients ? 100 clients ?”
  • “Comment réagiriez-vous si un client dit ‘Votre API ne me convient pas’ ?”

Carte Context Mapping #2 : Anticorruption Layer

📇 Carte #2 : Anticorruption Layer (ACL)

Vue Rapide

🎯 Objectif : L’équipe downstream crée une couche d’isolation pour protéger son modèle

👥 Relation d’équipe : Upstream/Downstream (asymétrique)

📊 Couplage : Bas (isolation complète)


Concept

L’équipe downstream crée une couche de traduction (ACL) qui :

  • Traduit le modèle upstream en modèle downstream
  • Isole le domaine downstream des changements upstream
  • Protège l’indépendance du downstream
Upstream (modèle compliqué/différent)
        ↓
Anticorruption Layer (translation)
        ↓
Downstream (modèle propre et indépendant)

Quand l’Utiliser ? ✅

  • ✅ Les modèles upstream et downstream sont radicalement différents
  • ✅ Vous voulez protéger votre domaine des pollutions upstream
  • ✅ L’upstream change fréquemment ou est mal conçu
  • ✅ Vous avez besoin d’indépendance maximale
  • ✅ L’interface upstream est imposée et immuable

Exemples

  • Legacy System Integration : Intégrer un vieux système avec ACL
  • Third-party API : Adapter une API externe à votre domaine
  • Big Ball Of Mud : Isoler votre domaine du chaos upstream

Quand l’Éviter ? ❌

  • ❌ L’interface upstream est simple et stable
  • ❌ Vous pouvez vous permettre d’adopter le modèle upstream (Conformist)
  • ❌ La complexité de traduction est excessive
  • ❌ Vous avez besoin de synchronisation temps-réel très serrée

Questions Clés à se Poser 💭

  1. Le modèle upstream pollue-t-il notre domaine ?
  2. Pouvons-nous nous permettre de créer une couche de traduction ?
  3. La traduction est-elle complexe ou simple ?
  4. Comment maintenons-nous la synchronisation entre les deux modèles ?
  5. Où plaçons-nous l’ACL : au niveau de l’équipe ou du service ?

Implications pour l’Équipe Downstream

Responsabilités

  • Concevoir l’ACL : mapper upstream → downstream
  • Maintenir l’ACL : gérer les évolutions upstream
  • Documenter les mappings : pourquoi cette traduction ?
  • Tester l’ACL : validation des conversions

Avantages

  • Indépendance totale : votre domaine est protégé
  • Flexibilité : vous pouvez changer sans affecter l’upstream
  • Clarté : votre code est clair, la traduction est centralisée
  • Évolutivité : remplacer upstream ne casse pas votre logique

Risques

  • ⚠️ Complexité : maintenir une couche de traduction
  • ⚠️ Performance : la traduction peut avoir un coût
  • ⚠️ Synchronisation : gérer les changements upstream
  • ⚠️ Duplication : code de mapping qui peut devenir lourd

Patterns de Traduction Courants

1. Mapping Simple

Upstream: Order { items: [], total: 0 }
       ↓
ACL: convertOrderToOurModel()
       ↓
Downstream: PurchaseOrder { lineItems: [], grossAmount: 0 }

2. Enrichissement

Upstream: minimal data
       ↓
ACL: enrichir avec contexte (user, country, etc.)
       ↓
Downstream: complete domain object

3. Agrégation

Upstream 1: User data
Upstream 2: Address data
       ↓
ACL: combiner les sources
       ↓
Downstream: Customer aggregate

4. Transformation

Upstream: Legacy format
       ↓
ACL: parser, validator, transformer
       ↓
Downstream: Modern format

Exemple Concret : Integration d’un Legacy System

Contexte Downstream : Nouvelle Commande Service

Votre domaine clair et moderne :

Carte Context Mapping #3 : Conformist

📇 Carte #3 : Conformist

Vue Rapide

🎯 Objectif : L’équipe downstream adopte le modèle upstream sans traduction

👥 Relation d’équipe : Upstream/Downstream (asymétrique)

📊 Couplage : Haut (adhérence au modèle upstream)


Concept

L’équipe downstream accepte simplement le modèle et les conventions de l’équipe upstream.

Upstream (modèle de référence)
    ↓ (pas de traduction)
Downstream (adopte le même modèle)

La philosophie : “Ce que vous donnez, nous l’utilisons tel quel”


Quand l’Utiliser ? ✅

  • ✅ Le modèle upstream est suffisamment bon pour votre besoin
  • ✅ Créer une ACL serait trop complexe ou non rentable
  • ✅ L’upstream est stable et bien conçu
  • ✅ Vous avez une dépendance forte et c’est acceptable
  • ✅ L’équipe upstream a du poids politique ou est essentielle

Exemples

  • API publique stable : Adopter directement une API bien conçue
  • Plateforme core : Tous les services acceptent le modèle core
  • Standard industrie : Utiliser un standard reconnu (ISO, RFC, etc.)

Quand l’Éviter ? ❌

  • ❌ Le modèle upstream est incompatible avec votre domaine
  • ❌ L’upstream change fréquemment sans coordination
  • ❌ Vous avez besoin de dépendances croisées (Partner pattern est meilleur)
  • ❌ C’est une dépendance temporaire (better: Anticorruption Layer)
  • ❌ Le modèle upstream est mal conçu (Big Ball Of Mud)

Questions Clés à se Poser 💭

  1. Est-ce que le modèle upstream nous convient vraiment ?
  2. Allons-nous devoir le modifier plus tard ?
  3. Quels sont les risques de cette adhérence ?
  4. Comment restons-nous informés des changements ?
  5. Qui décide des évolutions du modèle shared ?

Implications pour l’Équipe Downstream

Responsabilités

  • Accepter le modèle tel qu’il est
  • ✓ Communiquer rapidement si le modèle pose problème
  • Collaborer avec upstream pour améliorations
  • Supporter les changements d’upstream

Avantages

  • Simple : pas de couche de traduction
  • Rapide à intégrer : implémentation directe
  • Couplage intentionnel : c’est du domaine partagé
  • Moins de bugs : une seule source de vérité

Risques

  • ⚠️ Pollina votre modèle : compromis sur votre pureté
  • ⚠️ Couplage fort : difficile à défaire
  • ⚠️ Bloqué par upstream : changements lents
  • ⚠️ Conflit de visions : deux domaines, une structure

Implications pour l’Équipe Upstream

Responsabilités

  • Maintenir une API stable : les downstream dépendent de vous
  • Communicer les changements : informer rapidement
  • Respecter la compatibilité : ou avoir un processus de migration
  • Écouter les besoins downstream

Avantages

  • Influence : votre modèle devient référence
  • Couplage maîtrisé : par design

Risques

  • ⚠️ Responsabilité : you break it, you own all the consequences
  • ⚠️ Évolution lente : devoir négocier avec tous les conformists

Exemples de Conformist Patterns

1. Shared Business Model

Upstream Team (Orders Domain)
    ├── Order { id, customerId, items, status }
    ├── OrderItem { productId, quantity, price }
    └── Status enum

Downstream Team (Invoicing)
    └── Adopte exactement le même modèle
        ├── Invoice utilise Order directement
        ├── InvoiceItem utilise OrderItem
        └── Respecte Status enum

2. API Publique Standard

Upstream: REST API (JSON well-known)
    {
      "id": "...",
      "name": "...",
      "type": "...",
      "metadata": { ... }
    }

Downstream Services:
    └── Tous utilisent exactement cette structure
        Pas de traduction

3. Industrie Standard (XML/JSON Schema)

Standard: UBL Invoice
    Upstream (supplier): génère UBL
    Downstream (customer): consomme UBL
    → Pas de traduction

Exemple Concret : Plateforme E-commerce

Contexte

Vous avez une équipe Product Core qui gère l’essai central.

Carte Context Mapping #4 : Shared Kernel

📇 Carte #4 : Shared Kernel

Vue Rapide

🎯 Objectif : Deux équipes partagent du code et un modèle commun

👥 Relation d’équipe : Mutuellement Dépendant

📊 Couplage : Très haut (code partagé)


Concept

Deux contextes partagent du code source et un modèle de domaine commun.

Shared Kernel (Code + Model)
    ↙         ↘
Team A      Team B

Le noyau partagé n’appartient à aucun contexte, il est gardé par les deux.


Quand l’Utiliser ? ✅

  • ✅ Deux équipes très dépendantes l’une de l’autre
  • ✅ Créer une interface prendrait plus de temps qu’un code partagé
  • ✅ Les équipes veulent vraiment collaborer
  • ✅ Le code partagé est stable et bien défini
  • ✅ C’est une zone de frontière claire (pas du fouilli)

Exemples

  • Domain Entities partagées : Customer, Product (tous les services en ont besoin)
  • Value Objects : Money, EmailAddress (immuables, réutilisables)
  • Shared Policies : Règles métier communes
  • Shared Algorithms : Calculs complexes partagés

Quand l’Éviter ? ❌

  • ❌ Les équipes ne se font pas confiance
  • ❌ Le code partagé change fréquemment
  • ❌ Vous pouvez le dupliquer (plus simple)
  • ❌ Le code partagé n’est pas vraiment partagé (distinct par contexte)
  • ❌ Les équipes sont géographiquement éloignées (communication difficile)

Questions Clés à se Poser 💭

  1. Qu’est-ce qui est vraiment partagé ? (vs. similaire)
  2. Comment gérons-nous les changements du noyau ?
  3. Qui est responsable de maintenir le Shared Kernel ?
  4. Qu’arrive-t-il si les équipes divergent dans leurs besoins ?
  5. Comment versionnons-nous ce code partagé ?

Implications pour les Deux Équipes

Responsabilités Communes

  • Maintenir ensemble le Shared Kernel
  • Tester à fond : les changements affectent tous les contextes
  • Documenter clairement : quoi et pourquoi c’est partagé
  • Communiquer avant changement

Avantages

  • Efficacité : pas de duplication ou traduction
  • Cohérence : une seule source de vérité
  • Collaboration : force les équipes à travailler ensemble
  • Évolution facile : tout le monde évolue en même temps

Risques

  • ⚠️ Couplage très fort : changement = impacte les 2 contextes
  • ⚠️ Synchronisation lente : besoin de coordination
  • ⚠️ Conflits : si les besoins divergent
  • ⚠️ Cycles de dépendance : chaque équipe attend l’autre

Structure du Shared Kernel

Option 1 : Bibliothèque Partagée

shared-kernel/ (repository/package dédié)
├── domain-entities/
│   ├── Customer.ts
│   └── Product.ts
├── value-objects/
│   ├── Money.ts
│   └── EmailAddress.ts
└── policies/
    └── PricingPolicy.ts

Team A → imports shared-kernel
Team B → imports shared-kernel

Option 2 : Code Partagé dans Sous-Dossier

monorepo/
├── services/team-a/
│   ├── src/
│   └── shared/ (lien vers shared-kernel)
├── services/team-b/
│   ├── src/
│   └── shared/ (lien vers shared-kernel)
└── shared-kernel/
    ├── entities/
    ├── value-objects/
    └── policies/

Exemple Concret : E-commerce Shared Entities

Contexte

Deux équipes : Catalog et Inventory

Carte Context Mapping #5 : Partnership

📇 Carte #5 : Partnership

Vue Rapide

🎯 Objectif : Deux équipes avec besoin mutuel s’engagent à se coordonner

👥 Relation d’équipe : Mutuellement Dépendant

📊 Couplage : Élevé (interfaces négociées)


Concept

Deux contextes aussi importants l’un que l’autre s’engagent à :

  • Collaborer sur les interfaces
  • Se consulter avant changements majeurs
  • Synchroniser leurs efforts
Team A (contexte équivalent)
    ↔ Partnership ↔
Team B (contexte équivalent)

La philosophie : “Nous avons besoin l’un de l’autre, donc on se coordonne”

Carte Context Mapping #6 : Separate Ways

📇 Carte #6 : Separate Ways

Vue Rapide

🎯 Objectif : Deux contextes se séparent complètement et se dupliquent

👥 Relation d’équipe : Indépendant

📊 Couplage : Nul (zero integration)


Concept

Les deux contextes abandonnent l’intégration et chacun gère sa propre version.

Team A        Team B
(duplique)    (duplique)
     ↓ ↓ ↓ ↓ ↓ ↓
  Chemin séparé

La philosophie : “On se sépare, c’est plus simple”


Quand l’Utiliser ? ✅

  • ✅ Le coût de l’intégration dépasse les bénéfices
  • ✅ Les contextes évoluent différemment et indépendamment
  • ✅ La duplication est acceptable (pas critique)
  • ✅ Les équipes veulent une autonomie totale
  • ✅ Les données peuvent être synchronisées via batch (pas temps-réel)

Exemples

  • Legacy System vs. Nouveau Système : on les laisse cohabiter sans parler
  • Rapport de gestion vs. Système de facturation : même données, deux lectures
  • Analytics vs. Production : duplication OK, latence acceptable
  • Deux variantes régionales : chacun son instance

Quand l’Éviter ? ❌

  • ❌ L’intégration est vraiment nécessaire
  • ❌ Les données doivent être synchronisées en temps-réel
  • ❌ La duplication coûte trop cher (complexité, maintenance)
  • ❌ Vous devez garder les données cohérentes
  • ❌ C’est une fuite d’architecture (vraiment du même domaine)

Questions Clés à se Poser 💭

  1. Pouvez-vous vraiment vous permettre de dupliquer ?
  2. Quel est le coût de maintenir 2 versions ?
  3. Comment gérez-vous la divergence entre les deux ?
  4. Qu’arrive-t-il quand un changement métier affecte les deux ?
  5. Comment synchronisez-vous les données critiques ?

Implications pour les Équipes

Chaque Équipe Indépendante

Avantages

  • Autonomie totale : chacun progresse à son rythme
  • Zéro couplage : changements sans impact mutuel
  • Simplicité : pas d’interface complexe
  • Pas de réunions de coordination !

Risques

  • ⚠️ Duplication : maintenance coûteuse
  • ⚠️ Divergence : à long terme, les deux dérivent
  • ⚠️ Incohérence : les données ne correspondent plus
  • ⚠️ Coût caché : bug fixes doivent se répéter

Stratégies de Séparation

1. Complète (Clean Break)

Before: Service A ↔ Service B (intégration)
After:  Service A    Service B (indépendant)

→ Chacun a sa DB, son code, ses workflows
→ Zéro partage

2. Partielle (avec Batch Sync)

Service A (Commandes)
    ↓ (batch export chaque nuit)
Data Lake
    ↓ (batch import chaque nuit)
Service B (Analytics)

→ Services indépendants mais données synchronisées
→ Acceptable delay: 24h

3. Avec Archive

Legacy System (ancien)
    ↓ (migration progressive)
New System (nouveau)

→ Legacy continue de tourner
→ New prend du trafic progressivement
→ Un jour legacy s'éteint

Exemple Concret : Migration Vers Nouveau Système

Avant (Separate Ways Forcés - mauvais)

Legacy Order System (10 ans)
    ↓ (désuet, lent)
Couplé fortement à: 
    - Inventory System
    - Billing System
    - Reporting System

→ Impossible à modifier sans casser tout
→ Vraiment besoin de découpler!

Stratégie de Séparation

Phase 1: Créer New Order System (indépendant)
├── Copier la data du legacy
└── Tester en parallèle

Phase 2: Dual-write (transition)
├── Writes vont aux deux systèmes
├── New System est primary source of truth progressivement
└── Reports lisent à partir du New

Phase 3: Legacy read-only (legacy devient archive)
├── Legacy continue de tourner en read-only
├── Données historiques toujours accessibles
└── Queries récentes pointent vers New

Phase 4: Sunset legacy (éteindre l'ancien)
├── Archive les données du legacy
├── Décommissionner le système
└── Sauvegardes long-term seulement

Co-existence Pendant Transition

Frontend
    ↓
API Gateway (routing intelligent)
    ├→ New System (80% du trafic)
    └→ Legacy System (20% du trafic, migration progressive)

Batch Job (chaque nuit)
    ├→ Exporte du New
    ├→ Importe dans Analytics
    └→ Archive du Legacy

Données Critiques: Synchronisation Required

Scenario: Commandes et Facturation

Vous avez décidé de découpler Order ↔ Billing

Carte Context Mapping #7 : Published Language

📇 Carte #7 : Published Language

Vue Rapide

🎯 Objectif : Upstream publie un langage standard pour tous les downstream

👥 Relation d’équipe : Upstream/Downstream (nombreux downstream)

📊 Couplage : Bas (via langage public)


Concept

L’équipe upstream publie un langage commun (formats, événements, API) que tous les downstream adopent.

Upstream Service
    ↓
Published Language (JSON Schema, Events, OpenAPI)
    ↓ ↓ ↓ ↓ ↓
Downstream 1, 2, 3, 4, 5... (nombreux)

La philosophie : “Voici notre langage public. Si vous le respectez, ça fonctionne.”

Carte Context Mapping #8 : Customer/Supplier Development

📇 Carte #8 : Customer/Supplier Development

Vue Rapide

🎯 Objectif : Upstream co-concevoir des interfaces avec downstream

👥 Relation d’équipe : Upstream/Downstream (avec engagement)

📊 Couplage : Moyen (interface négociée)


Concept

L’équipe upstream et l’équipe downstream collaborent pour concevoir une interface optimale pour les deux.

Upstream Team          Downstream Team
(Supplier)    ↔       (Customer)
       ↓ Négociation ↓
   Interface optimale

La philosophie : “Je fournisseur, tu es client. Parlons de ce que tu as besoin.”

Carte Context Mapping #9 : Big Ball Of Mud (BBOM)

📇 Carte #9 : Big Ball Of Mud (BBOM)

Vue Rapide

🎯 Objectif : Reconnaître et documenter une zone chaotique sans structure claire

👥 Relation d’équipe : Sans structure (amorphe)

📊 Couplage : Extrêmement haut (tout touche à tout)


Concept

Une partie du système où les limites sont floues, les responsabilités mélangées, et les dépendances partout.

🌀 BBOM 🌀
├─ Code legacy sans structure
├─ Domaines entrelacés
├─ "Je sais pas comment ça marche"
├─ "Peur de toucher"
└─ Tout change partout

La philosophie : “C’est pas un pattern, c’est un symptôme d’absence de pattern”