Anti-Corruption Layer (ACL)

Cómo proteger tu dominio de la contaminación de sistemas externos, legacy o de terceros mediante una capa de traducción que aísla modelos incompatibles.

Qué problema resuelve

Cuando tu sistema necesita integrarse con un sistema externo (legacy, tercero o de otro equipo), los modelos de datos y conceptos de negocio suelen ser muy diferentes. Sin protección, el modelo del sistema externo contamina tu dominio:

Sin ACL:
  Tu Servicio de Pedidos
  ┌──────────────────────────────────┐
  │ createOrder(legacyCustomerCode,  │
  │   legacyProductSKU,              │  ← Conceptos del sistema legacy
  │   legacyPriceFormat,             │     infiltrados en tu dominio
  │   legacyTaxCalculation)          │
  └──────────────────────────────────┘


  Sistema Legacy ERP (modelo incompatible)

Los problemas concretos son:

  • Contaminación del modelo: Tu dominio adopta nombres, estructuras y reglas del sistema externo
  • Acoplamiento fuerte: Cambios en el sistema externo requieren cambios en tu dominio
  • Complejidad creciente: Tu código mezcla lógica de negocio con lógica de traducción
  • Testing difícil: No puedes testear tu dominio sin simular el sistema externo

Cómo funciona

El Anti-Corruption Layer es una capa de traducción que se sitúa entre tu sistema y el sistema externo. Traduce conceptos, formatos y protocolos en ambas direcciones, manteniendo tu dominio limpio.

Con ACL:
  Tu Servicio de Pedidos
  ┌──────────────────────────────┐
  │ createOrder(customerId,      │
  │   productId,                 │  ← Tu modelo de dominio limpio
  │   price,                     │
  │   tax)                       │
  └──────────┬───────────────────┘

  ┌──────────▼───────────────────┐
  │    Anti-Corruption Layer     │
  │                              │
  │  customerId → legacyCustCode │
  │  productId → legacySKU       │  ← Traducción bidireccional
  │  price → legacyPriceFormat   │
  │  tax → legacyTaxCalc         │
  └──────────┬───────────────────┘


  Sistema Legacy ERP

Componentes del ACL

ComponenteResponsabilidadEjemplo
TranslatorConvierte datos entre modelosLegacyCustomer → Customer
AdapterAdapta la interfaz del sistema externoREST → SOAP, JSON → XML
FacadeSimplifica la API del sistema externo5 llamadas legacy → 1 método limpio
MapperMapea campos y valores entre modelosstatus: "A"status: "active"

Ejemplo de traducción

Tu modelo (dominio limpio):
  Order {
    id: "ORD-001"
    customer: { id: "C-123", name: "María García" }
    items: [{ product: "Laptop", quantity: 1, price: 1500 }]
    status: "confirmed"
  }

Modelo del sistema legacy:
  LEGACY_ORDER {
    ORDER_NUM: "00000001"
    CUST_CODE: "CUST00123"
    CUST_NM: "GARCIA, MARIA"
    LINE_ITEMS: "LAPTOP|1|150000"  (precio en centavos, pipe-separated)
    STAT_CD: "CF"
  }

El ACL traduce entre ambos modelos:
  OrderACLTranslator.toExternal(order) → LEGACY_ORDER
  OrderACLTranslator.fromExternal(legacyOrder) → Order

Ubicación del ACL

El ACL puede implementarse en diferentes niveles:

Como servicio independiente:

Tu Servicio ──► ACL Service ──► Sistema Externo

Como módulo dentro de tu servicio:

Tu Servicio
  ├── Domain Layer (limpio)
  ├── Application Layer
  └── ACL Module ──► Sistema Externo

Como parte del API Gateway:

API Gateway (con ACL) ──► Sistema Legacy

Ventajas

  • Dominio limpio: Tu modelo de negocio no se contamina con conceptos externos
  • Desacoplamiento: Cambios en el sistema externo se absorben en el ACL, no en tu dominio
  • Testing aislado: Puedes testear tu dominio sin el sistema externo (mock del ACL)
  • Migración gradual: Puedes reemplazar el sistema externo sin cambiar tu dominio
  • Claridad: La lógica de traducción está centralizada y es explícita
  • Múltiples integraciones: Puedes tener ACLs diferentes para diferentes sistemas externos

Trade-offs / Desventajas

  • Código adicional: El ACL es código que hay que escribir, testear y mantener
  • Latencia: Una capa más de procesamiento en cada llamada
  • Sincronización de cambios: Cuando el sistema externo cambia su API, el ACL debe actualizarse
  • Complejidad de mapeo: Algunos mapeos son complejos (datos que no tienen equivalente directo)
  • Riesgo de ACL gordo: Si el ACL crece demasiado, puede convertirse en un problema en sí mismo
  • Doble mantenimiento: Cambios en tu modelo o en el externo requieren actualizar el ACL

Cuándo usar

  • Integración con sistemas legacy que tienen modelos de datos incompatibles
  • Consumo de APIs de terceros con modelos diferentes a tu dominio
  • Migración gradual de un monolito a microservicios
  • Cuando múltiples bounded contexts necesitan comunicarse sin contaminar sus modelos
  • Integración con sistemas que usan protocolos o formatos diferentes (SOAP, XML, archivos planos)
  • Cuando el sistema externo cambia frecuentemente y quieres aislar el impacto

Cuándo evitar

  • Integración con sistemas que comparten el mismo modelo de dominio
  • APIs externas simples donde la traducción es trivial (un mapeo de 2-3 campos)
  • Prototipos donde la velocidad de desarrollo es más importante que la pureza del modelo
  • Cuando el sistema externo es temporal y será reemplazado pronto

Tecnologías e implementaciones comunes

CategoríaOpciones
Patrones de diseñoAdapter, Facade, Translator, Mapper
Librerías de mapeoMapStruct (Java), AutoMapper (.NET), class-transformer (TS)
IntegraciónApache Camel, Spring Integration, MuleSoft
API TranslationGraphQL como ACL, API Gateway con transformaciones

Relación con otros patrones

  • DDD (Bounded Context): El ACL protege los límites entre bounded contexts
  • API Gateway: Puede implementar funciones de ACL para sistemas externos
  • BFF: El BFF actúa como un ACL entre el frontend y los microservicios
  • Shared Kernel: Alternativa al ACL cuando dos contextos comparten un modelo común deliberadamente
  • Microservicios: Cada microservicio puede tener su propio ACL para integraciones externas

Próximos pasos

El Anti-Corruption Layer es esencial para mantener la integridad de tu dominio. Para entender cómo manejar fallos en la comunicación con sistemas externos, explora el patrón Retry. Para compartir modelos de forma controlada entre contextos, revisa el Shared Kernel.