2010-01-20 32 views
36

Una de las situaciones más desagradables (y desafortunadamente más frecuentes) a las que me enfrento en mi vida cotidiana como desarrollador es que tengo que corregir errores o agregar funciones al código que está mal diseñado. Ahora, como buen artesano, me gustaría dejar el código en un mejor estado que el que encontré. A menudo, las nuevas características no se pueden implementar si no refactorizo ​​el diseño. Bueno, podrían, pero eso empeoraría el código.Cómo lidiar con el código incorrecto

Desafortunadamente, esto es exactamente lo que tiendo a tener dificultades. Siento que si hay algo que es difícil, es refactorizar el código incorrecto, especialmente cuando tienes fechas límite. Tocar el código malo y complejo que más o menos funciona es aterrador. Como resultado, introduzco aún más desorden cuando hackeo una nueva característica en el código sin modificar el código existente.

Ahora mi pregunta es ¿Cómo puedo aprender a lidiar con el código incorrecto? ¿Cómo puedo aprender a entender grandes bases de código y luego refactorizar algunas partes sin romper cosas que ya funcionaron y sin exceder la fecha límite? ¿Hay literatura que puedas recomendar? ¿Tienes algún consejo general para mí?

+0

wiki de la comunidad? – Thilo

+0

Sí, wiki de la comunidad! – bitbonk

Respuesta

19

Michael Feathers escribió un buen libro sobre este tema exactamente.

Working Effectively with Legacy Code.

Otro gran libro es por Martin Fowler, Kent Beck y otros:

Refactoring: Improving the Design of Existing Code.

+0

+1 para WELC - es la referencia clásica - ¡por una buena razón! - para exactamente estas preguntas. –

+2

Los libros son un par. Recomiendo leer * Refactoring * primero. Inspirará y frustrará, porque dirá: "Pero necesito hacer cambios para que sea comprobable. ¿Cómo lo hago sin romper el código?" Ahí es donde entra el libro de Plumas. –

21

punta general:

if (it is working) 
    Do (not touch it); 
else 
{ 
    Make (as few modifications as possible) 
    Or (it will stop working at all); 
} 

Ésta es la experiencia de las generaciones.

+15

+1. Triste pero cierto. – Thilo

+7

Estoy de acuerdo, pero ¿no te frustra ver lo mal que se hace? ¡Es como TENGO QUE ARREGLAR ESTO! – Strawberry

+2

Todo programador tiene eso;) pero el tiempo, y por lo tanto el dinero, no lo permitirán. – Oxymoron

6

Cuando tengo que lidiar con la adición de la funcionalidad de código malo, mi enfoque habitual es:

pruebas
  • Escribir automatizados para cada característica importante que debe trabajar (ya que la mayoría de código mal no tiene ningún pruebas).
  • Cambie el código.
  • Asegúrate de que las pruebas sigan funcionando.

Eso le da al menos la confianza de que no rompió todo. En cuanto a cómo aprender a lidiar con el mal código, supongo que se trata de experiencia.

+7

Muy a menudo el código está tan mal diseñado que es difícil escribir pruebas para nada. – bitbonk

+0

Siempre es posible escribir al menos * algunas * pruebas. –

+2

Puede al menos escribir pruebas contra las interfaces de más alto nivel. Si no hay interfaces buenas, agregue un contenedor que * proporcione * una buena interfaz, luego escriba las pruebas en contra de eso. – Ether

4

Bueno, si usted va a refactorizar grandes cantidades de código en un proyecto me gustaría recomendar el uso de algún control de versiones decente, por lo que puede diversificarse y entrar de nuevo fácilmente. Teniendo en cuenta, esta es probablemente una puerta abierta, pero crucial.

Además, antes de empezar a entrar en OO complejo, intente dividir métodos y funciones en otros más pequeños. Asegurando un cierto nivel de atomicidad en cada una de las funciones, lo que hace que el código sea mucho más fácil de mantener, leer y administrar. Se trata de cosas pequeñas, dividirlas en unidades lógicas de operación, estoy haciendo una acción de refactorización en un método de 1k líneas. Lo hace todo tipo de cosas de lujo. Mi primer objetivo es obtener la mayor cantidad de material en piezas más pequeñas, cuando eso esté listo comenzaré a pensar en un mejor diseño de OO, que es mucho más fácil porque tengo una mejor comprensión de las cosas.

Aspirin funciona bien también.

8

La refabricación necesita el arnés de seguridad de una unidad de prueba unitaria para eliminar ese "¿Lo he roto?" sensación. Cubrir el código incorrecto en una serie de pruebas te ayudará mientras luchas por un buen código de limpieza.

Pex es una herramienta que me parece útil (si se encuentra en el mundo de .NET) para crear pruebas de código heredado.

código heredado == código sin pruebas!

Bondad,

Dan

0

Depende de varios factores, pero el más importante es si usted tiene autoridad para modificarlo.

En caso de que lo haga, refactorícela. Por ejemplo, cambie el nombre de clases/funciones/variables. Extrae y generaliza funcionalidades. Ver refactorización: Improving the Design of Existing Code (Biblia para el tema). Antes de comenzar, asegúrese de que el código tenga el control de versión adecuado (VC) y tenga un buen conjunto de casos de prueba. VC le permite retroceder y los casos de prueba ayudan a detectar efectos secundarios inesperados.

Sugiero el Control de versiones distribuidas como Mercurial/Bazaar y Git porque es muy refactorizado y no está exactamente estructurado como la adición de características.

Si no hubo pruebas (comunes), debe crearlas. Lee Working Effectively With Legacy Code. Especialmente sobre "Punto de sello" (no sobre gato siamés: p).

En caso de que no cree una API contenedora que sea más limpia.

Por ejemplo:


Old code ==================== 
const ACT_SHOW = 'show'; 
const ACT_HIDE = 'hide'; 
function int DoThing(Object $Obj, Stirng $Action, Object $Param1, Object $Param1) { 
    ....; 
} 
Added code ================== 
enum Actions { 
    show, hide; 
}; 
class ActionDoer { 
    private obj; 
    ActionDoer($Object) { 
     this.obj = $Object; 
    } 
    function int act(Actions $Action, $Param1, $Param1) { 
     this.act($Action.toString(), $Param1, $Param1) ; 
    } 
    function int act(String $Action, $Param1, $Param1) { 
     DoThing(this.obj, $Action, $Param1, $Param1) ; 
    } 
    function int show() { 
     this.act(Actions.show, null, null); 
    } 
    function int hide(Color $ToBGColor, long $FadeTime) { 
     this.act(Actions.hide, $ToBGColor, $FadeTime); 
    } 
} 

De esta manera, el viejo código no se toca y la extensión se puede hacer utilizando el nuevo código. Un buen ejemplo de este método es jQuery, donde la forma antigua (por defecto) de acceder al DOM es dolorosa.

Espero que esto ayude.

1

Creo que siempre es bueno tener una idea general de cómo funciona todo en el software que está desarrollando/mejorando. Aquí es donde entran los documentos de diseño y otros documentos creados después o durante el proceso de desarrollo. Creo que si alguien antes no ha realizado la documentación adecuada, al menos debe escribir un par de líneas sobre lo que experimenta durante su proceso de desarrollo. . Usualmente uso OneNote u otras cosas para escribir notas sobre lo que encuentro, y generalmente sigo enumerando cosas que creo que requerirían refactorización. Y si hay algún tiempo de inactividad durante el proyecto, por lo general vuelvo a esa lista y trato de mejorar las cosas poco a poco.

Básicamente, si alguien antes que usted no lo ha hecho bien, sería bueno si al menos pudiera ayudar a reducir los problemas para cualquier otro desarrollador que se encuentre con el mismo código.

3

Actualmente estoy en esta situación. Mi enfoque es responder a algunas preguntas antes de tocar el código:

  1. es el código de realmente tan malo? En caso afirmativo, ¿cuáles son los errores comunes? ==> quizás concentrarse en los primeros
  2. ¿Cuál es el flujo de tiempo de ejecución principal en el código? Quizás puedas descartar bastantes constructos de él.
  3. Intenta copiar/modularizar el código sin cambiarlo. Esto lleva a una cierta reducción de las interdependencias
  4. Intente introducir el código con las pruebas. Si la base de código está enredada más allá de toda esperanza: utilice algo como PowerMock para simular objetos que aún no necesitan cambios
  5. Tenga a su disposición un entorno de integración en el que pueda probar los cambios en un entorno cercano a la producción.
  6. No dude en volver a escribir partes de la base de código. Pero trata de no aplicar demasiada cosas nuevas en ella
  7. Trate de hacer equipo, discutir diseños, principios, soluciones

Este es un trabajo duro, y nadie se lo agradecerán. Siéntete orgulloso de las pequeñas mejoras y disfruta de un buen trabajo :)

Cuestiones relacionadas