Órdenes de aerolínea, sin el legacy de por medio
Separar el modelo de venta del sistema de reservas que lo tenía secuestrado: límites explícitos primero, anti-corruption layer sobre el legacy, y ninguna venta apagada durante la migración.
Nadie sabía decir qué era una orden
Una aerolínea vende. Su sistema de reservas, en cambio, guarda un registro pensado hace treinta años para un mostrador de aeropuerto. Entre esas dos cosas hay un modelo de dominio que nunca se escribió, y cada equipo se armó el suyo: tarifas tenía una definición de “orden”, liquidación tenía otra, y el sistema legacy manejaba una tercera que no coincidía con ninguna.
El síntoma del que todos se quejaban era la lentitud para sacar un producto tarifario nuevo. La causa real era que cada cambio había que reconciliarlo a mano contra tres definiciones distintas de la misma palabra.
El legacy no se discute: se contiene
No empezamos separando servicios. Empezamos por ponerle nombre a los límites que ya existían dentro del código y que nadie había escrito en ningún lado.
- Oferta, orden, inventario y liquidación pasaron a ser contextos explícitos, cada uno dueño de su vocabulario.
- El sistema legacy quedó detrás de un anti-corruption layer. Su modelo de registro sigue existiendo del otro lado del adaptador; lo que dejó de existir es su vocabulario filtrándose al dominio nuevo.
- El camino de migración fue endpoint por endpoint, con el flujo viejo y el nuevo conviviendo. En un negocio que vende las veinticuatro horas, un big bang no es una opción de diseño: es una apuesta.
Extraer un servicio de un límite que todavía no se probó es apenas distribuir la incertidumbre.
La lógica de integración —la parte que más se ensucia— quedó ordenada con lo aburrido de siempre: una estrategia por proveedor, una fachada por capacidad, y la escritura separada de la lectura donde los dos caminos tenían razones distintas para cambiar.
Contratos en vez de confianza
La superficie de integración con distribución, canales de venta y pagos es donde un sistema de este tipo se rompe de verdad, porque falla por motivos que no controlás.
- Cada integración quedó cubierta con contract tests: si un partner cambia su payload, se rompe nuestro build y no sus reservas.
- Los pagos confirman de forma asíncrona por webhook, así que la orden tiene que poder esperar sin bloquear la venta ni duplicar el cobro.
- Reintentos, aislamiento de fallos y errores que dicen qué pasó. El proveedor se va a caer; la pregunta de diseño es qué queda en pie cuando eso ocurre.
Qué cambió
- La optimización del consumo de servicios de terceros bajó la latencia de los endpoints afectados hasta un 60 %.
- La cobertura se sostuvo por encima del 85 % —unitarios e integración— con revisión sistemática y quality gates que bloquean el merge, no que avisan después.
- Un cambio de tarifa dejó de necesitar arqueología: hay un solo lugar donde vive la definición.
Lo que más valoro es otra cosa. El código que migré lo mantiene gente que no estuvo en la decisión original, y el modelo les alcanza para tomar las siguientes sin preguntarme.