Refactorización de bajo impacto y limpieza de código de código descuidado mientras espera requisitos

17

Heredé una base de código existente para un producto que es reprensiblemente descuidado. El diseño fundamental es lamentablemente inadecuado, que desafortunadamente puedo hacer poco sin un refactor completo (acoplamiento ALTO, cohesión BAJA, duplicación desenfrenada de código, sin documentación de diseño técnico, pruebas de integración en lugar de pruebas unitarias). El producto tiene un historial, una alta exposición a clientes críticos de "vaca de efectivo" con una tolerancia mínima al riesgo, una deuda técnica que hará sonrojar a los griegos, una base de código y complejidad MUY grande, y un enfoque derrotista de errores por parte del equipo antes de la batalla. yo.

El viejo equipo saltó a otra división para que tengan la oportunidad de arruinar otro proyecto. Es muy raro que experimente una falla de proyecto de incompetencia técnica en lugar de una falla de gestión de proyecto, pero este es de hecho uno de esos casos.

Por el momento estoy solo, pero tengo mucho tiempo, libertad de decisión y dirección futura y la capacidad de construir un equipo desde cero para ayudarme.

Mi pregunta es reunir opiniones sobre la refactorización de bajo impacto en un proyecto como este cuando tiene algo de tiempo libre durante la fase de recolección de requisitos funcionales. Hay miles de advertencias del compilador, casi todas importaciones no utilizadas, variables locales no leídas, ausencia de verificación de tipos y conversiones inseguras. El formato del código es tan ilegible y descuidado que parece que el codificador sufrió la enfermedad de Parkinson y no pudo controlar la cantidad de veces que se presionó la barra espaciadora en una línea determinada. Los recursos adicionales de bases de datos y archivos generalmente se abren y nunca se cierran de manera segura. Argumentos de métodos sin sentido, métodos duplicados que hacen lo mismo, etc.

Mientras espero los requisitos para la próxima función, he estado limpiando cosas de bajo impacto y bajo riesgo a medida que avanzo, y me preguntaba si estaba perdiendo el tiempo o haciendo lo correcto. ¿Qué pasa si la nueva característica significa extraer código en el que pasé tiempo antes? Voy a comenzar un enfoque ágil y entiendo que esto es aceptable y normal refactorizar constantemente durante el desarrollo ágil.

¿Puedes pensar en algún impacto positivo o negativo de mí haciendo esto que te gustaría agregar?

árbol de arce
fuente
1
Salva lo que vale la pena salvar, reescribe el resto ...
SF.
"Es muy raro que experimente una falla de proyecto de incompetencia técnica en lugar de una falla de gestión de proyecto [...]" Qué cierto es esto, +1.
Gregory Higley

Respuestas:

22

En primer lugar, me gustaría señalar que las pruebas unitarias no son un reemplazo para las pruebas de integración. Los dos necesitan existir uno al lado del otro. Agradezca que tiene pruebas de integración, de lo contrario, una de sus pequeñas refactorizaciones podría hacer que una de las vacas de baja tolerancia se vuelva balística.

Comenzaría a trabajar en las advertencias del compilador y las variables e importaciones no utilizadas. Obtenga una construcción limpia primero. Luego comience a escribir pruebas unitarias para documentar el comportamiento actual, luego comience la refactorización real.

Realmente no puedo ver ningún impacto negativo. Obtendrá una gran comprensión profunda de la base del código, lo que ayudará con refactorizaciones más grandes. Casi siempre es preferible refactorizar que reescribir, ya que durante la refactorización todavía tiene un producto que funciona, mientras que durante la reescritura no. Y al final las ventas del producto tienen que pagar su salario.

Una vez que los requisitos comiencen a entrar, usaría lo que yo llamo el enfoque de atención. Haga lo ágil habitual (priorice, luego corte una pequeña losa para una iteración y trabaje en eso) y deje un poco de tiempo para las mejoras del código. Luego refactorice dónde está trabajando de todos modos. Con el tiempo, esto cubrirá áreas amplias de la base del código sin que tenga que aventurarse en áreas donde tendría dificultades para justificar a la administración por qué está trabajando en esa parte del código.

wolfgangsz
fuente
Realmente me gusta esta respuesta. Necesito una comprensión más profunda de la base del código y las vacas en efectivo SÍ pagan mi salario y también nos permiten trabajar en mejores proyectos nuevos para otros clientes donde tengo la oportunidad de comenzar desde cero y hacerlo desde el principio.
maple_shaft
10

Escribir pruebas unitarias puede ser un uso más valioso de su tiempo: le dará algunas ideas sobre el funcionamiento actual de la base de código, y si decide comenzar desde lo que tiene en lugar de reescribir todo desde cero, tendrá una base sólida para hacer cambios sin correr demasiado riesgo. Lo más probable es que al escribir pruebas unitarias, también realice cambios en la base de código solo para que tenga una forma comprobable; esos son buenos, porque la unidad de prueba generalmente también significa modular, encapsulado y en su mayoría independiente del estado externo. Y, sobre todo, las pruebas unitarias bien escritas son documentación técnica invaluable. Con las pruebas unitarias en su lugar, podrá juzgar lo que la base de código actual puede y no puede hacer, en lugar de hacer suposiciones o reescribir cosas por si acaso.

tdammers
fuente
2
¿Comience con los fáciles y luego suba?
tdammers 05 de
2
Este es siempre el problema en mi experiencia: un código como este nunca se escribe para permitir la prueba y terminarás teniendo que hacer grandes refactorizaciones si no es que reescribiendo el código para incluso permitir pruebas unitarias en primer lugar.
Wayne Molina
2
Si el código no fue diseñado para pruebas, esa es una razón más para obtener pruebas, pero de manera segura. Lea el libro de Michael Feathers "Trabajando efectivamente con código heredado"; Tiene recetas para hacer que el código no comprobable sea comprobable.
Joe White el
1
Estoy de acuerdo; Simplemente, según mi experiencia, cuando no hay pruebas, tendrías que iniciar una gran refactorización para prepararla para las pruebas en primer lugar, lo que lleva a una refactorización más "desperdiciada", lo que hace que sea más difícil escribir pruebas, lo que luego hace que sea mucho más difícil refactorizar cualquier cosa.
Wayne Molina
1
Se necesita algo de experiencia y buen juicio. No todo puede (o debe) hacerse unitario.
tdammers 05 de
1

Combinación de respuestas: mi idea sería combinar pruebas y limpieza, ¿quizás 50/50? Si trabaja en un área que realiza un tipo de enfoque TDD: configure las pruebas que necesita para saber que la unidad y las pruebas de integración son las deseadas y luego comience a repararlas. Avanzar como el tiempo lo permita.

Probablemente significa que no progresará tanto, pero significa que tendrá una base de código muy estable en algunas áreas, al menos, y tendrá una buena base de inicio.

Mi reacción instintiva fue inicialmente "¿realmente puede doler limpiar el código roto?" (también conocido como errores del compilador), pero luego recordé los momentos en que solucionar el problema realmente rompía la funcionalidad en algunos casos realmente extraños porque en lugar de morir un hilo, dejaba la memoria en lugares malos, esencialmente un mal quiebre ocultaba un error aún peor. Literalmente puede ser una caja de sorpresas desagradables de Pandora.

Dado que está haciendo esto mientras espera más requisitos, creo que cualquier cosa que pueda para diagnosticar el caos se agregará en gran medida a su cordura a largo plazo.

bethlakshmi
fuente