Free — no signup required

The Anti-Corruption Layer (ACL)

2 min read

The Real World is Messy

In a perfect world, every system you integrate with would use clean, well-designed models that align with your domain. In reality, you integrate with legacy mainframes from the 1980s, third-party payment APIs with bizarre field names, and partner systems that use completely different terminology.

If your clean Bounded Context directly calls a legacy system and maps its response directly into your domain objects, the legacy system's messy model starts leaking into your code. You end up with fields named CUST_ACCT_NO_7 in your otherwise clean domain model. This is called model corruption.

The Translation Layer

An Anti-Corruption Layer (ACL) is a protective barrier you build between your clean Bounded Context and a messy external system. It is a dedicated translation layer that speaks both languages.

Your Domain Model  ←→  ACL  ←→  Legacy System / External API

The ACL has two responsibilities:
1. Outbound: Translate your clean domain requests into whatever format the external system requires.
2. Inbound: Translate the external system's messy response back into your clean domain model.

# The legacy system returns something like this:
legacy_response = {
    "CUST_ACCT_NO_7": "C-00123",
    "CUST_NM_FULL": "Jane Smith",
    "ACCT_BAL_CENTS": 150000,
    "ACCT_STAT_CD": "A"
}

# The ACL translates it into your clean domain model:
class LegacyAccountingSystemACL:
    def get_customer_account(self, customer_id: str) -> CustomerAccount:
        raw = self._legacy_client.fetch(f"CUST_ACCT_NO_7={customer_id}")
        return CustomerAccount(
            id=raw["CUST_ACCT_NO_7"],
            name=raw["CUST_NM_FULL"],
            balance=Money(raw["ACCT_BAL_CENTS"] / 100, "USD"),
            status="ACTIVE" if raw["ACCT_STAT_CD"] == "A" else "INACTIVE"
        )

Your domain code never sees CUST_ACCT_NO_7. It only ever works with CustomerAccount objects that use your Ubiquitous Language. The ACL absorbs all the ugliness.

The ACL is also the right place to handle differences in business concepts. If the legacy system calls something a "Client" but your domain calls it a "Customer," the ACL performs that conceptual translation too — not just field name mapping.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free