Context mapping y anti-corruption layer
Un correo de otro banco
Un lunes llega un correo del banco de Luis: «Estrenamos la versión 2 de nuestra API. El campo beneficiario pasa a llamarse destinatario y añadimos un estado nuevo, 3 = en revisión. El antiguo 3 (liquidada) pasa a ser el 4».
En BCPS Bank, el equipo de Transferencias hace la cuenta de lo que hay que tocar. El envío, claro. Pero también el modelo de Transferencias, que guarda el estadoBancoLuis tal cual. Y el evento público TransferenciaCompletada, que lo lleva dentro. Y Notificaciones, que lo usa para el texto del aviso. Cuatro sitios, dos equipos, por un cambio en un banco que no es el nuestro.
Los contextos del episodio 2 no viven aislados: se relacionan, y cada relación es de un tipo, con consecuencias para los equipos. Dibujar esas relaciones es el context mapping.
El banco de Luis cambia su API
Transferencias manda 100 € de Ana a Luis. A la izquierda, sin nada en medio: el modelo del banco de Luis se usa tal cual. A la derecha, un traductor en la frontera. Envía una transferencia con la API v1, cambia a la v2 (mira el código: se marcan las líneas que ha habido que cambiar) y envía otra. Luego haz que el banco la ponga en revisión.
Qué ha pasado
El modelo de otro se cuela en el tuyo
Sin traductor, todo funciona con la API v1… y aun así ya hay un problema: la palabra estadoBancoLuis está en el modelo de Transferencias, en su lógica (if (estado === 3)), en su evento público y en el aviso que recibe Ana: «Tu transferencia está en estado 3».probar en el laboratorio El lenguaje de otro banco se ha colado hasta la app.
El día que ese banco cambia su API, se paga:probar en el laboratorio
- El renombrado obliga a tocar cuatro sitios en dos equipos: el envío, el modelo, el evento público (que otros consumen) y Notificaciones.
- El cambio de significado es peor, porque no rompe nada: el 3 sigue siendo un número válido, pero ahora significa «en revisión». La lógica sigue creyendo que es «liquidada», publica
TransferenciaCompletaday Ana recibe el aviso. Si el banco de Luis la rechaza después, BCPS Bank ya ha dado el dinero por entregado. - Y el 4, el nuevo «liquidada», no lo conoce nadie: las transferencias buenas se quedan en el limbo.
La anti-corruption layer
Una anti-corruption layer (ACL) es una capa que traduce en la frontera entre tu modelo y otro que no controlas. Hacia fuera, habla el idioma del otro (destinatario, códigos numéricos); hacia dentro, el tuyo (liquidada, pendiente, rechazada). En el panel de la derecha, Transferencias ni se entera de que existe una API v2: cambia el traductor, en un solo sitio, y el «3 = en revisión» se convierte en «pendiente». Nadie publica nada todavía, y Ana no recibe un aviso falso.
No es gratis: es código que mantener, y una traducción más en cada llamada. Por eso se usa donde el otro modelo es ajeno, cambia sin avisar o es malo. Un banco externo cumple las tres.
El mapa completo
La ACL es solo una de las relaciones posibles. Este es el mapa de BCPS Bank con el tipo de cada una. U y D marcan quién está arriba (upstream, el que manda en el modelo) y quién abajo (downstream, el que se adapta).
| Relación | Qué implica | En BCPS Bank |
|---|---|---|
| Cliente-proveedor (C/S) | El de arriba atiende las necesidades del de abajo; negocian los cambios | Clientes → Cuentas (ClienteVerificado); Antifraude → Tarjetas (llamada síncrona) |
| Servicio anfitrión abierto + lenguaje publicado (OHS/PL) | Un protocolo abierto y documentado para todos, en vez de uno a medida para cada consumidor | Los eventos de Cuentas (MovimientoRegistrado), con su esquema versionado (ep. 6 de eventos) |
| Conformista (CF) | El de abajo acepta el modelo del de arriba tal cual | Notificaciones y Fidelización con los eventos de Transferencias y Tarjetas |
| Núcleo compartido (SK) | Un trozo pequeño de modelo común, que solo cambia de acuerdo | Los tipos Importe e IBAN, entre Cuentas y Transferencias |
| Anti-corruption layer (ACL) | Un traductor que protege tu modelo del de otro | Transferencias ↔ banco de Luis |
Fíjate en el conformista, que es el contrapunto a la ACL. Notificaciones acepta los eventos de Transferencias sin traducir nada, y está bien: el evento es estable, lo publicamos nosotros y Notificaciones solo necesita un texto. Montar una ACL ahí sería traducir por traducir. Adaptarse al de arriba sale más barato cuando su modelo es razonable; la ACL compensa cuando no lo es, o cuando no controlas cuándo cambia.
Subdominios: dónde invertir
Pulsa «Ver subdominios» en el mapa. Cada contexto resuelve un tipo de problema, y no todos merecen el mismo esfuerzo:
- Core (Cuentas, Antifraude): lo que distingue al banco. Un mejor modelo de riesgo es menos fraude y menos pagos buenos denegados. Aquí van los mejores equipos, y aquí DDD compensa más.
- Supporting (Transferencias, Tarjetas, Reporting, Fidelización): necesario pero no diferenciador. Hacerlo simple y bien, sin sobrediseñar.
- Generic (Notificaciones, la verificación de identidad de Clientes): igual en cualquier empresa. Se compra hecho, y se envuelve, si hace falta, con una ACL para que el modelo del proveedor no se cuele.
Eventos de dominio y eventos de integración
Pulsa Transferencias en el mapa. Dentro de su contexto pasan cosas que a nadie más le importan: EnvíoAlBancoReintentado, RespuestaDelBancoRecibida. Son eventos de dominio: hablan el lenguaje interno y pueden cambiar cuando el equipo quiera. TransferenciaCompletada, en cambio, es un evento de integración: sale del contexto, otros lo consumen y es un contrato (un lenguaje publicado). La simulación enseña qué pasa cuando un detalle interno, o de otro banco, acaba en el contrato público: todos los que lo consumen heredan el problema.
Criterio
-
¿El otro modelo es tuyo (de tu organización) y razonable?Lo publica otro equipo de BCPS Bank, con un esquema estable.conformista
-
¿Los dos equipos pueden negociar los cambios?Hay una relación de trabajo y prioridades compartidas.cliente-proveedor
-
¿Tienes muchos consumidores y no puedes adaptarte a cada uno?Como Cuentas con sus movimientos.OHS + lenguaje publicado
-
¿El otro modelo es ajeno, cambia sin avisar o es malo?Otro banco, un sistema antiguo, un proveedor.anti-corruption layer
El núcleo compartido va aparte: solo para piezas pequeñas, estables y que de verdad significan lo mismo en los dos lados, como un importe o un IBAN.
En el mundo real
Los tipos de relación vienen del libro de Evans (2003) y de su Domain-Driven Design Reference posterior. Hay más de los que salen aquí: partnership (dos equipos que triunfan o fracasan juntos), separate ways (no integrarse en absoluto) y el big ball of mud (reconocer una zona sin modelo claro y aislarla). La comunidad DDD Crew mantiene una chuleta de patrones de context mapping, y herramientas como Context Mapper permiten describir el mapa como código y generar los diagramas.
Las ACL más habituales en banca no son contra otros bancos (aunque esas existen, como adaptadores para cada red de pagos), sino contra el sistema antiguo del propio banco: el núcleo en mainframe que lleva décadas funcionando. La red de tarjetas es otro caso claro: sus mensajes tienen su propio formato y sus propios códigos de respuesta, y ningún banco quiere esos códigos repartidos por su modelo. Sam Newman describe la ACL como pieza del patrón strangler fig para ir sustituyendo un sistema antiguo poco a poco.
La distinción entre eventos de dominio y de integración aparece, con esos nombres, en la guía de microservicios de Microsoft (.NET) y en buena parte de la literatura de DDD con eventos.
Siguiente episodio
Hemos bajado del banco entero a los contextos, y de los contextos a sus relaciones. Queda un nivel más: dentro de Cuentas, ¿qué cosas tienen que cambiar juntas, en una sola transacción? En Black Friday, a Ana le llegan a la vez un pago con tarjeta, la nómina y el recibo de la luz. ¿Tienen que esperarse unos a otros?
Siguiente · Episodio 4 Agregados como frontera de consistencia Un agregado grande o varios pequeños, la contención en Black Friday, y la transferencia interna que rompe la regla a propósito.