¿Reescribir o refactorizar un sistema legacy? Cómo decidir sin frenar el negocio

Cuándo conviene reescribir un sistema legacy y cuándo refactorizar: señales, costos y riesgos de cada camino para un producto que ya está en producción.

HitOcean HitOcean Desarrollo de Software Publicado el 9 min de lectura
Primer plano de un monitor con código fuente y un teclado iluminado en un escritorio de desarrollo

Respuesta corta: en la mayoría de los casos, a un sistema legacy le conviene una refactorización por partes y no una reescritura desde cero. Reescribir tiene sentido en tres situaciones: la tecnología ya no tiene soporte, el negocio cambió tanto que el sistema resuelve un problema que ya no tienes, o cada cambio cuesta más que rehacer ese módulo. Si no puedes decir cuál de las tres es tu caso, todavía no es momento de reescribir.

La conversación suele empezar igual. Un feature que debía salir en dos semanas lleva dos meses. El equipo dice que el código “no da más” y propone tirarlo y empezar de nuevo. Del otro lado, el negocio no puede frenar un año mientras se construye un sistema que, el día que esté listo, va a hacer lo mismo que el actual.

Las dos posturas tienen algo de razón. Esta guía es para decidir con datos y no por cansancio.

Qué es un sistema legacy (y por qué no depende de la edad)

Un sistema legacy es software que todavía sostiene el negocio pero que tu equipo ya no puede cambiar con confianza. La antigüedad importa menos de lo que parece. Un producto de tres años sin tests, cuyo único desarrollador que lo entendía ya se fue, es más legacy que un sistema en Java de 2012 con buena documentación y cobertura de pruebas.

Algunas señales de que tienes uno:

  • Hay partes del código que nadie quiere tocar, y todos saben cuáles son.
  • Un cambio chico en un módulo rompe algo en otro que no tenía nada que ver.
  • Sumar a una persona nueva al equipo lleva meses antes de que pueda trabajar sola.
  • Las estimaciones fallan siempre para el mismo lado.
  • Los deploys se hacen con miedo, en horario de poco tráfico y con alguien de guardia.

Deuda técnica: cuánto te cuesta hoy

Antes de discutir qué hacer, conviene ponerle un número al problema. La deuda técnica es todo lo que se hizo rápido en su momento y hoy cobra intereses: cada feature nuevo paga un poco de ese atraso.

No hace falta una herramienta sofisticada para medirla. Alcanza con mirar cuatro cosas de los últimos tres meses:

  1. Qué parte del sprint se va en bugs e incidentes. Si tu equipo de cinco personas dedica el 40% del tiempo a apagar incendios, estás pagando dos sueldos completos para que el sistema no se caiga.
  2. Cuánto tarda un cambio chico en llegar a producción. Un cambio de texto que necesita una semana dice mucho del estado del sistema.
  3. Cuántos features se atrasaron por “complejidad técnica”. Y cuáles de esos estaban comprometidos con un cliente.
  4. Cuánto tardó en ser productiva la última persona que se sumó.

Con esos números la conversación cambia. Ya no es “el código está feo”, es “estamos perdiendo X horas por mes y el roadmap viene atrasado Y semanas”. Eso se puede comparar contra lo que cuesta arreglarlo.

Cuándo conviene refactorizar

Refactorizar es cambiar la estructura interna del código sin cambiar lo que hace. Se hace de a poco, sobre el sistema que ya está en producción, y cada paso se puede revertir.

Es el camino correcto cuando:

  • El sistema funciona y el negocio confía en él. Los problemas están en la velocidad para cambiarlo, no en lo que hace.
  • La tecnología sigue teniendo soporte. El lenguaje, el framework y la base de datos reciben actualizaciones de seguridad y consigues gente que los conoce.
  • Los problemas se concentran en algunos módulos. Casi siempre la deuda no está repartida de forma pareja: dos o tres partes del sistema generan la mayoría de los dolores de cabeza.
  • No puedes frenar el roadmap. Si hay clientes esperando features con fecha, refactorizar te deja seguir entregando mientras mejoras el sistema.

La práctica que mejor funciona es refactorizar la parte del código que vas a tocar para el próximo feature. No hace falta un proyecto aparte de “limpieza” que compita con el roadmap: la mejora sale junto con algo que el negocio pidió.

Cuándo conviene reescribir

Reescribir desde cero es construir un sistema nuevo que reemplace al actual. Es la opción más cara y la más riesgosa, pero hay casos en los que es la única razonable:

  • La tecnología llegó al final de su vida útil. Sin parches de seguridad, sin gente disponible en el mercado y con dependencias que dejaron de mantenerse.
  • El negocio cambió de forma profunda. El sistema se pensó para vender a consumidores y hoy vendes a empresas, o se pensó para un país y hoy operas en cinco. Si el modelo de datos ya no representa tu negocio, refactorizar es poner parches sobre una base equivocada.
  • Cambiar un módulo cuesta más que rehacerlo. Si cada intento de modificarlo termina en semanas de corrección de errores, y eso pasa una y otra vez, el cálculo ya está hecho.
  • No hay nadie que entienda el sistema. Si se fue toda la gente que lo construyó y no hay documentación ni tests, a veces es más barato rehacerlo con reglas claras que hacer arqueología.

Ojo con un riesgo que casi nunca entra en la estimación: mientras dura la reescritura, el sistema viejo sigue en producción y sigue necesitando cambios. Durante meses tu equipo mantiene dos productos. Y el sistema viejo guarda reglas de negocio que nadie anotó, que aparecen recién cuando el nuevo falla con un cliente real.

El caso más citado es el de Netscape a fines de los noventa: decidió reescribir su navegador desde cero, pasó años sin lanzar una versión nueva y perdió el mercado en ese tiempo. Joel Spolsky lo usó como ejemplo del peor error estratégico que puede cometer una empresa de software. Exagerado o no, el punto sigue vigente: mientras reescribes, tu competencia sigue avanzando.

Reescribir vs refactorizar, lado a lado

RefactorizarReescribir desde cero
Cuándo ves valorEn semanas, con cada mejoraRecién cuando el sistema nuevo reemplaza al viejo
Impacto en el roadmapBajo: se sigue entregandoAlto: buena parte del equipo deja de sumar features
RiesgoBajo y repartido en pasos chicosAlto y concentrado en el día del cambio
Conocimiento del negocioSe conserva, porque el código sigue ahíHay que redescubrirlo, y siempre falta algo
CostoDistribuido en el tiempoGrande y difícil de estimar
Cuándo es la mejor opciónSistema que funciona pero es lento de cambiarTecnología sin soporte o negocio que cambió de fondo

La tercera opción: modernizar por partes

Entre “arreglar lo que hay” y “tirar todo” hay un camino intermedio que es el que usan la mayoría de los equipos con producto en producción. Martin Fowler lo llamó strangler fig, por una higuera que crece alrededor de un árbol hasta reemplazarlo: el sistema nuevo crece alrededor del viejo y lo va reemplazando de a un módulo por vez.

En la práctica se ve así:

  1. Fijar cómo funciona hoy. Antes de tocar nada, se escriben pruebas que registran el comportamiento actual, con errores incluidos. Si quieres profundizar en cómo encararlas, en nuestra guía de TDD y BDD explicamos las dos formas de trabajar con tests.
  2. Elegir el primer módulo. El que más duele y menos dependencias tiene. Facturación, permisos o reportes suelen ser buenos candidatos.
  3. Ponerle una puerta de entrada. Se aísla el módulo detrás de una API, de forma que el resto del sistema no sepa si responde el código viejo o el nuevo.
  4. Reemplazar y medir. Se construye la versión nueva, se le deriva una parte del tráfico y se compara con la vieja.
  5. Apagar lo viejo. Cuando la versión nueva funciona igual o mejor, se elimina el código anterior. Y se pasa al siguiente módulo.

La ventaja es que en ningún momento apuestas todo a un solo lanzamiento. Si algo sale mal, el alcance del problema es un módulo, no el sistema entero.

Modernizar tampoco obliga a pasar a microservicios. Muchas veces un monolito bien ordenado es la mejor arquitectura para un equipo chico. Si estás evaluando ese cambio, en monolito o microservicios comparamos los costos y la complejidad de cada opción.

Cómo decidir sin adivinar

Antes de comprometer presupuesto, responde estas preguntas con tu equipo:

  • ¿La tecnología actual tiene soporte de seguridad para los próximos tres años?
  • ¿Los problemas están en todo el sistema o en dos o tres módulos?
  • ¿Cuánto nos cuesta por mes la deuda técnica, en horas y en features atrasados?
  • ¿Podemos dejar de entregar funcionalidades nuevas durante seis meses o más?
  • ¿Hay alguien en el equipo que entienda las reglas de negocio que viven en el código?

Si la mayoría de las respuestas apuntan a “el sistema funciona pero es lento de cambiar”, el camino es refactorizar o modernizar por partes. Si apuntan a “la base ya no sirve”, toca planificar una reescritura, y aun así conviene hacerla módulo por módulo.

El error más caro es decidir sin un diagnóstico. Por eso en HitOcean no arrancamos estimando la reescritura completa. Cada proyecto de desarrollo de software a medida empieza con un discovery: revisamos el código, la arquitectura y las prioridades del negocio, y al terminar tienes el alcance, el plan de trabajo y un rango de inversión antes de comprometer el desarrollo. Muchas veces la conclusión es que no hace falta más gente, sino ordenar la arquitectura antes de crecer.

Si el diagnóstico confirma que falta capacidad, podemos sumar un equipo dedicado que trabaje sobre tu producto sin frenar el roadmap. Puedes ver cómo lo hicimos con otras empresas en nuestros casos de éxito.

¿Tu sistema frena el roadmap? Cuéntanos qué está pasando y te decimos por dónde empezaríamos.

Preguntas frecuentes

¿Cuánto tarda reescribir un sistema legacy?

Casi siempre más de lo que dice la primera estimación. El sistema viejo tiene reglas de negocio que nadie documentó y que aparecen recién cuando el nuevo falla en producción. Además, mientras dura la reescritura el sistema viejo sigue necesitando cambios, así que el equipo trabaja en dos productos a la vez. Por eso conviene estimar por módulo y no el sistema completo de una vez.

¿Se puede refactorizar un sistema sin tests?

Se puede, pero es apostar. Lo recomendable es escribir primero tests que fijen cómo se comporta hoy el sistema, aunque ese comportamiento tenga errores. Con esa red puesta, cada cambio se puede verificar en minutos en lugar de descubrir el problema cuando lo reporta un cliente.

¿Refactorizar frena el desarrollo de nuevas funcionalidades?

No tiene por qué. La forma que mejor funciona es refactorizar la parte del código que vas a tocar para el próximo feature, no abrir un proyecto aparte de limpieza. Así la mejora sale con algo que el negocio pidió y el roadmap no se detiene.

¿Cuándo hay que cambiar de lenguaje o de framework?

Cuando la tecnología perdió soporte de seguridad, cuando ya no consigues gente que la conozca o cuando una dependencia crítica dejó de mantenerse. Que el stack sea viejo o poco atractivo para el equipo no alcanza como motivo.

¿Quién debería tomar la decisión de reescribir?

Entre el CTO y quien responde por el negocio. Es una decisión técnica con consecuencias comerciales: meses de roadmap, riesgo de perder clientes en la migración y presupuesto. Si solo la toma el equipo técnico, suele subestimarse el costo para el negocio; si solo la toma el negocio, se subestima el riesgo técnico.

Temas
  • Desarrollo de Software
  • Arquitectura de Software
  • Deuda técnica
¿Quieres aplicarlo en tu empresa?