Anti-Corruption Layer
The defensive boundary preventing an external system's concepts from polluting the internal business model — a strategic dam in DDD.
Problem
A modern EDI hub integrates with a legacy SAP ERP installed for 25
years. The SAP model uses proprietary codes: BUKRS for company, WERKS for plant, LFART for delivery type, status "E0008"
for "approved but not yet delivered". If the EDI hub lets these
codes invade its internal services, every line of business code
must know SAP codes. An ERP model change becomes a full rewrite.
Worse: the EDIFACT model of the Walmart partner uses other codes,
and the mix produces an incomprehensible hybrid internal model.
Forces
- External models are out of our control. Vendor lock-in (SAP), commercial partner (Walmart), regulation (HL7 FHIR) — their evolution follows their agenda.
- External models have 30 years of debt. Cryptic codes, special values, historical exceptions: letting them leak into the internal model pollutes it.
- Several externals coexist. SAP + Oracle EBS + Salesforce + 50 EDI partners: a single internal model must absorb everything without bearing any external's signature.
- Translation has a cost. Performance (per-message mapping), maintenance (mapping tables), precision (potential losses).
Solution
Build an Anti-Corruption Layer between the internal context and every external system. The ACL combines several classic patterns: a Façade simplifying the external API, an Adapter for the technical signature, a Translator converting business concepts. Everything leaving the ACL toward the internal context speaks the internal ubiquitous language; everything leaving the ACL toward the external speaks the external's language. The ACL is the membrane.
┌────────────────────────────────┐
│ Bounded Context: our hub │
│ domain.Invoice { │
│ invoiceId, debtor, │
│ creditor, lines[] │
│ } │
└────────────────────────────────┘
▲
│ Translator (Façade + Adapter + Translator)
│
┌──────────┴──────────────────────────────────────┐
│ Anti-Corruption Layer │
│ - EDIFACT INVOIC D.96A parser │
│ - UN/EDIFACT codes ↔ internal enum mapping │
│ - input validation vs partner schema │
│ - RFF SBDH ↔ internal field translation │
└─────────────────────┬───────────────────────────┘
│
┌──────────▼──────────┐
│ EDI partner │
│ Raw INVOIC D.96A │
│ + their quirks │
└─────────────────────┘
EDI implementation
Concrete case: an EDI hub receives an EDIFACT INVOIC D.96A from a
Walmart partner. The partner uses UN/EDIFACT codes for "package
unit type" and its own US tax identifier (EIN). The ACL does: (1)
structural EDIFACT parsing; (2) validation against the D.96A
schema and the Walmart Implementation Guide constraints; (3)
mapping UN/EDIFACT codes to internal enumerations; (4) EIN →
internal partner ID lookup; (5) emits an InvoiceReceived event in the internal language. No
downstream service needs to know EDIFACT. If Walmart introduces a
new qualifier in 2027, only the ACL is impacted. Same on SAP side:
an IDoc connector adapts SAP structures into internal models.
Sterling B2B Integrator is typically deployed as ACL in front of
SAP.
Anti-patterns
- Skeleton ACL. A simple literal field-by-field translation: external concepts pass through with another name. The pollution is just renamed.
- Business logic in the ACL. Putting business
rules ("if
creditTerm> 30 then flag") duplicates domain logic, and the ACL becomes a competing mini-domain. - No ACL for a strategic partner. "Walmart is our biggest customer, we align on their model": the day we add a second partner, we discover that the internal model is in fact Walmart's.
- Poorly thought-through bidirectional ACL. ACL for input and for output: both directions can have different rules. Spell out which direction is defended.
Related patterns
- Bounded Context — the ACL sits at the context boundary.
- Message Translator — the EIP brick for message-to-message translation.
- Canonical model — typical target output of a hub-level ACL.
- Adapter — technical sub-pattern of the ACL.
- Normalizer — typical entry door of a multi-format ACL.
Sources
- Evans E. — Domain-Driven Design, Addison-Wesley 2003. Chap. 14 §3 "Anti-corruption Layer".
- Microsoft Architecture Center — Anti-Corruption Layer pattern. learn.microsoft.com — ACL
- Vernon V. — Implementing Domain-Driven Design, Addison-Wesley 2013. Chap. 13 expands the pattern with concrete ERP/CRM mapping examples.
- Strangler Fig + ACL (Fowler). The classic combo to progressively decommission a legacy via a hub-level ACL. martinfowler.com — StranglerFigApplication