¿Dónde debería encajar la refactorización y la optimización del código en una línea de tiempo de proceso ágil y en cascada?

10

Parece existir esta noción entre el equipo de gestión del proyecto de que afirmar que "funciona" significa que debería considerarse 100% completo. La mayoría de los programadores saben que no siempre es así. Si estoy probando enfoques alternativos para que funcione una pieza de funcionalidad, eso no necesariamente significa que encontré la mejor solución, o no requerirá un poco de revisión después de revisar con otros desarrolladores. A menudo terminaré con algo, daré un paso atrás y luego me preguntaré qué puedo hacer mejor una vez que se cumplan las normas comerciales. ¿Debería este tiempo "puedo hacerlo mejor" encajar en algún lugar dentro de la línea de tiempo? Soy de la opinión de que el mejor enfoque es que siempre dejas el código mejor que cuando lo encontraste (hasta cierto punto), lo que podría significar una refactorización posterior al lanzamiento. Sin embargo,


fuente

Respuestas:

13

Hay un principio general que rige la necesidad de refactorizar y optimizar, tanto en cascada como en Agile: YAGNI (No lo vas a necesitar). Un segundo principio es el corolario del primero: "La optimización prematura es la raíz de todo mal", el equivalente de codificación del proverbio general "el enemigo de la excelencia es la perfección".

Tomemos los principios y apliquémoslos. Tiene el requisito de construir un algoritmo ETL que tome un archivo de un tipo particular, extraiga su información y luego la coloque en una base de datos. Su objetivo para esta semana (para nuestros propósitos, no importa si está en una tienda Agile o SDLC) es lograrlo.

Eres un tipo inteligente, y se te ha dado una idea del panorama general. Usted sabe que este no es el único tipo de archivo para el cual el proyecto necesitará un ETL. Por lo tanto, considera implementar este algoritmo ETL para que también funcione en otro tipo de archivo, que solo tiene pequeñas diferencias. Hacer esto violaría a YAGNI. Su trabajo no es desarrollar el algoritmo para ese otro archivo; es desarrollar el algoritmo para el archivo que se necesita para el final de la semana. Para cumplir con ese objetivo y pasar las pruebas de aceptación, debe desarrollar ese algoritmo y hacer que funcione correctamente. "No necesitará" el código adicional para que funcione con el otro archivo. Puede pensar que le ahorrará tiempo incorporarlo ahora, y puede que tenga razón, pero también puede estar terriblemente equivocado; Es posible que el algoritmo para el otro archivo deba usarse en un área del sistema en la que no se puede usar su código, o los requisitos para el nuevo archivo pueden ser diferentes a los suyos en formas que no conoce (en Agile, esos los requisitos pueden no existir todavía). Mientras tanto, ha perdido tiempo y ha aumentado innecesariamente la complejidad de su algoritmo.

Ahora, es la próxima semana, y como dudosa recompensa por su excelente trabajo en el primer algoritmo, se le ha encomendado la tarea de crear algoritmos para dos nuevos tipos de archivos. Ahora, usted necesita un código adicional para que su algoritmo funcione con más archivos. Puede extender su algoritmo existente usando un patrón de método de plantilla que usará un patrón básico con pasos individuales específicos de archivo, o simplemente puede derivar una interfaz común de su algoritmo existente, desarrollar dos nuevos que sigan la interfaz y conectarlos a un objeto que puede elegir qué algoritmo usar.

Durante el desarrollo, sabe que tiene el requisito de que el sistema pueda procesar 10 KB de datos sin procesar por segundo. Realiza una prueba de carga y encuentra que su algoritmo de borrador inicial maneja 8 KB / s. Bueno, eso no va a pasar los AAT. Echas un vistazo y ves que hay alguna estructura de bucle de complejidad O (mi Dios) en tu algoritmo; lo optimiza y obtiene 12 KB / s. "Bastante bien", piensas, "pero si tuviera un bucle tan pobre en el código, ¿qué más puedo depilar?". zumbido Acabas de violar la regla de "optimización prematura". Su código funciona y pasa todos los requisitos. Está "listo", hasta el momento en que los requisitos se actualicen para requerir 15 KB / s. Si eso sucede, ENTONCES, vuelve a extraer el código y busca cosas para mejorar.

Siga este proceso simple mientras desarrolla, ya sea en Agile o en SDLC tradicionales: "En el primer pase, haga que funcione. En el segundo pase, hágalo bonito. En el tercer pase, hágalo SÓLIDO". Lo que esto significa es que, cuando crea una línea de código por primera vez, haga que ese código haga su trabajo correctamente y sin errores, pero no preste demasiada atención a las reglas de diseño dentro de este código, ya que por todo lo que sabe ahora mismo ' Nunca volveré a tocar esta área. La próxima vez que visite esa línea de código, acaba de demostrar que está equivocado; ya no es una pieza única del sistema. Reformúlelo para facilitar la lectura, la concisión del código y / o los principios DRY (es posible que haya copiado algún código para hacer algo cinco veces; refactorícelo en un bucle y / o una llamada a un método). La tercera vez que trabajas en esa línea de código o alrededor de ella,

KeithS
fuente
3
¡+1 porque O(my God)-complexitysi nada más, me hizo reír!
Joel C
+1 para que funcione primero. Demasiadas personas intentan escribir patrones y optimizan prematuramente desde el principio.
Justin Shield
Creo que este es uno de los problemas más difíciles de superar como programador. Los ingenieros tienen un deseo innato de experimentar, desarrollar y refinar, pero al final del día, se le paga por la productividad. ¿De qué sirve un producto perfecto si pasa tanto tiempo y / o dinero que se cancela debido a excesos?
ToddR
Me gusta el enfoque pragmático, pero tengo un problema con "En la segunda pasada, que sea bonita": si la segunda pasada es un año después y no has asegurado que los nombres de variables y métodos son significativos y los números mágicos fueron reemplazados por constantes simbólicas Probablemente tenga problemas para entender el código. Como lidiar con esto? "Hacer que sea bonito" 1 hora después de "hacer que funcione" es mucho más barato que "hacerlo bonito" después de un mes o después de un año. Estoy de acuerdo en que "hacerlo bonito" cuando sea necesario el próximo cambio de código es útil si no se ha hecho "hacerlo bonito" en primer lugar.
k3b
En Agile / TDD, según mi experiencia, el segundo pase generalmente ocurre poco después del primero. En los SLDC de Waterfall-ish, tienes más razón; la función tiende a escribirse una vez y luego permanece allí hasta que llega la siguiente ronda de requisitos que toca ese método. Por lo tanto, algunas buenas prácticas de codificación deben suceder la primera vez, como el código de autodocumentación, para que cuando regrese un año después, pueda recordar qué hace el código y por qué lo escribió de esa manera.
KeithS
10

si funciona y ha sido probado, ¿por qué arreglarlo?

Esto puede ir en contra de su propio temperamento personal como ingeniero / programador, pero si está funcionando, ¿qué valor comercial tiene para continuar refinándolo? ¿Hará que sea más fácil de mantener con el tiempo? Si es así, trabajando bajo la metodología ágil, debería poder crear nuevos elementos en su cartera de pedidos para refinar y refactorizar su código existente, y esos serían priorizados con los otros elementos en la cartera de pedidos. Eso es parte del valor del proceso ágil: el equipo decide juntos qué es lo más importante y qué se hace a continuación.

Nuestro equipo también rastrea lo que llamamos "deuda técnica", por lo que si obtiene algo que funciona pero sabe que podría hacerse mejor, lo registra como deuda técnica. Usamos scrum, y a veces terminarás todo el trabajo en un sprint temprano (deberías terminar un poco temprano aproximadamente la mitad del tiempo si estás bastante cerca de las estimaciones), pero no tienes suficiente tiempo para hacer un trabajo completamente nuevo. historia de usuario, por lo que pasamos el tiempo extra para volver y reducir nuestra deuda técnica. No se rastrea formalmente como nuestras historias de usuario en nuestra cartera de pedidos, y podemos trabajar en ello cada vez que tengamos tiempo disponible.

También es más o menos un juicio de tu parte cuando llamas a la tarea "terminada"; Si no se siente cómodo con el estado en que se encuentra su código, no marque la tarea como completada.

Joel C
fuente
2
Me he hecho fanático del concepto de "deuda técnica", +1 por mencionarlo en este contexto.
Patrick Hughes
Se olvidó por completo de la idea de "deuda técnica"; buen plazo Pero, me enseñaron que todo lo que calificaba como "deuda técnica", lo que significa que requeriría ciclos de desarrollo significativos para refactorizar, debía evitarse; "hazlo ligero" todavía significaba "hazlo bien", simplemente no vayas "torre de marfil" en el código que puede ser único.
KeithS
5

¿Debería este tiempo "puedo hacerlo mejor" encajar en algún lugar dentro de la línea de tiempo?

Si.

Justo antes de comenzar a codificar el próximo lanzamiento.

No refactorizar basado en la "intuición".

Refactorización basada en las historias reales del próximo sprint.

S.Lott
fuente
2

No marque el código como 100% completo hasta que esté satisfecho con la refactorización. Solo tiene que evaluar constantemente el costo / beneficio de refactorizar el código porque si estudia lo suficiente, siempre verá formas de mejorar el código.

Yo uso el método refactor verde rojo de TDD. Entonces mi refactorización está integrada en mi desarrollo. Para grandes refactorizaciones, como cambiar el modelo subyacente o algo similar, conseguiría que la gerencia comprara el tiempo primero.

mpenrow
fuente
1
El código no está "100% completo" hasta que todos los productos en los que reside estén muertos. Al igual que usted no está "completo" como persona hasta que su corazón deja de latir permanentemente; siempre absorberá nueva información y se le pedirá que haga cosas específicas que nunca antes haya hecho, o que haga lo mismo de una manera nueva, más eficiente o menos costosa. Del mismo modo, su base de código SIEMPRE necesitará trabajo, nuevas características y correcciones antiguas, hasta que ya nadie use el software.
KeithS
2

La "refactorización posterior al lanzamiento" tiene un costo oculto en las pruebas de regresión y el tiempo de control de calidad que está ignorando, además de que conlleva el costo de oportunidad de no trabajar en errores reportados y características y cambios nuevos / solicitados. TANSTAAFL

Si vale la pena hacerlo, vale la pena hacer una tarea para obtener prioridad a través de su proceso normal y no como una excepción especial. Usted es parte de un equipo, después de todo, y trabaja en objetivos comunes y extiende arbitrariamente su horario para acomodar la fijación del código de trabajo también los afecta.

Entonces, para una respuesta real: si sabe que querrá refactorizar, programe ese tiempo como parte de la tarea. Si está haciendo scrum / agile, entonces el cuadro de tiempo es una tarea de limpieza. Si eres cascada / espiral, haz que el refactor sea parte del proceso para revisar el código y aceptar los módulos.

Patrick Hughes
fuente
0

Si estoy probando enfoques alternativos para que funcione una pieza de funcionalidad, eso no necesariamente significa que encontré la mejor solución,

... En cuyo caso aún no está 100% listo ...

o no requerirá un poco de revisión después de revisar con otros desarrolladores.

Si las revisiones de código y el reproceso posterior son parte de su ciclo de vida de desarrollo, nuevamente la característica no se realiza hasta que todos estos hayan finalizado.

A menudo terminaré con algo, daré un paso atrás y luego me preguntaré qué puedo hacer mejor una vez que se cumplan las normas comerciales. ¿Debería este tiempo "puedo hacerlo mejor" encajar en algún lugar dentro de la línea de tiempo?

Depende. Si significa refactorizar, debería ser parte de la tarea de desarrollo original. Si significa experimentar con un algoritmo potencialmente mejor, podría ser una tarea separada.

Soy de la opinión de que el mejor enfoque es que siempre dejas el código mejor que cuando lo encontraste (hasta cierto punto), lo que podría significar una refactorización posterior al lanzamiento. Sin embargo, los equipos de proyecto a menudo se sienten extremadamente incómodos con este enfoque porque, una vez más, si funciona y se ha probado, ¿por qué solucionarlo?

En resumen, porque el código puede romperse en muchos niveles.

Una cosa es que funciona en este momento. Es algo completamente diferente si es limpio, ampliable y mantenible a largo plazo.

Para respuestas más detalladas, vea este hilo .

Péter Török
fuente
0

Hasta donde puedo ver y haber leído, esta es una pregunta sin resolver. Por lo tanto, las respuestas de evitación como "YAGNI" y las respuestas de "hágalo bien la primera vez". El hecho es que no hay un lugar en Agile para la refactorización, pero diría que debería haberlo.

La mejor respuesta hasta ahora menciona la deuda técnica. Esto, desafortunadamente, es una triste realidad del software en muchas empresas, donde la prisa por sacar las cosas fuera de la puerta, ya sea en una metodología ágil o no ágil, es muy común, pero bajo Agile las soluciones rápidas y sucias se racionalizan como algo bueno: "cumple con el requisito comercial mínimo" y "YAGNI" (con respecto a mantener limpio el código).

Sería genial si todos hicieran TDD, y sería genial si todos los desarrolladores refactorizaran la segunda o la tercera vez como lo sugiere una respuesta. Pero eso simplemente no sucede en el mundo real. Los desarrolladores de diferentes niveles de habilidad casi siempre se encuentran con atajos en la búsqueda de soluciones rápidas. Como resultado, el código se descompone en montañas de código que no se puede mantener, lo que lleva días a los nuevos desarrolladores simplemente descifrar, lo que perjudica la productividad y retrasa los plazos. Por "no mantenible" me refiero a soluciones de copiar y pegar, 5000 clases de línea, etc. ¡Y todo este código y estas correcciones sobre correcciones son esenciales para el negocio! - Yo diría que en estos casos de soluciones aditivas, ¡no existe YAGNI! Necesitarás un código limpio, SIEMPRE. Si el código no está limpio, definitivamente no lo necesitarás: ¿ves la profecía autocumplida? Los desarrolladores harían todo lo posible para no usar ese código en absoluto porque es demasiado doloroso de ver. Y el círculo vicioso continúa y continúa hasta que toda la gran bola de barro tiene que ser arrojada y reescrita.

Así que digo: a pesar de que la refactorización de códigos no es un concepto ágil, propio, distinto, digno de su propia historia, deberíamos hacer tiempo para refactorizar. Algunas tiendas ahora requieren que los equipos gasten el 20% de sus sprints en deuda técnica. Con suerte, los proponentes ágiles cambiarán de opinión sobre YAGNI y harán un lugar para refactorizar como una actividad separada de tiempo asignado. Y si ya lo han hecho y no he oído hablar de él, señale dónde se describe porque estoy muy interesado en saberlo.

blindcodifier9734
fuente
"El hecho es que no hay un lugar en Agile para la refactorización" . No creo que sea una declaración verdadera. En ágil, hay un lugar para cualquier tipo de desarrollo, incluida la refactorización, siempre que exista un caso comercial para ello. Si no hay un caso de negocios para ello, ¿por qué lo haces?
Bryan Oakley
Supongo que tienes un punto si es un poco simplista. En teoría, un desarrollador podría fabricar un caso de negocios para arreglar un código de mala calidad, incluso si no produce ningún cambio funcional, pero eso no coincidiría con el espíritu de agilidad: usar el negocio como un proxy para justificar el trabajo. Diría entonces que la actividad de refactorización se encuentra fuera del ámbito de la agilidad, una especie de actividad de CYA si se quiere, arreglando un código que no se puede mantener para que no le cueste a la empresa a largo plazo y se culpa a los desarrolladores. Llámelo "sprint refactorizador" o lo que sea, pero debe haber un lugar formal para ello.
blindcodifier9734