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
| Componente | Responsabilidad | Ejemplo |
|---|---|---|
| Translator | Convierte datos entre modelos | LegacyCustomer → Customer |
| Adapter | Adapta la interfaz del sistema externo | REST → SOAP, JSON → XML |
| Facade | Simplifica la API del sistema externo | 5 llamadas legacy → 1 método limpio |
| Mapper | Mapea campos y valores entre modelos | status: "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ía | Opciones |
|---|---|
| Patrones de diseño | Adapter, Facade, Translator, Mapper |
| Librerías de mapeo | MapStruct (Java), AutoMapper (.NET), class-transformer (TS) |
| Integración | Apache Camel, Spring Integration, MuleSoft |
| API Translation | GraphQL 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.