udemy software refactorización herramientas código arquitectura refactoring code-smell

refactoring - software - ¿Cómo te detienes de refactorizar el código de trabajo pero horrible?



udemy arquitectura de software (30)

Tengo este problema No puedo dejar de refactorizar el código existente que funciona pero, en mi opinión (y quizás objetivamente), está mal diseñado o contiene otros "olores de código". Esto puede tener un efecto negativo significativo en mi productividad inmediata. Pero en última instancia, será una gran ayuda de mantenimiento.

Si también sufres de esta "aflicción", ¿cómo te restringes? O, al menos, administre la refactorización para evitar tener que alterar grandes porciones de código existente para que pueda mantenerse a largo plazo.


"Refactorizar el código existente que funciona": esto es obviamente una opinión minoritaria aquí, pero esto es una completa pérdida de tiempo. Es bueno que estés intentando restringirte.

Si crees que el código es tan malo, encuentra un error no trivial antes de refactorizarlo . Luego agrega una prueba automatizada para ese error. Sólo entonces permítete refactorizar.

La actitud de que después de la refactorización del código de trabajo "He dejado el código mejor" es a menudo una arrogancia del programador. En muchos casos, realmente no sabe que dejó el código mejor, simplemente cree que lo hizo. Si ni siquiera corrigiste un error o agregaste funcionalidad, ¿por qué correr el riesgo de estar equivocado?


¿Está habitualmente refactorizando el código escrito por otros, o el código que escribió hace seis meses mientras estaba en un tipo diferente de ''zona''? Si su respuesta es la última, es muy bueno que no pinte o haga esculturas para ganarse la vida ... lo arrestarían por irrumpir en las casas de la gente para "terminar" sus obras mucho después de que fueron compradas.

Soy un gran fan de Doxygen , lo que me permite pegar un simple:

/** * Function to rule the world * @todo make this actually work */

Luego, le digo a Doxygen que genere listas de tareas basadas en mis comentarios. Esto ayuda a garantizar que las funciones que huelen a pies no se olviden.

Miro hacia atrás a cosas que hice hace dos meses y digo "Ick, ¿qué diablos estaba pensando? Debería hacerlo de esta manera ...", lo que en realidad nunca consigue un consumible por la puerta.

Si el código de otras personas con el que constantemente redimensionas, intenta preguntarte si hacerlo realmente mejora el código. Si puede volver a factorizar una función, es bastante obvio que entiende la función ... así que, a menos que obtenga un beneficio (más que trivial) de reescribirlo, ponga un comentario encima y vuelva más tarde.

Una vez que esté acostumbrado a todo el código y haya pensado en cómo hacer las cosas más coherentes ... luego sumérjase. De lo contrario, terminará re-factorizando su re-factorización anterior (qué ciclo vicioso que tomó años). ¡perfeccionar!).

Por lo tanto, a menos que esté en línea, o que se use en todo el lugar ... trate de evitar jugar con él a menos que realmente lo necesite. Más tarde, vuelva y golpee su lista de TODO en un solo golpe ... cuando hacerlo sea su único objetivo inmediato.


A menudo, la refactorización puede reducir o eliminar la necesidad de realizar el trabajo real asignado. Si está solucionando un error, la refactorización es un buen lugar, asumiendo que hay pruebas implementadas. En menor medida, se pueden agregar nuevas funciones con una simple refactorización del código para hacerlo un poco más limpio o más eficiente, y luego verá que la función ya estaba allí y cómo hacer que el usuario la habilite.

La respuesta corta, sin embargo, es que no refactoriza el código que funciona a menos que haya una necesidad apremiante. Una buena lista de verificación es:

  • ¿Trabajaré con este código diariamente durante un período prolongado Y soy la ÚNICA persona que lo será?
  • ¿Es el código tan malo que no se puede entender correctamente? Por lo general, me parece que simplemente estoy sufriendo de un caso de síndrome no inventado aquí (la cosa en la que la solución de otra persona es perfectamente buena no es cómo lo habría hecho, así que quiero hacerlo de nuevo sin ninguna ganancia real, excepto el orgullo).
  • ¿Es la arquitectura no capaz de soportar dicho trabajo nuevo (característica, corrección de errores, etc.)?
  • ¿Es el código tan incestuoso que cambiar algunas cosas pequeñas tiene un efecto de onda masiva de errores de seguimiento?

Si responde sí a cualquiera de esas preguntas, entonces podría ser el momento de refactorizar.


Antes de comenzar a refactorizar, necesita tener pruebas de unidad completas para él, y a nadie le gusta escribir pruebas de unidad :)


Creo un problema en nuestro rastreador de problemas (o podrías usar una nota post-it) sobre cómo arreglar ese código y luego me olvido del problema.

Esto permite que todos sepan que hay un código malo que podría causar algunos problemas, pero también me permite seguir trabajando en mi tarea actual sin demasiadas distracciones.


Decida en función del "beneficio final" en lugar de escuchar su "voz interior". Si ese código se reutilizará muy a menudo, entonces podría tener sentido refactorizarlo. Sin embargo, generalmente trato de ignorar mi odio por el "olor a código" y realmente me concentro en la relación beneficio / pérdida de tiempo de la refactorización en cuestión.


Deja de preocuparte.

Quiero decir, CMON, todos somos ingenieros aquí, y a los ingenieros les encanta publicar EL CÓDIGO PERFECTO MÁS ABSOLUTO DE TODOS. Y vamos a seguir intentando. Y no nos alegraremos con nuestro trabajo, a menos que sepamos que todo lo que hemos tocado es TMAPCE. Además, solo sabemos que esta manera es mucho mejor ...

Por lo tanto, la única forma real de no seguir intentando refactorizar un poquito a la vez, es no preocuparse por su trabajo.
(Como nota al margen, esto me sucedió una vez. Fue muy triste ... hasta que me mudé a otro trabajo).


El viejo adagio acerca de las suposiciones viene a la mente cuando surge la tentación de arreglar el código que no está roto. Trabajar en un código feo que tiene muchos usuarios puede afectar la productividad de muchas personas, especialmente si una solución funciona en un entorno pero no en otro. Cualquiera que haya trabajado en sitios web de intranet sabe bien cómo convertir JScript a JavaScript puede tener muchos efectos secundarios imprevistos.


Es realmente fácil.

Todo lo que modifiquemos, tenemos que elaborar un plan de prueba escrito que sea entendido y revisado por un ingeniero de control de calidad. No modificar cosas simplifica drásticamente el hecho de que se libere el código. Por lo tanto, a menos que esté tocando esa pieza de código por alguna otra razón, cualquier tipo de refactorización es prácticamente un no-no.

EDITAR: Incluso si su compañía no tiene dicha política, solo recuerde que necesita probar lo que cambia . Calcule la cantidad de tiempo que necesitará para probar sus cambios.

Respondiendo a la pregunta "¿Cuál es el valor agregado?" tambien ayuda


Estoy de acuerdo, es tentador, pero si te concentras en él, ¡es posible que no realices tu trabajo real!

Dos sugerencias:

  1. Marque el código para que pueda volver a él más tarde para limpiarlo (use el comentario TODO o algo similar)
  2. Agregue un error a su sistema de seguimiento de errores que indica un código maloliente. Tal vez usted puede obtener el tiempo programado para arreglar un grupo de ellos.

He sufrido de esto en el pasado, y microgestiono mi "mal" buen hábito.

Básicamente, hago lo siguiente:

  • Tengo dos instancias separadas de nuestro árbol fuente en un momento dado.
  • Si tengo un refactor masivo que no es realmente la máxima prioridad, lo hackeo en la segunda rama.
  • Luego seguiré trabajando lejos en mi primera rama, y ​​solo mantendré la segunda rama, haciendo pequeñas pruebas mientras lo pienso para asegurarme de que no haya roto nada.
  • Luego lo registraré una vez que esté seguro, y puedo cronometrarlo con una desaceleración en nuestro ciclo de producción (es decir, ¡no lo haga justo antes del hito!).

Con toda honestidad, esa refactorización "importante" nunca ocurre con frecuencia, por lo general, si tengo que hacerlo, ya se me ha asignado una tarea. Aún así, las pocas veces que he hecho eso, ha sido útil. Ideal si puedes hacer una rama para ello, y simplemente seguir integrando los cambios.

Para las cosas más pequeñas, a menudo mantendré esos cambios localmente en mi rama ''principal'' y los ejecutaré localmente por un tiempo. En el momento en que cualquier cosa en la que estoy trabajando toca esos archivos, reviso todo el cambio. Nuestro proceso actualmente incluye un sistema de "verificación de amigos" antes de los registros, por lo general, es algo que, de todos modos, es algo que podría compensarlo.

De todos modos Puede ser más un volcado de cerebros de lo que cuidas, pero espero que te sirva de ayuda.


Intento refactorizar de forma poco sistemática. Es decir, cuando necesito agregar una nueva funcionalidad, la refactorizo ​​de tal manera que sea más fácil agregar esa funcionalidad en primer lugar. Esto hace que la refactorización sea un proceso más lento, pero tiende a hacer que sea más fácil agregar cambios.


La respuesta con la calificación más alta que lo exhorta a seguir adelante y refactorizar es buena para muchos casos, pero también algo simplista. (Probablemente lo comentaré, pero no tengo privilegios para hacerlo, espero que esto también funcione de manera independiente).

Si trabaja con un sistema grande (legado) que ha estado en desarrollo durante años y años, siempre hay demasiadas cosas para refactorizar a la vez (a menos que haya sido excepcionalmente riguroso en todos esos años, lo cual no creo :). Por lo tanto, simplemente no puede obtener todos los tangenciales que le gustaría; eso es un hecho de la vida que tienes que aceptar. De lo contrario, siempre se perderían días al final de la limpieza de todo, cuando el cambio original (corrección de errores o mejora) podría haberse realizado en mucho menos tiempo (¡pruebas incluidas y algunas refactorizaciones incluidas!).

Entonces, usualmente tienes que dibujar una línea en algún lugar; solo refactoriza el código que concierne directamente a la tarea en cuestión, y solo si no toma una cantidad desproporcionada de tiempo .

En cuanto a las revisiones más grandes de la arquitectura, que ciertamente no se pueden evitar al tratar con los grandes códigos de base mencionados anteriormente. Tendrá que seleccionar los que se consideren más críticos, y asignarlos y priorizarlos en su proceso lo suficientemente alto como para que realmente se realicen, incluso cuando estos cambios no agreguen valor externo por sí mismos (es decir, solo un valor inmediato para los desarrolladores, al hacer el Código más manejable). (Ahora, si esto no fuera posible, si los tomadores de decisiones no son lo suficientemente inteligentes como para ver que es necesario usar el tiempo en dichas mejoras, bueno, entonces su base de código simplemente está condenada a largo plazo. :))

Si no tiene ninguna restricción en el desarrollo de software comercial, su millaje puede variar. ;)

Por cierto, buena pregunta: yo también me encuentro pensando en dónde dibujar la línea con bastante frecuencia.


La respuesta es que no. El hecho de que el código funcione no significa que siempre funcionará. Código malo es código malo

Nos refaccionamos para hacer que el código sea más legible, más fácil de mantener y para garantizar la confiabilidad.

Mientras mantengas la lógica del código anterior, debería seguir funcionando, además de tener la ventaja adicional de ser un mejor código en general.

Siempre trato de dejar el código mejor de lo que lo encontré.


La siguiente regla de Boy Scout se aplica muy bien al código (mal) y al diseño:
Deja el campamento más limpio de lo que lo encontraste!


La toma de Martin Fowler sobre el tema:

Su esencia es aplicar una serie de pequeñas transformaciones que preservan el comportamiento, cada una de las cuales es "demasiado pequeña para valer la pena". Sin embargo, el efecto acumulativo de cada una de estas transformaciones es bastante significativo. Al hacerlos en pequeños pasos, se reduce el riesgo de introducir errores. También evita que se rompa el sistema mientras realiza la reestructuración, lo que le permite refactorizar gradualmente un sistema durante un período prolongado de tiempo. - Martin Fowler

Así que cuando cambias grandes trozos de código a la vez, realmente no lo llamaría una verdadera refactorización. Más como reescritura total de segmentos de código particulares. Los cambios deben ser graduales y "casi no vale la pena hacerlo". Después de un tiempo notarás su efecto acumulativo.

He escuchado que una definición de "código heredado" es código sin pruebas automatizadas. Si está trabajando en código sin pruebas, sugeriría escribir pruebas antes de realizar cambios significativos. Si tiene pruebas en su lugar, puede refactorizarlas sin temor a romper ese horrible código porque tiene sus pruebas para respaldarlo y garantizar que todo siga funcionando.



Lo que funcionó para mí fue ser despedido de un trabajo por ello. : /

Dicho esto, mi problema básico era doble:

  1. Estaba refaccionando el código en el que nadie me había pedido que trabajara.

  2. Me resultó demasiado difícil realizar pruebas, así que lo hice sin ellas. Que, naturalmente, rompió algunas cosas.

Lo que aprendí fue:

  1. No trabaje en un código en el que no necesita trabajar, y que nadie le haya pedido que trabaje. Es fácil recordar esto ahora, dadas las consecuencias en el pasado.

  2. Cuando necesite refactorizar el código en el que se supone que debe trabajar, haga pruebas, pero no tiene que ser automatizado.

Después de leer demasiadas cosas de TDD, tendía a pensar en las pruebas automatizadas como el único tipo de prueba que existe. En realidad, incluso un puñado de declaraciones Debug.Print puede ser una prueba decente para determinar si la funcionalidad se mantiene constante.

Si tiene que refactorizar y no puede hacer pruebas automatizadas, debe hacer algún tipo de prueba, ya sea imprimir texto, un script de UI o lo que sea. Cualquier prueba efectiva es mejor que ninguna prueba en absoluto.


No diré que ''sufro'' por esta aflicción, pero ... ¡te escucho hermano!

Creo que debemos dejar el código en mejor estado que cuando lo dejamos. Así que tu búsqueda es noble. Llamémosla ''refactoritis''.

Supongo que todos estamos de acuerdo con los beneficios de la refactorización y que eso depende del código en cuanto a qué tan necesario es ... Para el quid de la pregunta, entonces ...

Una de las formas en que me reprimo es tratar de sentirme seguro sabiendo que está listo para ser reparado. Y sé cómo arreglarlo. Y en lugar de restringirme por completo, solo hago un paso, como "Extraer método". Y deje la siguiente "ronda" de arreglos para más adelante (tal vez deberíamos llamar "segundo servicio" o "postre" si está seguro de que es el último paso). Luego pégale un TODO grande en él, para que puedas encontrarlo nuevamente. Y aclarar lo que aún queda por hacer.

Gracias por la interesante pregunta. Me pregunto si necesitamos un grupo de ''Refactorors Anonymous'' donde podamos sentarnos en un círculo y compartir nuestros problemas e historias de guerra.


Por lo general, no toco ningún código heredado A MENOS QUE me pidan que lo amplíe ampliamente. Si el código es tan malo que agregar una característica en cascada en todos los lugares, tienes una razón real para volver a diseñarlo.

Además, existe un riesgo muy, muy real de que introduzcas errores que se han solucionado en el problema heredado. Eso te hará lucir poco profesional.

La única manera buena, IMO, es refactorizar lentamente el código antiguo fuera de producción. Luego, cuando creas que la funcionalidad es la misma, revisa los errores resueltos y asegúrate de que no vuelvan a aparecer errores antiguos.

Extiéndalo a control de calidad y presumir de su gestión, preferiblemente con alguna característica nueva o dos. Si el nuevo código tiene un rendimiento mucho más rápido, ese es un punto de venta definitivo.

En general, tendrá dos problemas: falta de tiempo total y administración que empuja en contra de asignar tiempo al refactor. Si ninguno de ellos es un problema, considérese muy afortunado.

Edición: Joel Spolsky tiene la mejor respuesta , creo.


Pregunta perfectamente válida.

Lo utilizo para encontrar que estoy comenzando a refactorizar el código automáticamente cuando lo encontré. Cuando estoy dentro de la operación de más o menos 5 minutos (revisando cosas, etc.) de repente tengo la sensación de que lo que estoy haciendo va a tomar más tiempo del esperado. En este punto me pregunto, ¿vale la pena el esfuerzo para bajar por este agujero de conejo? Para ser honesto, a veces lo es, pero la mayoría de las veces no lo es, y después de un tiempo te das cuenta de que quieres reescribir todo el sistema, ¡solo mientras lo haces!

Esto me llevó al hábito de preguntarme continuamente: ¿el código que estoy escribiendo ahora me ayudará a realizar esta tarea en un tiempo razonable? ¿Estoy "perdiendo" el tiempo de la empresa haciendo esta refactorización mientras hay elementos pendientes que son mucho más altos en la lista de prioridades?

He visto programadores que ni siquiera se dan cuenta de que lo están haciendo. Trabajarán durante días y días para obtener el código en un estado en el que sienten que ahora pueden comenzar a implementar nuevas funciones o realizar correcciones de errores. No pueden distinguir entre refactorizar y pasar tiempo en el tema asignado.

Lo que hago es simplemente comentar lo que quiero hacer más adelante, y simplemente trabajar con el sistema existente, ¡no importa cuán feo sea! Esto me permite romper menos cosas y, de hecho, revisar mi lista de cosas para hacer mucho más rápido. (No hacemos TDD ... todavía)

Una vez que encuentres el tiempo, vuelve y refactoriza.


Primero, debe darse cuenta y aceptar que la única razón por la que el código incorrecto importa es si necesita ser leído y / o modificado. Solo necesita ser leído y / o modificado si está buscando un error o agregando funcionalidad. Así que solo toca el código si estás reparado o mejorado. Por lo tanto, si se encuentra con algunas declaraciones anidadas de if-then-else, o una variable o método mal llamado, déjelo solo a menos que necesite entender o cambiar ese código para finalizar la tarea en la que está trabajando. Si tiene que cambiar el código, refactorícelo lo suficiente para que el código sea comprensible y el cambio sea más fácil de hacer, pero no más.


Si estoy trabajando en una tarea, no dejo que nada se interponga, es muy fácil dejarse llevar. Cualquier cosa que parezca que necesita trabajo, entonces probablemente lo haga, pero tal vez no de inmediato - tome una nota / agréguela a su rastreador de errores.


Solía ​​refactorizar el código cada vez que encontraba algo que no me gustaba, pero ya no. Encontré por experiencia que simplemente no vale la pena. Hay mejores cosas en las que podrías pasar tu tiempo.

La razón principal por la que ya no me refactorizo ​​es el riesgo de introducir un nuevo error. Cuanto peor es el código anterior, mayor es la probabilidad de que cometa un error. Por ejemplo, el código antiguo podría tener un efecto secundario no deseado. Eso podría considerarse un error de codificación, y lo eliminaría en su reescritura. Sin embargo, el código que llama a su función reescrita puede depender de ese efecto secundario.

Trabajo en un montón de código legado realmente feo que en su mayoría no tiene comentarios y para el que no hay especificaciones. El código simplemente hace lo que hace, y nadie puede decir realmente por qué. Sólo saben que parece funcionar. Por horrible que sea, este código hace su trabajo, así que es mejor dejarlo solo.

Dicho esto, creo que el código malo debe ser reescrito. Simplemente no creo que los programadores deban hacer este tipo de cosas por su cuenta. Debe tratarse como un proyecto, con alcance definido, líneas de tiempo, planes de prueba, etc., al igual que la implementación de una nueva característica.


Solo quería agregar que si el proyecto en cuestión está respaldado por pruebas unitarias, entonces la refactorización tendrá un riesgo considerablemente menor y tendrá un grado menor de costo de productividad (porque sabrá exactamente cuándo estará listo). incorrecto).

Todavía hay un costo / beneficio por hacer, pero en principio estaría de acuerdo con Longhorn en que no deberías detenerte.


Tengo problemas para descifrar el código maloliente, pero generalmente postergaré la limpieza y la refactorización hasta que tenga que hacer cambios, o si tengo algún tiempo de inactividad.

Hasta entonces, solo anotaré ideas para cambios en los comentarios.


Usualmente no me reprimo. Si encuentro una pieza defectuosa en el código en el que estoy trabajando, lo corrijo directamente.

Estoy trabajando en un software que se ha mantenido durante unos 10 años y que tendrá que funcionar al menos diez años más. En tal situación, cuanto más tiempo permanezca un olor de código en el código, más a menudo mis colegas desarrolladores y yo nos tropezaremos con él y perderemos el tiempo intentando resolverlo o inventar soluciones para él. Esto cuesta más dinero que solo hacer el trabajo ahora mismo.

Una excepción son los grandes problemas de diseño que tardan días en refactorizar. Si esos no obstruyen mi proyecto actual de manera significativa, lo agrego a nuestra lista de tareas de mantenimiento para trabajar en la refactorización como una tarea planificada en un futuro próximo.


Whoa, muchos de ustedes son un poco de OCD si saben lo que quiero decir. Creo que para CYA, si solo estás trabajando con el código base a corto plazo, entonces no te molestes en refactorizar. Pero si va a poseer este código a largo plazo, ¡adelante! Pero debe hacer una copia de seguridad de su nuevo código con pruebas unitarias, así como agregar pruebas unitarias al código heredado que afectará si las pruebas aún no existen.


Yo también sufro de refactoritis, y lo trato dirigiéndolo a un código que es el mío que otros han mantenido o el código de otras personas que tengo que mantener. Y al tratar con eso, me refiero a "verificar el control de versión cada hora a la hora para ver si alguien ha tocado mi código y si lo hizo, hacer una diferencia inmediata".


Yo priorizo

Cuando tengo algunos ciclos disponibles (ha),

Generalmente trato de re-factorizar el código que:

  • sería sensible para cualquier otra persona para trabajar,
  • en realidad necesitaría ser trabajado , lo que significa que se toca regularmente
  • que está en mal estado por razones de rendimiento o documentación, en ese orden.

Donde re-factoring agrega valor, lo hago. Tratar de alinear las nuevas características futuras para que se superpongan con la re-factorización hace que sea más fácil hacerlo bajo el capó.

¿Razones para no tocar nada que nos apetezca tocar?

  • A menudo, el código antiguo se ha reforzado para la entrada / salida, por más torpe que pueda ser, funciona.
  • Si no está roto, no lo hagas así.
  • Siempre debe haber algo nuevo y ordenado para trabajar, y codificar de la manera correcta. Las cosas viejas se volverán a factorizar con el tiempo a medida que se extiendan.