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 :

class Order {
  orderId: uuid
  customer: Customer
  items: OrderItem[]
  status: OrderStatus
  createdAt: Timestamp
}

Contexte Upstream : Vieux Système (Big Ball Of Mud)

LEGACY_ORD {
  ORD_ID: string (format bizarre)
  ORD_CUST: string (mélange nom/email)
  ORD_ITEMS: delimited string
  ORD_STAT: numeric code (0=pending, 1=confirmed...)
  ORD_DATE: yyyymmdd
}

Anticorruption Layer

class LegacyOrderTranslator {
  toNewOrder(legacyOrder: LEGACY_ORD): Order {
    return new Order(
      orderId: parseUuid(legacyOrder.ORD_ID),
      customer: parseCustomer(legacyOrder.ORD_CUST),
      items: parseItems(legacyOrder.ORD_ITEMS),
      status: mapLegacyStatus(legacyOrder.ORD_STAT),
      createdAt: parseDate(legacyOrder.ORD_DATE)
    )
  }
}

Emplacement de l’ACL

Option 1 : Dans le Service Downstream

Downstream Service
├── Controllers
├── Domain
├── Application
└── Adapters
    └── LegacyOrderTranslator (ACL)

Option 2 : Service Dédié (Strangler Pattern)

Upstream (Legacy)
    ↓
ACL Service (Adapter)
    ↓
Downstream Service

Intégration avec Context Mapping

Relations d’Équipe

Legacy System Team (Upstream)
        ↓ (interface imposée et sale)
Anticorruption Layer (gérée par notre équipe)
        ↓ (propre et prévisible)
New Service Team (Downstream - indépendant)

Stratégies Connexes

  • Strangler Pattern : Remplacer progressivement le legacy
  • Bubble Context : Isoler pendant la migration

Checklist de Mise en Place ✓

  • Vous avez clairement identifié ce qui doit être traduit
  • La complexité de traduction est acceptable
  • Vous avez une équipe dédiée pour maintenir l’ACL
  • Les mappings sont documentés avec justifications
  • Vous avez des tests pour valider les conversions
  • Vous avez une stratégie pour les changements upstream

Ressources et Lectures


Notes de Facilitation pour l’Atelier

Animation

  • Demandez : “Pourriez-vous vivre avec le modèle upstream directement ?”
  • Explorez : “Qu’est-ce qui vous gêne le plus ?”
  • Proposez : “Et si on créait une couche intermédiaire ?”

Pièges Communs

  • ⚠️ Sous-estimer la complexité du mapping
  • ⚠️ Oublier que l’ACL elle-même devient un domaine à maintenir
  • ⚠️ Performance : la traduction peut devenir lente
  • ⚠️ Duplication de logique entre upstream et downstream

Questions Provocatrices

  • “Et si l’upstream disparaît demain ? Qu’arrive-t-il à votre ACL ?”
  • “Combien de temps consacrez-vous à maintenir cette traduction ?”
  • “Pourriez-vous juste adopter le modèle upstream ?”