¿Qué enfoques puedo tomar para reducir las probabilidades de introducir nuevos errores en una aplicación heredada compleja?

10

Cuando trabajo, a menudo tengo que desarrollar (y corregir errores) en un sistema antiguo (.NET 1) cuyo código es un espagueti completo, sin pensar mucho en los nombres de variables, la estructura del programa ni los comentarios.

Debido a esto, me lleva mucho tiempo comprender qué bits necesitan cambiar, y a menudo 'rompo' el software existente porque he realizado una modificación. Realmente realmente quiero pasar un par de meses (con colegas) que pasan por allí a refactor pero existente desarrolladores tanto no puede ver la necesidad - ni pensar theres tiempo para esto (el sistema es enorme).

Temo tener que trabajar en su código, ya que lleva días arreglar algo solo para descubrir que he roto algo más. Obviamente, esto me hace parecer incompetente, entonces, ¿cómo puedo lidiar con esto?

billy.bob
fuente
pregunta relacionada: programmers.stackexchange.com/questions/66438/…
Matthieu

Respuestas:

16

Comience a escribir pruebas para las partes en las que está trabajando. Puede probar un flujo de trabajo que sea más o menos así:

  1. Escriba pruebas para la parte que está a punto de cambiar. Esto también lo ayudará a comprender cómo se comporta el código existente.
    • Refactorice el código para admitir las pruebas si es necesario, pero es posible que desee escribir pruebas no unitarias si el tiempo es corto.
  2. Ejecute sus pruebas para asegurarse de que las cosas funcionen como espera.
  3. Haz tus cambios. Refactorice si es necesario en el espíritu de la mejora continua del código, pero no se deje llevar.
  4. Vuelva a ejecutar sus pruebas para asegurarse de que mantiene la misma funcionalidad.

Si no descarta sus pruebas, con el tiempo creará un conjunto de pruebas que debería cubrir las partes más importantes (y / o volátiles) de la aplicación y hacer cambios en ella será más fácil y seguro.

También es posible que te resulte útil trabajar eficazmente con código heredado de Michael Feathers.

Adam Lear
fuente
1
+1 para "... pero es posible que desee escribir pruebas que no sean de unidad si el tiempo es corto".
Marcie
1
Buena respuesta. @ m.edmondson También puede encontrar a medida que refactoriza que ciertas partes del código son 'enormes' porque hay duplicación en todas partes y que a medida que refactoriza se vuelve más pequeño y más simple.
Alb
6

Me gusta seguir el tío Bob Martin 's Boy Scouts Regla :

"Cuando tienes un gran legado desordenado, lo que tienes que hacer es ... Lo que tienes que hacer es dejar de hacer el desastre y comenzar a limpiarlo".

Esto no significa que llame a sus gerentes a una sala de conferencias y les diga que no ofrecerá funciones durante los próximos tres meses mientras refactoriza el código. ¡No hagas esto! Más bien, significa que adoptará la "Regla de los Boy Scouts" y revisará cada módulo de forma un poco más limpia que cuando lo revisó.

De iteración en iteración, y de versión en versión, va a limpiar este sistema mientras continúa agregando nuevas características y funcionalidades. No hay otra manera."

Jesse C. Slicer
fuente
2

Podría explicarle al gerente que las correcciones que deberían tomar horas terminan tomando días debido al desorden de la base del código. Los otros desarrolladores no verán la necesidad de refactorizar si son los desarrolladores originales: conocerán el sistema al revés, pero la gerencia debería saber que existe un riesgo si esos desarrolladores alguna vez se van y se llevan sus conocimientos.

Por lo general, no es factible realizar una refactorización completa, por lo que a menudo refactoriza pequeños bits a la vez: un par de métodos o un módulo. Demonios, si lleva varios días hacer una solución, tal vez pueda incluir una pequeña refactorización del módulo problemático al mismo tiempo.

FrustratedWithFormsDesigner
fuente
1
Estoy de acuerdo, y en el pasado he incluido estos refactores 'pequeños' como simplemente lo he necesitado para comprender el código; sin embargo, generalmente aparece alguien "lo has roto por completo" y lo revierte a como estaba ...
billy.bob
@ M. Edmondson: Ah. Bueno, si tuvieran un conjunto completo de pruebas unitarias, simplemente ejecutando eso verificaría si el refactor era bueno o no. Por lo que parece, no tienen eso, por lo que tendrá que escribir las pruebas unitarias usted mismo. Sé que no es fácil y no hay una respuesta definitiva definitiva a este problema (al menos no una que haya encontrado, aunque estaré atento para ver qué sugieren otras personas ya que también he estado allí).
FrustratedWithFormsDesigner
2

¿Realmente necesita pasar meses refactorizando el código? ¿O podría refactorizar el código a medida que realiza cambios? Entonces, por ejemplo, si determina que el método Foo necesita ser modificado, podría aprovechar la oportunidad para refactorizar el método Foo. Y si tiene que pasar por una docena de otros métodos para descubrir que Foo es el problema, puede dejar comentarios en esos métodos para que usted u otra persona en el futuro sepan qué se supone que debe hacer el código. Por supuesto, eso significa que todavía hay una pila de código de espagueti, pero al menos puede mover la base del código en la dirección correcta y facilitarle la tarea. Obtener varios meses de tiempo para refactorizar el código será una gran venta porque eso significa que no está entregando nada que el usuario final quiera durante todo ese tiempo.

Y crear pruebas unitarias (o, con suerte, extender el conjunto de pruebas existente) debería hacer que sea menos probable que rompa algo sin darse cuenta.

Justin Cave
fuente
0

Otro consejo Cuando los errores se manifiestan, y después de aplicar el vendaje, ¡ no te detengas allí!

Pregunte los cinco porqués, tome la píldora roja y vea qué tan profundo es el agujero del conejo, y arregle la causa raíz (y el camino hacia abajo).

Aprendes mucho sobre el sistema. Ayuda a priorizar qué arreglar y refactorizar. Y después de algunos viajes de este tipo, tiene algunas "vigas de soporte" sólidas para fortalecer el montón monolítico de espagueti.

Maglob
fuente
0

También puede mantener el código antiguo en su lugar hasta que esté absolutamente seguro de que sus modificaciones son a prueba de sonido. Solo en caso de que haya todos sus cambios, para que pueda alternarlos en tiempo de ejecución y señalar rápidamente la ubicación del nuevo error de regresión:

// old code
...

if (!File.ReadAllText("c:\patch_control.txt").Contains("StrangeUIBugFix=0"))
{
    // new code goes here
    ...
}

// old + new code
int someValue = 
    IsEnabled("StrangeUIBugFix") ? a + b :  // new code
    a * b; // old code
AareP
fuente
0

Una cosa: Never change any existing code if you are not sure what effect change would have on complete application.

Rachel
fuente