Anti-Corruption Layer Explained: Protecting Your Domain from External System Complexity

How the Anti-Corruption Layer pattern works — translating between bounded contexts, isolating legacy systems, and keeping your domain model clean.

anti-corruption-layerdomain-driven-designsoftware-architecturebounded-contextintegration-patterns

Anti-Corruption Layer

An Anti-Corruption Layer (ACL) is a translation boundary between two systems or bounded contexts that prevents the model and semantics of one system from leaking into and corrupting the domain model of another.

What It Really Means

When your system integrates with an external service — a legacy ERP, a third-party API, or another team's microservice — you face a choice. You can model your domain around the external system's data structures, field names, and concepts. Or you can maintain your own domain model and translate at the boundary.

The first approach is faster initially but creates long-term coupling. If the external system renames a field, changes a status code, or restructures its API, your domain logic breaks. Your codebase fills with comments like "// 'ACTV' means active in the legacy system" and mapping logic scattered across services.

The Anti-Corruption Layer is the second approach, formalized. It is a dedicated translation layer that sits between your system and the external system. It converts the external system's concepts, data formats, and semantics into your domain's language. Your domain code never sees the external system's model. When the external system changes, only the ACL changes.

Eric Evans introduced this pattern in Domain-Driven Design (2003) specifically for protecting a well-designed domain model from the corrupting influence of integrating with systems that use different models, terminology, or conventions.

How It Works in Practice

Without an ACL

python

With an ACL

python

Typical ACL Structure

Implementation

Full ACL for a legacy inventory system:

python

ACL as a separate service (for complex integrations):

Trade-offs

Benefits:

  • Your domain model stays clean — no leaked external concepts
  • External system changes only affect the ACL, not your business logic
  • Testability: mock the ACL to test domain logic without external dependencies
  • Multiple external systems can be swapped behind the same ACL interface
  • Documents the mapping between systems explicitly

Costs:

  • Additional layer of code to write and maintain
  • Translation overhead (usually negligible for I/O-bound operations)
  • Risk of the ACL itself becoming complex and poorly maintained
  • Data loss during translation if the mapping is incomplete

When to use an ACL:

  • Integrating with legacy systems that have cryptic data models
  • Consuming third-party APIs whose models differ significantly from your domain
  • Bounded context boundaries in microservices where domain models diverge
  • During migrations: the ACL wraps the old system while you build the new one

When an ACL is overkill:

  • The external system's model closely matches your domain model
  • You are the only consumer and the external system is stable
  • Simple integrations with well-designed, well-documented APIs
  • Prototypes where long-term maintenance is not a concern

Common Misconceptions

  • "An ACL is just a wrapper class" — A wrapper exposes the same interface with minor changes. An ACL translates between fundamentally different domain models, vocabularies, and concepts. It transforms meaning, not just syntax.
  • "You only need ACLs for legacy systems" — Any external system with a different domain model benefits from an ACL: third-party APIs, partner systems, even other microservices within your organization that model the same concepts differently.
  • "The ACL should translate everything" — Only translate what your domain needs. If the external system returns 50 fields and your domain uses 5, the ACL maps only those 5. The rest are noise.
  • "ACLs add latency" — The translation itself is in-memory object mapping (microseconds). The external API call (milliseconds) dominates. The ACL adds negligible overhead.
  • "Once you add an ACL, you never talk to the external system directly" — The ACL is the only point of contact. If any code bypasses the ACL, the corruption it prevents will leak through the bypass.

How This Appears in Interviews

  1. "You need to integrate with a legacy billing system that uses XML and cryptic codes. How do you approach it?" — ACL: build a translation layer that converts legacy XML responses to your domain objects. Your business logic never sees XML or legacy codes.
  2. "How do you prevent a third-party API change from breaking your service?" — ACL: isolate the third-party API behind a translation layer. When the API changes, only the ACL needs updating.
  3. "Two microservices use different models for 'Customer.' How do they communicate?" — Each service has its own bounded context. The consuming service uses an ACL to translate the other service's Customer model into its own.
  4. "What is the relationship between ACL and hexagonal architecture?" — In hexagonal architecture, ACLs are adapters. They implement a port (interface) defined by the domain and translate between the domain and the external system.

Related Concepts

GO DEEPER

Learn from senior engineers in our 12-week cohort

Our Advanced System Design cohort covers this and 11 other deep-dive topics with live sessions, assignments, and expert feedback.