AXENTED — Blog Article
Slug: /blog-posts/software-rewrite-vs-refactor |
Meta description: La atracción hacia una reescritura completa es casi siempre emocional, no analítica. Un marco de decisión objetivo con criterios que separan claramente los dos casos. |
Target keywords: rewrite vs refactor software, debo reescribir codebase, refactorizar código heredado, decisión reescritura software |
"Necesitamos reescribir esto" es una de las frases más costosas en el software. No porque las reescrituras siempre estén mal — a veces son la decisión correcta. Pero la decisión se toma emocionalmente con mucha más frecuencia que racionalmente, y la versión emocional casi siempre apunta hacia una reescritura cuando la versión racional apuntaría hacia una mejora incremental.
Este es un marco de decisión con criterios objetivos.
Las reescrituras se sienten decisivas. Ofrecen la promesa de empezar de cero, de tomar todas las buenas decisiones que se perdieron la primera vez, de eliminar todos los compromisos heredados en un movimiento audaz. El refactoring se siente como parchear un bote con goteras. La atracción hacia la reescritura es casi siempre emocional, no analítica.
La literatura de ingeniería tiene un hallazgo consistente: la mayoría de las reescrituras de software tardan de tres a cinco veces más de lo estimado, entregan menos funcionalidades que el sistema que reemplazaron y reproducen una parte significativa de los bugs del sistema original porque los requisitos para los casos borde vivían en el código, no en la documentación. Joel Spolsky lo llamó "el peor error estratégico que cualquier empresa de software puede cometer." La reescritura 5.0 de Netscape. La reescritura de FogBugz. El patrón se repite.
Las reescrituras están justificadas en un conjunto estrecho de circunstancias. La pila tecnológica subyacente es genuinamente de fin de vida sin ruta de actualización — no "vieja," sino realmente sin soporte e incompatible con las herramientas e infraestructura que necesitas usar. El sistema tiene restricciones arquitectónicas fundamentales que hacen que la funcionalidad requerida sea imposible de agregar, no solo difícil. La base de código ha sido modificada por tantas personas a lo largo de tantos años sin ningún diseño coherente que la complejidad acumulada es mayor que empezar de cero.
Ese último criterio es más raro de lo que los equipos creen. Una base de código que se siente desordenada para los ingenieros que se incorporan generalmente es navegable para los ingenieros que han trabajado en ella durante un año. "Los nuevos ingenieros están confundidos" es un problema de documentación e incorporación, no un problema de reescritura.
Para la mayoría de los sistemas que genuinamente necesitan una mejora importante, el patrón strangler fig es más seguro que una reescritura completa. Construye nueva funcionalidad en un nuevo sistema limpio junto al existente. Gradualmente enruta el tráfico al nuevo sistema módulo por módulo. Retira el sistema antiguo a medida que se reemplaza cada parte. El sistema antiguo nunca deja de funcionar, por lo que nunca hay un momento en que nada funcione.
Este enfoque es más lento y menos satisfactorio que una reescritura limpia. También entrega funcionalidades durante el proceso, mantiene el sistema existente funcionando para usuarios reales y expone los problemas de integración de forma incremental en lugar de todos a la vez al final de un proyecto de varios años.
El refactoring tiene sentido cuando la lógica de negocio es correcta y la ejecución es desordenada. El sistema hace lo que se supone que debe hacer, pero cambiarlo es lento y arriesgado. La intervención correcta es la mejora incremental: extrae el módulo más doloroso, límpialo, agrega pruebas, pasa al siguiente. Cada mejora hace que la siguiente sea más barata.
La disciplina es no intentar refactorizar todo a la vez. Elige el módulo que genera más fricción para el trabajo actual. Límpialo. Repite. Los equipos que intentan refactorizar todo el sistema en una sola iniciativa generalmente abandonan el esfuerzo a medias, dejando la base de código en peor estado del que estaba antes de comenzar.
Antes de decidir, responde estas preguntas honestamente: ¿El sistema nos impide construir funcionalidades que nuestro producto requiere? ¿Los ingenieros que lo construyeron todavía están aquí para explicar la lógica? ¿La tecnología subyacente está realmente sin soporte o solo es antigua? ¿Podía el 20% más doloroso de la base de código, si se limpia, resolver el 80% de la fricción diaria?
Si el sistema impide funcionalidades requeridas: considera una reescritura parcial del componente afectado. Si los ingenieros originales se fueron: prioriza la documentación y la recuperación del conocimiento antes de cualquier cambio estructural. Si la tecnología solo es antigua pero funcional: refactoriza incrementalmente. Si el 20% de la base de código causa el 80% de los problemas: empieza por ahí.
La mayoría de los problemas de la base de código son problemas de refactoring. Los que requieren reescrituras son genuinamente raros.