2010-05-14 21 views
8

Acabo de completar una pieza compleja de código. Funciona según las especificaciones, cumple con los requisitos de rendimiento, etc., pero me siento un poco ansioso y estoy considerando volver a escribirlo y/o refactorizarlo. ¿Debería hacer esto (dedicar tiempo que de otro modo podría gastarse en funciones que los usuarios realmente notarán)?Refactorizar/reescribir el código o continuar?

Las razones por las que se siente ansioso acerca del código son:

  1. La jerarquía de clases es compleja y no es evidente
  2. Algunas clases no tienen un propósito bien definido (que hacer una serie de cosas no relacionadas)
  3. Algunas clases utilizan otros elementos internos (que están declarados como amigo clases) para eludir las capas de abstracción para el rendimiento, pero siento que se rompen encapsulación al hacer esto
  4. Algunas clases se filtran detalles de implementación (por ejemplo, he cambiado un mapa a un mapa hash antes y me encontré tener que modificar el código en otros archivos de código fuente para hacer el trabajo de cambio)
  5. Mi gestión de memoria/sistema de fondo común es un poco torpe y menos que transparente

Parecen excelentes razones para refactorizar y código limpio, ayudando al mantenimiento y la extensión futuros, pero podría llevar bastante tiempo. Además, nunca estaré completamente satisfecho con ningún código que escribo de todos modos ...

Entonces, ¿qué piensa stackoverflow? ¿Limpiar el código o trabajar en las características?

+0

Gracias a todos por el consejo. Es realmente apreciado. Creo que voy a refactorizar mientras esté fresco en mi mente y mientras pueda dedicarle algo de tiempo. Puede que no tenga la oportunidad de hacerlo más tarde y el código es bastante difícil para refactorizar incrementalmente tal como está, lo que definitivamente no es bueno. ¡Gracias de nuevo! – Dan

+0

Un artículo posiblemente relevante: http://www.joelonsoftware.com/articles/fog0000000069.html –

+0

Gracias por eso. Afortunadamente, hay grandes secciones de código con las que estoy contento y que puedo volver a utilizar tal como están, por lo que definitivamente no es una reescritura completa. Si fue "completa reescritura vs continuar", no habría hecho la pregunta y simplemente continué. – Dan

Respuesta

6

Yo diría que si sientes la necesidad de refactorizar este código, entonces aún no lo has "completado".

Creo que es mucho mejor refactorizar sobre la marcha (suponiendo que tenga pruebas y siga el método rojo, verde, refactor de TDD), pero dado dónde se encuentra, no tiene mucho sentido decirle lo que "debería" " haber hecho.

Le aconsejo que lo refactorice. Sin embargo, el pragmático en mí daría la siguiente advertencia: el código nunca se "hace", por lo que timebox su refactorización esta vez (así que concédase una o dos horas, siga aprobando las pruebas y luego llámese "hecho por ahora") y luego, cada vez que toque el código, siga el boy scout rule y limpie el código un poco cada vez que lo registre. Con el tiempo, va a limpiar este código, y en el futuro, trate de refactorizar sobre la marcha, como parte del proceso de desarrollo, en lugar de una gran tarea al final del desarrollo.

+0

Un gran consejo en general, pero debido a mis puntos 2, 3 y 4, refactorizar solo un poco ahora y un poco más tarde es ... difícil, pero creo que esa es mi respuesta: necesito asegurarme de que puedo mejorar el código gradualmente. . Ahora mismo no puedo. – Dan

+0

@Dan: "Cuando codificas, cuando piensas que voy a refacturar más adelante, tienes una deuda. Y pagarás una por una" Un gran consejo. – nXqd

1

¿Es probable que otros estén sujetos a los horrores que usted ha forjado? Cuando tengo un código horrible a punto de ser lanzado en la naturaleza, tiendo a limpiarlo, pero si soy el único que va a ser sometido a mantenimiento y lidiar con él, lo dejaré festejar por un tiempo ya que funciona lo suficientemente bien y si me siento un poco, incluso puedo encontrar una solución mejor de la que hubiera tenido si me hubiera inspirado para "arreglarla" de inmediato.

En mi humilde opinión, por supuesto.

+0

Estoy pidiendo opiniones de la gente, ¡así que gracias!:-) No es probable que alguien vea el código para los próximos meses de todos modos, pero se construirá una gran cantidad de código además de eso, por lo que será mucho más difícil solucionarlo más tarde. Al mismo tiempo, funciona bien y es lo suficientemente rápido y su limpieza puede tomar tiempo que podría ser mejor gastar en otro lado, especialmente si rediseño para corregir deficiencias (como el código de administración de memoria) e incluso después de todo eso, es poco probable que Alguna vez estará 100% feliz con eso. Es por eso que estoy buscando ver lo que otras personas piensan. Motivarme de una forma u otra. – Dan

+0

OK, "se creará una gran cantidad de código encima" es información no divulgada previamente que cambia totalmente la ecuación. Ciertamente, la refactorización de la interfaz que usará el código del cliente, para hacer que esa interfaz soporte una "buena implementación" es una alta prioridad. –

+0

Estoy muy contento con la interfaz. Puede haber algunas pequeñas mejoras que podría hacer, pero en general es bueno. Supongo que las funciones internas se volvieron un tanto complejas en el sentido de mantener la interfaz estable, por lo que puede valer la pena volver a evaluarlo y ver si puedo simplificar cómo se conecta todo, especialmente ahora antes de que el código empiece a usar la interfaz. – Dan

1

"Algunas clases se filtran detalles de implementación (por ejemplo, he cambiado un mapa a un mapa hash antes y me encontré tener que modificar el código en otros archivos de código fuente para hacer el trabajo de cambio)"

Ésta es una razón suficiente para que valga la pena el esfuerzo imo. Por definición, es algo que los usuarios realmente notarán.

Algunas otras cosas importantes a considerar:

  • mantenibilidad - ¿Qué tan fácil será para corregir los errores inevitables que surgen?
  • Testabilidad: Trabajar el código en una forma más comprobable es una excelente manera de refactorizarlo. Agregar pruebas unitarias significa que puede cambiarlo y saber exactamente qué se rompe.
  • Capacidad de ampliación: ¿cree que alguna vez tendrá que agregar nuevas funciones?

Realmente, el único momento en el que no querrá considerar la mejora de su código es que, si está seguro, nunca más tendrá que volver a tocarlo (es decir CASI nunca).

+0

Gracias por eso. Grandes puntos. La expansibilidad está cubierta, por lo que no es un problema, pero vale la pena considerar la capacidad de mantenimiento y la capacidad de prueba. Me di cuenta de que podría ser una pesadilla lidiar con ellos debido a mi tercer punto. Supongo que sentí lo que dijiste, pero tienes ese molesto "trabajo en algo que te beneficia ahora", lo que creo que es probablemente lo que no debes hacer. ¡Gracias por el consejo! – Dan

0

Yo diría refactor siempre. Cada línea extra de código y todos esos pequeños problemas molestos volverán y te morderán el culo.

En el futuro, incluso podría refactorizar sobre la marcha: el tiempo nunca se detiene, incluso si lo tira, todavía habrá aprendido a hacer algo mejor.

2

Por lo que puedo decir, eres un poco perfeccionista y quieres que tu código sea lo más limpio posible, un rasgo valioso, pero en los negocios debes considerar el análisis de costo beneficio de lo que estás haciendo. Si el código está a la altura de las especificaciones y existen funciones más importantes para trabajar, tome nota de que le gustaría refactorizar el código y seguir adelante. Si alguna vez tienes algo de tiempo libre, puedes volver a él.

1

"Me acaba de terminar ..."

Parece que usted está escribiendo activamente código heredado, que no es una buena cosa. Ha resaltado muchas razones por las que podría querer refactorizar su código, pero como dice que funciona según las especificaciones, no hay un costo actual para mantenerlo como está.

En el lado positivo, la forma en que funciona el código (y debería funcionar) es probablemente nuevo en su mente, por lo que la refacturación ahora es más barata que la refactorización posterior; por otro lado, refactorizar más adelante con una solicitud de cambio real en mente aumentará la probabilidad de refactorizar en la dirección correcta.

En el futuro, consideraría seriamente desacelerar y pensar en el futuro mientras escribe el código. Refactorizar (o factorizar) a medida que avanza es mucho más fácil y no tiene la presión de "pero funciona" para mantener las cosas como están.

Reloj. Si nota que una clase parece estar ganando múltiples responsabilidades, deténgase y piense si necesita separar las responsabilidades en clases separadas.

Si observa que desea acceder a las partes internas de una clase, deténgase y averigüe cuál debe ser la interfaz entre las clases para que no necesite conocer y utilizar una clase concreta 'interna'.

+0

"Consideraría seriamente desacelerar y pensar en el futuro" - Lo hice y el código es bastante sólido y podría salirse con la suya sin demasiadas consecuencias para el código futuro (es decir, como un todo, el código es razonablemente auto -contenido). Pero, nunca se puede predecir lo que sucederá y puede ser mucho más costoso cambiar las cosas más adelante. La razón por la que formulé esta pregunta es porque he intentado zambullirme y limpiar el código porque ya he dedicado mucho tiempo a esto y si lo limpio ahora, gasto más. Por supuesto, eso podría ser lo mejor que se puede hacer en esta etapa. – Dan

+0

Si disminuyó la velocidad y pensó en el futuro y aún así terminó con clases inmersas en las otras partes internas y acumulando múltiples responsabilidades, entonces es probable que sea una señal de que todavía no tiene el diseño correcto. Esto no es inesperado, ya que obtener todo menos el diseño de clase más simple la primera vez es extremadamente difícil. Debes reducir la velocidad _incluso más_. Solo cuando llegue a un ritmo en el que pueda detectar y corregir su diseño antes de completar cada clase, llegará a la etapa en que su código no necesita refactorización tan pronto como lo haya completado. –

2

Si este código ya ha pasado el control de calidad, entonces quizás debería liberarlo tal cual y aceptar el código de la deuda. Si hay tiempo para gastar en eso, elegiría las piezas más notables y trataré de refactorizarlas, por ejemplo, concluyendo su implementación de hashtable. De lo contrario, haga una lista de cosas para mejorar y trabaje con sus futuras solicitudes de cambio.

Es bueno saber que nunca se sentirá satisfecho con el código. Recuerda eso para que no permitas que tu perfeccionismo se interponga en el lanzamiento regular.

3

Refaccionarlo ahora.

Dado que incluso está considerando la refacturación, parece que puede dedicar tiempo a ello. Si lo deja para más adelante, es probable que se ocupe de otras cosas y pierda esta oportunidad. Cuando los horarios se vuelven ajustados, los clientes pueden entender si necesita tiempo adicional para terminar una nueva función. Son mucho menos comprensivos cuando les dices que necesitas más tiempo para reescribir algo que ya está funcionando.

+0

Buen punto, gracias – Dan

0

Si tiene un conjunto de pruebas para verificar que su código funciona ahora, y después de su refactorización, le diría que, si tiene tiempo, corríjalo, ya que le costará más tiempo más tarde. Pero, si el tiempo apremia, entonces es perfectamente aceptable dejar esto como un código de deuda y volver a él en un momento mejor. Si el código funciona, puede cortar un lanzamiento perfectamente bueno con él ahora y volver más tarde cuando tenga más tiempo y menos presión.

1

Trabaja en los aspectos que darán lugar a errores más adelante. No dores.

2

En uno de sus comentarios, dijo "se construirá una gran cantidad de código encima". Usted dice que funciona correctamente, pero si es descuidado y funciona con malos principios de diseño, será cada vez más difícil cambiar algo a medida que pase el tiempo. En general, cuanto más importante es una pieza de código, mejor diseñado debe ser. Obtenga el diseño justo antes de agregar cosas encima (dentro de lo razonable).

Además, uno de los objetivos principales de escribir software (en mi opinión) es gestionar la complejidad. Si lo hiciste funcionar, tienes la mitad del trabajo hecho. La otra mitad MUY importante del trabajo es hacer las cosas razonablemente fáciles de entender y cambiar. Sin eso, creas un software que no responde bien a los cambios. Y el software necesita cambiar. A menudo.

Mi empresa tiene algún software que se construyó de manera muy descuidada en su infancia, y cada pequeño cambio que se agregaba a lo largo de los años se basaba descuidadamente en la ya de por sí descuidada base. Ahora es cuando la gente está pidiendo cosas simples (como la compatibilidad con la rueda del mouse para desplazarse) y el desarrollador principal responde con "No sabes cuánto tendría que cambiar para poder hacer eso". Sin embargo, si el código fue limpiado mientras se escribía (o poco después), no tendríamos este problema.

Si tiene un código descuidado y mal diseñado ahora, le morderá en el trasero más tarde. Especialmente si se escribirán muchos otros códigos encima.

0

Si tiene un conjunto de pruebas automatizadas que verifica que su código funciona correctamente, maravilloso, adelante y refactorícelo; ahora es el mejor momento, mientras está fresco en tu mente. Si no lo hace, use este tiempo, mientras esté fresco en su mente, para escribir las pruebas. Si tiene tiempo para solo realizar pruebas o refactorizar: escriba las pruebas para que sea más fácil (algunos dirán que sea posible) refactorizar más adelante.

El ciclo TDD es RED-GREEN-REFACTOR, y dice que no está "terminado" hasta que el diseño es bueno - es decir, hasta que no necesita refactorización más.

1

En realidad, no es tan complicado. Simplemente siga esta regla:

Código de refactor a menudo. Refactor cada vez que sea posible.

Por lo tanto, si cree que puede refactorizar su código, debe hacerlo ahora antes de que se vuelva mucho más complicado cuando todos los códigos se ajusten entre sí.

1

Ahora tiene su implementación de referencia. Si te sientes motivado, prueba una refactorización.No tengas miedo de tirar y seguir adelante o reiniciar.

Quizás rehaga la API/interfaz basada en el código de consumidor y dirija la refactorización hacia arriba.

No debería preocuparse realmente por tener miembros de datos públicos. La gente escribe muchos accesorios que terminan siendo tipeados por diversión y, francamente, la fuente de errores realmente estúpidos y frustrantes (el único código sin errores es el código que nunca se ha escrito). Eso es irritante. Solo encapsula para proteger estados frágiles (cuando el estado de datos del miembro está acoplado).

+0

En cuanto a los datos públicos, no se preocupe, no soy fanático de los usuarios y creo que los objetos deberían operar con sus propios datos y no hurgar en los datos de otros objetos siempre que sea posible. – Dan

1

Entonces, ¿qué piensa stackoverflow? ¿Limpiar código o trabajar en funciones?

La pregunta que veo aquí es qué precio tendrá que pagar si compara el refactor con el precio que paga si no lo hace.

Si lo deja como está, le costará cualquier mantenimiento (tiempo adicional, mayor posibilidad de agregar nuevos defectos con cada cambio) y reputación como desarrollador (cualquier otro programador que lo investigue puede probablemente maldecirle:)).

Si puede garantizar que nadie volverá a tocar ese código nunca (no porque sea demasiado horrible;)) puede dejarlo como está. (En más de 10 años como desarrollador, nunca he encontrado una situación en la que pueda garantizar esto).

En todos los demás casos, es mejor que refactorice.

Parecen excelentes razones para refactor y código limpio, ayudando futuro mantenimiento y la ampliación, pero podría ser bastante tiempo.

No es necesario que el código sea perfecto. De hecho, debe tomar un cambio a la vez, y refactorizar en iteraciones, y si lo hace bien, no afectará ningún otro código.

Esto significa que debe poder refactorizar dependiendo de su tiempo disponible, y no al revés.

Por ejemplo, si solo divide una de sus clases multipropósito en tres o cuatro clases separadas y actualiza el código con eso, tendrá el resto del código funcionando igual que antes. Si estás fuera de tiempo cuando terminaste este cambio, puedes dejarlo tal como está (un poco más claro, en una sola área).

Si tiene más tiempo, puede realizar la próxima refactorización y repetir.

Además, si utiliza un sistema de control de fuente de ramificación, puede incluso trabajar en paralelo para refactorizar y agregar nuevas características con un costo adicional relativamente bajo (y continuar refactorizando a medida que tenga más tiempo).

Cuestiones relacionadas