En las selvas de América Central y el sudeste asiático crece un árbol que no sigue las reglas habituales. Un strangler fig (higuera estranguladora) empieza su vida como una semilla diminuta que un pájaro deja caer entre las ramas de otro árbol, más viejo, muy por encima del suelo. Nunca brota de la tierra. En cambio, envía raíces finas hacia abajo, que van envolviendo el tronco del árbol huésped mientras buscan alcanzar el suelo. Con los años, esas raíces se engrosan hasta formar una red leñosa que termina encerrando por completo al huésped. Con el tiempo, el árbol original muere y se pudre dentro de su nueva cáscara, y queda en pie un tubo con forma de árbol hecho de raíces de higuera, cumpliendo exactamente la misma función que cumplía el huésped —sostener un follaje, buscar el sol— sin que el bosque haya perdido nunca un árbol para lograrlo.
Es una imagen rara para traer a una conversación sobre software legacy, pero los arquitectos de software la toman prestada por una razón: describe, casi al pie de la letra, la forma más segura de reemplazar un sistema viejo. No derribándolo y empezando de una hoja en blanco, sino haciendo crecer el reemplazo alrededor de él, pieza por pieza, hasta que el viejo finalmente se pueda retirar sin que nadie note el momento exacto en que sucedió.
Por qué la reescritura total fracasa tan seguido
La forma obvia de reemplazar un sistema viejo es construir uno nuevo de cero y pasarse a él en un día elegido. Casi nunca sale así, y las razones son estructurales, no una cuestión de esfuerzo ni de talento.
Primero, el negocio no puede detenerse durante los meses, o años, que toma una reescritura completa. Los pedidos siguen llegando, los tickets de soporte siguen llegando, y alguien tiene que mantener el sistema viejo funcionando y correcto durante todo el tiempo que se está construyendo el nuevo, lo que significa que ese sistema viejo "temporal" se convierte, en silencio, en un sistema permanente y con doble mantenimiento durante toda la duración del proyecto.
Segundo, el sistema viejo no se queda quieto mientras lo reconstruís. El negocio sigue cambiando, lo que significa que los requerimientos siguen cambiando, lo que significa que la reescritura persigue un objetivo que se mueve todo el camino. Para cuando el sistema nuevo está "terminado", se lo está midiendo contra una versión del negocio que ya no existe.
Tercero, y lo más peligroso: una reescritura total valida casi nada hasta el final. Cada supuesto, cada caso límite, cada comportamiento particular que el sistema viejo manejaba correctamente queda sin probar en producción hasta el día del cambio, cuando todo tiene que funcionar a la vez, para todos los usuarios, sin ninguna exposición gradual a tráfico real antes de eso. Es una cantidad enorme de riesgo concentrada en una sola tarde.
Cómo funciona el enfoque strangler, paso a paso
El patrón strangler fig —a veces llamado simplemente migración incremental— evita los tres problemas porque nunca llega a existir un "día del cambio".
- Poner una aplicación nueva delante. Se construye una aplicación nueva y liviana —en este contexto, generalmente ASP.NET Core— que recibe primero cada solicitud entrante, antes de que el sistema viejo la vea siquiera.
- Reenviar lo que todavía no está migrado. Para cualquier página o ruta que la aplicación nueva aún no maneje, simplemente reenvía la solicitud directo al sistema viejo que está detrás, que responde como siempre lo hizo.
- Migrar una pieza a la vez, en producción, con tráfico real. Se elige una sola página o funcionalidad, se reconstruye dentro de la aplicación nueva, y esa ruta puntual pasa a apuntar al código nuevo en lugar de reenviarse. Todo lo demás sigue funcionando exactamente como antes.
- Repetir, ordenando por riesgo y valor. Se avanza por la aplicación página por página, normalmente empezando por algo de bajo riesgo para probar que el esquema funciona, y después yendo hacia lo que más le importa al negocio.
- Retirar el sistema viejo cuando queda vacío. Cuando todas las rutas ya fueron migradas y la aplicación vieja no recibe tráfico real, se la apaga. Nunca hubo un día en que todo cambió de una vez: solo una larga serie de cambios chicos, ya probados.
Un ejemplo concreto
Imaginemos una empresa que corre todo su sitio público sobre una aplicación ASP.NET WebForms antigua, del tipo que tiene un ciclo de vida de página y controles de servidor que, como expliqué en otra nota, no tienen un equivalente directo en el .NET moderno y hay que reconstruir en lugar de convertir.
No reescribimos todo el sitio. Construimos una aplicación nueva en ASP.NET Core y la ponemos delante de la vieja: cada solicitud llega primero a la aplicación nueva, y por ahora, la aplicación nueva reenvía todas directo al sistema WebForms que está detrás. Nada cambia todavía para los usuarios.
Después migramos la página de inicio de sesión —un buen primer candidato, fundamental pero bien entendido— hacia la aplicación nueva, y dejamos de reenviar esa ruta puntual. Los usuarios que inician sesión ahora llegan al código nuevo; todos los demás siguen en el sistema viejo, sin notar que algo cambió. Después sigue el catálogo de productos, luego la configuración de cuenta, luego el checkout, cada uno probado en producción, con tráfico real, antes de empezar el siguiente. La aplicación WebForms vieja se achica un poco con cada entrega, manejando cada vez menos rutas, hasta que un día no maneja ninguna, y la apagamos.
Qué te da esto que una reescritura no da
Cada paso de este enfoque queda validado con usuarios y datos reales antes de que empiece el siguiente, en lugar de que toda la validación ocurra de una sola vez, en un día de altísimo riesgo. Si las prioridades cambian a mitad de camino —y en un proyecto largo, suele pasar— podés pausar después de cualquier página migrada con un sistema completamente funcional en ambos lados de la línea, no con una reescritura a medio terminar que nadie puede lanzar. Y como cada entrega es chica y acotada, un error en una página migrada es un bug para corregir, no una crisis que afecta a todo el negocio.
Y, siendo honesto, también es mejor para la moral del equipo. Un equipo que entrega algo real cada pocas semanas se mantiene seguro de sí mismo y visible para el negocio. Un equipo que desaparece durante un año para reconstruir todo está pidiendo una confianza que todavía no se ganó, sin importar qué tan bueno termine siendo el trabajo.
El árbol, con el tiempo, queda en pie por sí solo
Esa es toda la idea detrás del nombre. La higuera estranguladora pasa años pareciendo que solo está envuelta alrededor de otro árbol, hasta que un día el huésped ya no está, y lo que queda fue construido, con paciencia, para sostenerse completamente por sí mismo. Nadie que observe el bosque ve el día exacto en que sucedió, porque nunca hubo uno.
Así se ve, también desde afuera, una migración de sistemas legacy bien llevada: no un cambio dramático de un día para el otro, sino una larga serie de días chicos, aburridos y exitosos, hasta que el sistema viejo, en silencio, deja de estar ahí.