Anti-Corruption Layer (ACL)
Pattern architectural qui isole un système des incohérences d'un système externe en traduisant les modèles et protocoles incompatibles.
Mis à jour le 8 janvier 2026
L'Anti-Corruption Layer (ACL) est un pattern stratégique du Domain-Driven Design qui crée une couche de traduction entre votre domaine métier et des systèmes externes legacy ou tiers. Il préserve l'intégrité de votre modèle de domaine en empêchant la contamination par des concepts, structures de données ou logiques inappropriées provenant d'autres systèmes.
Fondements
- Isolation du modèle métier : protège votre bounded context des abstractions inadaptées des systèmes externes
- Traduction bidirectionnelle : convertit les requêtes sortantes et les réponses entrantes selon les besoins de chaque système
- Découplage architectural : permet l'évolution indépendante de votre domaine sans être contraint par les systèmes legacy
- Responsabilité unique : centralise toute la logique d'adaptation dans une couche dédiée et testable
Avantages
- Préservation de la pureté du modèle de domaine sans compromis techniques imposés par des systèmes externes
- Facilitation des migrations progressives en permettant la coexistence de l'ancien et du nouveau système
- Réduction de la dette technique en évitant la propagation de modèles obsolètes dans le nouveau code
- Amélioration de la testabilité en isolant les dépendances externes derrière une interface contrôlée
- Flexibilité accrue pour remplacer ou modifier les systèmes externes sans impact sur le cœur métier
Exemple concret
Imaginons une application e-commerce moderne qui doit intégrer un système ERP legacy utilisant des codes produits numériques, alors que le nouveau domaine utilise des identifiants UUID et une structure de catégorisation différente :
// Modèle du domaine moderne (notre système)
interface Product {
id: string; // UUID
name: string;
category: ProductCategory;
pricing: Money;
}
interface ProductCategory {
slug: string;
hierarchy: string[];
}
// Modèle du système ERP legacy
interface LegacyProductDTO {
product_code: number;
product_name: string;
cat_id: number;
price_cents: number;
currency_code: string;
}
// Anti-Corruption Layer
class ERPProductAdapter {
private categoryMapping: Map<number, ProductCategory>;
constructor(private erpClient: ERPClient) {
this.categoryMapping = this.initializeCategoryMapping();
}
async fetchProduct(productId: string): Promise<Product> {
// Convertir UUID -> code numérique legacy
const legacyCode = this.convertToLegacyCode(productId);
// Appeler le système legacy
const legacyProduct = await this.erpClient.getProduct(legacyCode);
// Traduire vers notre modèle de domaine
return this.toDomainModel(legacyProduct);
}
private toDomainModel(legacy: LegacyProductDTO): Product {
return {
id: this.convertToUUID(legacy.product_code),
name: legacy.product_name,
category: this.categoryMapping.get(legacy.cat_id) ?? this.defaultCategory(),
pricing: {
amount: legacy.price_cents / 100,
currency: legacy.currency_code
}
};
}
async saveProduct(product: Product): Promise<void> {
// Traduire notre modèle vers le format legacy
const legacyDTO = this.toLegacyDTO(product);
await this.erpClient.updateProduct(legacyDTO);
}
private toLegacyDTO(product: Product): LegacyProductDTO {
return {
product_code: this.convertToLegacyCode(product.id),
product_name: product.name,
cat_id: this.findLegacyCategoryId(product.category),
price_cents: Math.round(product.pricing.amount * 100),
currency_code: product.pricing.currency
};
}
}Mise en œuvre
- Identifier les frontières : cartographier les bounded contexts et repérer les systèmes externes qui menacent l'intégrité de votre modèle
- Définir l'interface du domaine : créer les abstractions pures qui reflètent les besoins métier sans considération technique externe
- Créer les adaptateurs : développer les composants de traduction qui convertissent entre votre modèle et celui du système externe
- Implémenter le mapping : établir les règles de transformation des données, identifiants, et concepts métier
- Gérer les incohérences : définir les stratégies pour les cas où la traduction n'est pas parfaite (valeurs par défaut, enrichissement, validation)
- Tester exhaustivement : vérifier la bidirectionnalité des conversions et les cas limites avec des tests unitaires et d'intégration
- Monitorer les traductions : instrumenter l'ACL pour détecter les anomalies et suivre les performances de l'intégration
Conseil d'architecture
L'Anti-Corruption Layer ne doit pas devenir un God Object. Si les traductions deviennent complexes, décomposez l'ACL en plusieurs adaptateurs spécialisés (ProductAdapter, OrderAdapter, etc.) avec des responsabilités clairement définies. Utilisez le pattern Facade pour fournir une interface unifiée si nécessaire.
Outils associés
- AutoMapper / Mapster : bibliothèques de mapping objet-objet pour automatiser les conversions simples
- NestJS Interceptors : mécanisme pour implémenter des ACL de manière déclarative dans les applications NestJS
- GraphQL DataLoader : pattern utile pour optimiser les traductions avec batching et cache
- OpenAPI Generator : génération automatique de clients typés pour les API externes à encapsuler
- Wiremock / MSW : outils de mock pour tester l'ACL sans dépendre des systèmes externes
L'Anti-Corruption Layer représente un investissement stratégique qui protège votre capital logiciel le plus précieux : un modèle de domaine cohérent et expressif. En acceptant la complexité de traduction dans une couche dédiée, vous préservez la simplicité et la maintenabilité de votre cœur métier, facilitant l'évolution à long terme et la migration progressive des systèmes legacy.
