¿Cómo manejo la refactorización que lleva más de un sprint?

49

Trabajo con una base de código que tiene más de 500 mil líneas de código. Tiene una gran necesidad de refactorización. Se han identificado esfuerzos de refactorización que tomarán más tiempo que el sprint normal de dos semanas. Estos no se pueden dividir en tareas más pequeñas como he visto sugeridas en otras respuestas en este sitio. El producto debe funcionar al final de la iteración, y la refactorización parcial dejará el sistema en un estado inutilizable ya que la dependencia entre los elementos es horrible. Entonces, ¿cuál sería la mejor manera de abordar este obstáculo? Una vez más, menciono, dividirlo en pedazos más pequeños no es una opción, eso ya se ha hecho.

Actualización: Las personas parecen necesitar una explicación de por qué esto no puede encajar en un sprint de 2 semanas. Hay más cosas involucradas en un sprint que solo escribir código. Tenemos una política de no código sin pruebas. Esa política no siempre existió y una gran parte de la base de código no los tiene. Además, algunas de nuestras pruebas de integración siguen siendo pruebas manuales. El problema no es que la refactorización en sí sea tan grande. Es con el hecho de que pequeños cambios tienen un efecto en muchas partes del sistema, y ​​debemos asegurarnos de que esas partes sigan funcionando correctamente.

No podemos posponer o extender un sprint porque tenemos revisiones mensuales. Entonces, este cambio que se extiende más allá de un sprint no puede detener el otro trabajo que se agrega al hotfix.

Refactorización vs rediseño: el hecho de que nuestro proceso de desarrollo no sea lo suficientemente eficiente como para manejar esta refactorización en un ciclo de dos semanas no garantiza cambiarle el nombre a un rediseño. Me gustaría creer que en el futuro podríamos realizar exactamente la misma tarea dentro de un ciclo de dos semanas a medida que nuestro proceso mejore. El código en cuestión aquí no ha tenido que cambiar en mucho tiempo, y es bastante estable. Ahora, a medida que la dirección de la empresa se está adaptando más al cambio, queremos que esta parte de la base del código sea tan adaptable como el resto. Lo cual requiere refactorizarlo. Con base en las respuestas aquí, se está haciendo evidente que faltan los andamios necesarios para que esta refactorización funcione en el marco de tiempo de los sprints normales.

Responder:

Voy a hacer el enfoque de ramificación y fusión que Corbin March sugirió la primera vez para que podamos aprender más sobre estas áreas problemáticas y cómo identificar las pruebas faltantes. Creo que, en el futuro, deberíamos adoptar el enfoque que Buhb sugirió para identificar las áreas a las que les faltan pruebas e implementarlas primero, luego hacer la refactorización. Nos permitirá mantener nuestro ciclo de sprint normal de dos semanas, como muchos aquí han estado diciendo que siempre debería ser el caso para la refactorización.

Charles Lambert
fuente
23
Como nota al margen, esto es, por definición, un rediseño a gran escala, no una refactorización . Espero que no tomes esto como una trampa: en mi humilde opinión, es importante usar una terminología clara para evitar problemas de comunicación :-)
Péter Török
99
@Charles, "Refactoring se realiza normalmente en pequeños pasos. Después de cada pequeño paso, uno se queda con un sistema de trabajo que es funcionalmente sin cambios. " Tomado de la página he vinculado anteriormente.
Péter Török
2
@Charles: la refactorización siempre se puede hacer de forma incremental, mientras se mantiene el sistema funcionando. coloque un gran comentario de "Refactorización en progreso" en la parte superior de la clase / paquete / módulo que se está refactorizando, y realice las partes de una en una. Si corta una versión provisional mientras el modelo de objeto está en transición, está bien.
Sean McMillan
77
Si está realizando pasos tan grandes que no puede tener un código de trabajo de forma regular, esa es la definición de cuándo la refactorización se convierte en rediseño. Por favor, no te enojes con la gente por llamarte por tu mal uso de la palabra No hay nada de malo en preguntar sobre el rediseño. Los comentaristas simplemente están tratando de indicar que no obtendrás las respuestas que deseas porque estás usando mal la palabra, que es lo que ya sucedió.
jprete
55
Sé que está un poco fuera de tema, pero me da mucha curiosidad sobre cuáles son las circunstancias que hacen imposible la refactorización en pequeños pasos. Por favor, comparta más antecedentes sobre esto.
Buhb

Respuestas:

14

Si tiene el lujo de retrasar la refactorización, le sugiero que centre las próximas iteraciones en agregar pruebas unitarias y pruebas de integración automatizadas hasta el punto en que pueda refactorizar cómodamente la base de código y luego refactorizar en un solo sprint.

Buhb
fuente
68

Mi sugerencia:

  1. Crear una rama
  2. Fusionar diariamente desde el tronco a su rama y resolver conflictos.
  3. Trabaja hasta que esté hecho. Su rama puede estar fuera del desarrollo central para varios sprints.
  4. Combinar de nuevo al maletero.

No hay forma de evitar el hecho de que probablemente se pondrá feo. No te envidio. En mi experiencia, cuando cambias drásticamente un proyecto, es más fácil fusionar el desarrollo continuo en el nuevo paradigma que fusionar de alguna manera el nuevo paradigma en un tronco ahora cambiado después de que todo haya terminado. Aún así, va a doler.

Corbin March
fuente
1
Hemos discutido el uso de este enfoque, y si no surgen otras ideas antes de abordarlo, esto es lo que planeamos hacer.
Charles Lambert
3
Me temo que tendrá un montón de sobrecarga de ida y vuelta entre el tronco y la rama si desea realizar una refactorización tan completa.
Giorgio
En la mayoría de los casos (con suerte) esos cambios combinados no afectarán el código en cuestión aquí. No me importaría extender la línea de tiempo para este cambio si garantiza un resultado confiable.
Charles Lambert
1
Teniendo en cuenta la volatilidad que sugiere su presentación, tal vez debería considerar Git , ya que facilita este tipo de ramificación y fusión especulativa.
John Tobler
1
@Giorgio: yo también, la fusión diaria parece un poco paranoica, pero realmente depende del tamaño del equipo. Cuantas más personas, más cambios y con más frecuencia debe fusionarse. Sin embargo, todos los días parece el límite inferior, si quieres tener tiempo para trabajar.
Matthieu M.
40

No todas las tareas se pueden hacer en un sprint (artificial) de 2 semanas, por lo que se requiere sentido común. Si ya no puede desglosarse, y debe hacerse, simplemente súbase y hágalo. El proceso no es más importante que el resultado final, y debe verse como una guía más que como una ley que nunca se debe violar.

Chris Card
fuente
3
Su respuesta es muy buena información sobre el tema. Estoy aquí para "seguir y hacerlo" como tú dices. Hice la pregunta con la esperanza de obtener información para poder encontrar un proceso que se ejecute en paralelo a mi existente o modificar de alguna manera el proceso actual para resolver mi situación actual. Necesito algo que decirle a los desarrolladores para que tengan pautas dentro de las cuales trabajar, ya que esto sucederá al menos 2 veces más.
Charles Lambert
+1 para "El proceso no es más importante que el resultado final, y debe verse como una guía más que como una ley que nunca se debe violar". - La gente realmente parece olvidar esto.
Bjarke Freund-Hansen
32

Simplemente haz un sprint de 3, 4 o 5 semanas. ¿A quien le importa? Obviamente estás convencido de que no se puede hacer nada en un período de tiempo más corto, así que deja de luchar contra él.

Simplemente no se lo digas a tus compañeros en The Royal Society of Blind Agile Adherance.

JeffO
fuente
Parece que por razones organizativas (revisiones mensuales), los sprints de 2 semanas son bastante difíciles de cambiar.
Steve Bennett
10

Recomiendo comenzar con el libro Working Effectively with Legacy Code , de Michael Feathers. Cubre una variedad de técnicas para reducir el alcance de los cambios de estilo de refactorización.

kdgregory
fuente
Un buen libro seguro, pero no creo que cubra la refactorización dividida en varios sprints.
Adam Lear
44
Voy a darle a esto un +1 porque es probablemente el mejor libro para comenzar cuando comiences a aprender, como dice el título, a trabajar efectivamente con código heredado. Es relevante para alguien que podría hacer esta pregunta y no entender lo que implica dividir las cosas en pasos más pequeños.
Charles Lambert
@Anna: entonces es posible que desee (re) leer el capítulo 25, que habla sobre técnicas para romper el tipo de acoplamientos que evitan pequeños cambios.
kdgregory
@kdgregory lo suficientemente justo. :) ¿Te importaría agregar eso a tu respuesta para hacerlo más increíble?
Adam Lear
7

En nuestra tienda, cuando tenemos grandes tareas de refactorización o reescritura que no se pueden completar en una ventana de lanzamiento, dejamos la funcionalidad tal como está en el sistema. Pero comenzamos con las nuevas funciones refactorizadas de bloque de lego según lo permita el tiempo. Eventualmente, llegamos a un estado en el que tenemos suficientes bloques de lego, que un sprint proporciona suficiente tiempo para conectar los bloques de lego en la aplicación y activarlo para los usuarios.

De manera más concisa, separamos o reelaboramos grandes funciones con nuevos nombres. Luego, al final, usamos nuestro trabajo renombrado y refactorizado en lugar del viejo código desagradable.

Amy Anuszewski
fuente
Esta es una buena idea, pero requeriría un alto nivel de comunicación para promulgarse. Por ejemplo, cuando estoy codificando, si identifico un método que no se está utilizando en ningún lugar y no es público, lo eliminaré.
Charles Lambert el
5

Dedique un sprint a descubrir cómo mantener el código funcionando correctamente a mitad de refactorización. Esto puede tomar la forma de métodos y clases en desuso, envoltorios, adaptadores y similares. Su refactorización puede ensuciar el código por un corto tiempo para que sea más limpio a largo plazo; está bien. En este momento estás diciendo que no se puede hacer. No creo que sea correcto: piense en cómo sería su proceso si se pudiera hacer, piense en los pasos que puede seguir para hacerlo. Entonces sumérgete.

Carl Manaster
fuente
Ya hemos hecho todo esto. Esa fue la razón por la que expresé claramente que no podía desglosarse.
Charles Lambert
De Verdad? ¿Pasaste un sprint completo simplemente planeando cómo refactorizar sin romper tu sistema y no se te ocurrió nada? Me resulta difícil creer que un sprint de planificación dedicado no haya tenido nada; tal vez necesites traer un consultor (y no, no soy uno, no estoy tratando de conseguir un concierto).
Carl Manaster
1
No dije nada por el estilo. Estaba diciendo que pasamos por un proceso similar al que usted describió y obtuvimos en el otro extremo un código que no se puede refactorizar en un solo sprint.
Charles Lambert
Dije: "Dedique un sprint a descubrir cómo mantener el código funcionando correctamente a mitad de refactorización". Usted dijo: "Ya hemos hecho todo esto". ¿Ahora estás diciendo lo contrario? Lo siento si esto suena contencioso, pero no entiendo.
Carl Manaster
5

+1 en la respuesta de Corbin March, eso es exactamente lo que estaba pensando. Parece que su código base es un poco feo y tomará más de un ciclo de sprint para limpiarlo.
Entonces, como dijo Corbin,

  1. bifurcarlo en un "proyecto de refactorización"
  2. prueba tu cambio de sucursal
  3. promover a su entorno de prueba para pruebas de control de calidad
  4. Vuelva a fusionarlo gradualmente en el tronco hasta que finalice la refactorización.

Estoy seguro de que no tendría ningún problema en venderle esto a su gerente de desarrollo, si sus PM tienen dificultades para verlo, explíqueles que Roma no se construyó en un día y que limpia toda la basura arrojada a Roma. las calles tampoco se van a hacer en un día. La refactorización llevará un tiempo, pero al final valdrá la pena en términos de mantenimiento más fácil, lanzamientos de mejoras más rápidos, menos tickets de producción y un SLA más completo.

bkdraper
fuente
1
Tengo toda la munición que necesito para convencer a todos. Solo necesito un plan oficial para ejecutarlo, cuando lo presente. De las respuestas aquí, no tengo dudas de que se me ocurrirá una solución repetible.
Charles Lambert el
4

Aunque el rediseño que realmente desea hacer es una tarea grande, ¿sería posible refactorizar piezas más pequeñas para romper / desacoplar dependencias individuales? Ya sabes, cuando tengas dudas, agrega indirección. Cada uno de estos desacoplamientos debe ser una tarea más pequeña que la gigantesca que no puedes completar.

Una vez que se eliminan las dependencias, debe poder dividir las tareas de refactorización restantes para que se puedan obtener dentro de los sprints.

Matthew Flynn
fuente
3

En el proyecto para el que estoy trabajando en este momento, estamos usando sprints de 4 semanas. Y a veces no podemos terminar una historia de usuario y simplemente la reiniciamos durante el siguiente sprint.

Sin embargo, en mi humilde opinión, debería ser posible dividir una refactorización en historias más pequeñas que caben en un sprint de 4 semanas. Si no puede llevar el código a un estado coherente en 4 semanas, tengo la sensación de que está reescribiendo su aplicación en lugar de refactorizarla.

Giorgio
fuente
un sprint de 4 semanas debería cubrirlo. Sin embargo, no podemos detener los sprints actuales de 2 semanas debido a otras correcciones de errores, etc. Por lo tanto, esto debería extenderse a través de más de un sprint. De ahí el quid de mi problema.
Charles Lambert
Como dije, estamos usando sprints de 4 semanas y, si una historia no termina en 4 semanas, simplemente la programamos para el próximo sprint. ¿Puede al menos tener el sistema en un estado consistente al final de un sprint de 2 semanas (y luego continuar durante el siguiente sprint)?
Giorgio
No es un estado consistente verificable .
Charles Lambert
Debo agregar mi saludo al esfuerzo que otros han hecho para esperar que encuentres otra palabra para usar en lugar de "refactorizar". La refactorización está bien definida y su alcance es mucho más inmediato y a corto plazo que el rediseño y la reprogramación masivos y lentos que necesita hacer.
John Tobler
2

Recomiendo que cuando ciertas tareas demoren más que el ciclo de sprint de 2 semanas, la tarea se programe para otro momento. Su equipo ha identificado la necesidad de refactorizar y eso es importante. A veces, no hay otra opción ... y, sí, eso apesta.

Cuando llegue el momento de comenzar la refactorización, simplemente suspenderás los sprints normales. No tienes elección. Utilice el control inteligente de versiones: bifurcación, refactorización, prueba, fusión. Siempre hay un momento en el que la refactorización de algunos proyectos grandes tiene prioridad sobre las características. Si es posible, también trataría de separar las preocupaciones para una mejor flexibilidad.

IAbstract
fuente
No podemos posponerlo para siempre, y su respuesta no aborda cómo realizar la refactorización.
Charles Lambert
@Charles: 'programado para otro momento'. ;) No dije cancelar el proyecto.
Resumen de
2

Habiendo pasado recientemente por el mismo problema con una parte de nuestra base de código (que también es un poco más grande), espero poder compartir algunas ideas con usted. En mi situación, la base de código había sido desarrollada por otro equipo, por lo que nadie de los desarrolladores originales estuvo involucrado en esta refactorización. Mi experiencia con la base de código fue de aproximadamente 1 año, y otro desarrollador le encargó 2 años.

Permítanme dos pequeñas notas con respecto a las otras respuestas aquí:

  • La ramificación lo ayudará a establecer un patio de recreo para usted, pero nunca combine sus cambios en el tronco en un gran conjunto de cambios. Tendrás serios problemas con el resto del equipo.
  • Debe hacerlo de forma incremental, y se puede hacer. No hay excusas. Lea Trabajo eficiente con código heredado de principio a fin. Leelo de nuevo.
  • Pensar que puedes hacerlo es un gran paso es una falacia. Aunque parece más trabajo, hacerlo de manera incremental es mucho más fácil de administrar.

Pasar aparentemente "fuera de reserva" durante dos semanas o más no pasará desapercibido. Debe asegurarse de contar con el respaldo de la gestión de proyectos y, lo que es más importante, del equipo. Si el equipo no está comprometido con esta refactorización (y esto significa, hazlo ahora, no en un futuro lejano), te meterás en problemas.

No lo hagas solo, usa la programación de pares. Esto no significa estrictamente que deba sentarse frente al mismo teclado todo el tiempo, sino que puede manejar tareas pequeñas y estrechas (por ejemplo, escribir pruebas que capturen el comportamiento de esta clase) individualmente.

Haga una refactorización de rasguños y trátelo como tal. (¡Una especie de refactorización prototipo "desechable", el bit "desechable" es importante!) Honestamente, es poco probable que sepas todas las implicaciones que tendrá tu refactorización. Una refactorización scratch lo ayudará en ciertos aspectos:

  • Descubrirá piezas del sistema que nunca supo que existían.
  • Tendrá una mejor visión de cómo se interconectan los módulos
  • Descubrirá una nueva forma de agrupar su sistema en módulos, probablemente muy diferente de su comprensión actual. Discuta ideas con su pareja. Intenta destilar tu nueva vista. Escriba un documento técnico breve sobre arquitectura (o dibuje un diagrama) que diga dónde están las cosas actualmente y dónde deberían pertenecer lógicamente.

Cuando hayas refactorizado desde cero, espero que descubras que no puedes simplemente ir y cambiar todo. Te sentirás mal, es solo un gran desastre y no puedes simplemente accionar un interruptor y hacerlo funcionar. Esto es lo que me pasó, puede ser diferente en tu situación.

Sin embargo, mi compañero y yo entendimos mucho mejor nuestro sistema. Ahora pudimos identificar refactorizaciones / rediseños individuales, más pequeños (aunque todavía grandes). Capturamos nuestra visión del sistema en un diagrama y lo compartimos con el equipo, junto con los elementos del trabajo atrasado que se nos ocurrió para implementar esa visión. Con el poder de un consenso común, decidimos qué elementos implementaríamos en el transcurso de la próxima iteración.

Una última cosa que nos ayudó fue usar una gran pizarra. Hay demasiadas cosas para tener en tu cabeza. Es muy importante que guardes notas. Escríbete una nota de resumen al final del día, capturando lo que has hecho hoy y quieres hacer mañana. Ayuda a relajarse a lo grande, y necesita un momento relajado si desea mantenerse al día con la tarea. ¡Buena suerte!

Johannes Rudolph
fuente
1

Inicie una ventana de mantenimiento durante la cual no se realiza ningún desarrollo adicional. Realice el rediseño, luego reanude los sprints de desarrollo.

Christopher Mahan
fuente
0

Tenemos dos tipos de trabajos a nuestra mano:

  1. Trabajos de hora hombre
  2. Obras de genio

La refactorización generalmente consiste en el primer tipo de trabajo, ya que muchos desarrolladores ya conocen muchos métodos como DRY , SRP , OCP , DI , etc. Por lo tanto, cuando un proyecto tarda dos meses en refactorizarse, simplemente lleva dos meses , hay No hay forma de evitarlo. Por lo tanto, mi sugerencia sería no refactorizar el proyecto original y dejar que funcione en su situación actual. Deje de recibir nuevas solicitudes y requisitos de las partes interesadas y el propietario del producto . Luego, deje que el equipo trabaje en el proyecto hasta que se refactorice y esté listo para comenzar.

Saeed Neamati
fuente
0

Una sugerencia que puede ser útil: si tiene un código no probado que no tiene tiempo suficiente para refactorizarlo y volver a probarlo dentro del sprint de dos semanas, considere primero realizar otros pequeños cambios no relacionados al código para que pueda concentrarse en pruebas de escritura para el primer sprint o dos. Quizás pueda identificar varios clientes no probados del código que desea refactorizar; elija un cliente y realice otros cambios de alguna utilidad para el negocio que lo obligarán a escribir pruebas para ese cliente. Una vez que esté más familiarizado con el código, después de trabajar con él, y tenga más pruebas, y posiblemente haya realizado algunas refactorizaciones menores, estará en una posición mucho mejor para lograr la refactorización y la (ahora más fácil ) probar ambos en una iteración.

Otro enfoque es hacer una copia del código ofensivo, refactorizarlo y luego mover a los clientes uno por uno al nuevo código. Este trabajo se puede dividir en iteraciones.

Y no te rindas: no aceptes que una refactorización grande no se puede dividir en pasos más pequeños. El enfoque más fácil / rápido / mejor puede llevar más tiempo que una iteración. Pero eso no significa que no haya forma de hacer fragmentos del tamaño de iteración.

Jeff Grigg
fuente