Exprimiendo Scrum: Scrum y la gestión de la configuración (I)

Toda implantación de una metodología tiene un aspecto clave que muchas veces se olvida: diseñar una adecuada política de gestión de la configuración que de soporte a las actividades de desarrollo concurrente que el equipo realiza y las verificaciones de calidad que llevan a cabo los testers.

 

Además otra cuestión relacionada con la gestión de la configuración, que resulta imprescindible, es la necesidad de poder trazar nuestros binarios . Esta es una cuestión que a menudo se olvida y que se hace especialmente importante en los momento de dificultad, cuando nuestro software está sufriendo problemas: es sumamente difícil depurar un problema con garantías de éxito si no contamos con la certeza de que en el entorno de depuración contamos con el código fuente, la información de depuración (generalmente en forma de PDBs) y los binarios que se corresponden con una determinada entrega.

 

Otro aspecto vital, sobre todo en las metodologías ágiles, pero cada vez más en cualquier proceso de desarrollo, es la integración continua: construir nuestro software y ejecutar las pruebas automatizadas del mismo cada vez que se realiza un check-in.

 

En este post voy a cubrir la primera parte: describir la política de ramas que permite a un equipo de desarrollo que utiliza Scrum desarrollar de manera concurrente, estabilizar el software desarrollado y habilitar los mecanismos que permitan que los testers reciban software de calidad suficiente para su validación y de manera aislada de los continuos cambios realizados por el equipo de desarrollo para evolucionar la solución. En próximos post abordaré otras cuestiones relacionadas con las construcciones automatizadas y diarias, la integración continua y la trazabilidad.

 

Evidentemente, no pretendo dar una solución global, de universal aplicación en todo proyecto. La política de gestión de fuentes se ve condicionada por una infinidad de aspectos: el número de equipos, el número de versiones a mantener en producción, la existencia de adaptaciones para clientes determinados, el número de plataformas en las que se desplegará el proyecto, la necesidad de asegurar formalmente la calidad, rendimiento o seguridad del código antes de su integración en líneas privilegiadas (golden lines) y así un largo etcétera. Cada caso, según su complejidad y necesidades exige la utilización de unos patrones de SCM u otros. Lo que pretendo mostrar es el mínimo común denominador que todo equipo Scrum y en general todo equipo ágil necesita en su política de gestión de fuentes.

 

Cuando se plantea una política de gestión de fuentes, es una buena idea es enumerar los objetivos que persigue. Los objetivos que persigo, en esta ocasión, por considerarles comunes a todo equipo ágil son:

 

  • Permitir que los desarrolladores trabajen de manera concurrente y en equipo.
  • Permitir que los testers puedan estabilizar el software sin sufrir interferencias por parte de los desarrolladores.
  • Permitir el objetivo de Scrum de conseguir tras cada Sprint ‘un incremento de funcionalidad potencialmente entregable’.
  • Permitir la corrección de errores encontrados con el mínimo impacto.
  • Establecer una nomenclatura para las diferentes ramas.

 

Permitir que los desarrolladores trabajen de manera concurrente y en equipo

 

Uno de los valores claves en Scrum es que los desarrolladores trabajen en equipo, evitando el código con propietario y fomentando la colaboración. Lógicamente cualquier herramienta de gestión del código fuente habilita escenarios de compartición de fuentes entre desarrolladores y el trabajo compartido. Luego aquí podríamos decir que para cubrir este objetivo necesitamos poco más que instalar una herramienta de gestión de código, crear una línea de código, y utilizar la herramienta. Pero esto es cierto hasta cierto punto. Cuando los equipos crecen y hay un número relevante de desarrolladores tocando la misma línea de código compartida se producen continuos cuellos de botella (si utilizamos bloqueos exclusivos, práctica nada recomendada) o continuos conflictos a la hora de integrar las fuentes (si no utilizamos bloqueos).

 

La solución habitual en este tipo de escenarios es utilizar una rama por desarrollador, pero esta no es una buena solución. De hecho se trata de un antipatrón conocido como ‘Berlin Wall’, ya que si bien es cierto que aísla a los desarrolladores de los cambios de otros desarrolladores, también impide que varios desarrolladores trabajen en equipo para desarrollar un misma característica.

 

Una aproximación que funciona mejor es usar ‘ramas por característica’. En la aproximación de rama por característica se crea una rama de desarrollo partiendo de la rama de desarrollo principal, generalmente llamada DEV, con el fin de desarrollar sobre ella una determinada característica. La rama de característica incluye todo el código de la rama principal de desarrollo (DEV) Una vez completada esta característica la línea creada converge de nuevo con la línea principal de desarrollo (DEV). Varios desarrolladores trabajan de manera concurrente sobre cada rama de característica, pero el número de desarrolladores que en un equipo trabajan sobre una característica determinada en un momento del tiempo, no debe ser muy elevado, con lo que evitamos cuellos de botella que se producen cuando solo contamos con una única rama de desarrollo.

 

A la hora de nombrar las ramas de característica se suele elegir entre dos esquemas: dar a la rama el nombre de la característica (p.e.: DEV-TransferenciaAlmacenes, DEV-ConversionAlbaranFactura) o usar el número de ticket o workitem que define la caracteristica como nombre de la rama (DEV-401, DEV-402, siendo el número el identificar del Producto Backlog Item que describe la característica o historia de usuario que se implementará en esa rama). Es una cuestión, más que nada, de gustos.

 

Con lo descrito hasta ahora, nuestra política de gestión de fuentes tendría un aspecto similar al siguiente: Desarrollo concurrente y en equipo

Permitir que los testers puedan estabilizar el software sin sufrir interferencias por parte de los desarrolladores

 

Scrum es una metodología que no prescribe el rol de tester. Sin embargo, sí tiene la calidad continua como uno  de sus valores y como ya he comentado en alguna ocasión la calidad no es algo de lo que se pueda prescindir. Para mantener la calidad de manera continua en nuestros proyectos, no podemos hacer nada mejor que poner un tester en el proyecto.

 

Siguiendo la máxima de que un bug nos cuesta más dinero cuanto más tarde lo detectamos, debemos poner a nuestros testers (o al menos una parte significativa de los mismos) lo más cerca posible de nuestro equipo de desarrolla e idealmente los testers deben ser parte integrante del equipo de desarrollo.

 

En cualquier caso se hace evidente la necesidad de que nuestros testers prueben software con un mínimo de estabilidad, que presente características concretas y que no se vea continuamente bajo impactos provenientes de los  desarrollos que están en curso.

 

La conclusión es evidente. Aparece la necesidad de una nueva rama a la que promocionaremos código con ciertas garantías, de manera que el trabajo de los testers comience sobre una base de código de cierta calidad. Esta rama, sobre la que no se realiza desarrollo, sino sobre la que se promociona código maduro, se suele llamar MAIN.  Esta rama contendrá el código, correspondiente a características completas, que los testers estarán probando para lograr su estabilización.

 

Las garantías que se deben cumplir para promocionar código desde la rama DEV a esta cambian de equipo a equipo en función de las situaciones concretas. Se suele exigir, para promocionar código a esta rama, que el código a promocionar se haya compilado correctamente,  pasado todas la pruebas automáticas, y probablemente que haya pasado satisfactoriamente al menos un test de humo realizado por los desarrolladores o por los propios testers.

 

Con la aparición de esta rama, nuestra política de gestión de fuentes tendría un aspecto similar al siguiente:  Aislar el entorno de pruebas

Permitir el objetivo de Scrum de conseguir tras cada Sprint ‘un incremento de funcionalidad potencialmente entregable’

 

Uno de los apectos claves de Scrum es que tras cada Sprint (periodo de desarrollo de 20 días hábiles como máximo) debemos lograr un ‘incremento de funcionalidad potencialmente entregable’. Para ello es vital lograr que la línea principal de desarrollo nunca contenga características a medio desarrollar. Hemos visto como la necesidad de lograr un desarrollo altamente colaborativo y concurrente nos ha llevado a usar ramas por característica.

 

Las ramas por característica también nos ayudan a evitar que la línea principal de desarrollo pueda contener en algún momento del tiempo características incompletas. Puesto que establecemos la política de integrar en la rama de desarrollo principal (DEV) características completas, provenientes de las rama de características, nunca tendremos, en la rama MAIN, código de características a medias. Esto nos garantiza que al final de cada Sprint y a partir de la rama MAIN, podremos construir la solución con la garantía de poder presentar características completas. Esto es vital, pues en Scrum seguún las reglas del Sprint Review, el equipo solo puede presentar durante el mismo funcionalidad completa.

 

Según lo comentado, el modelo que tenemos hasta ahora, nos sirve perfectamente y, en consecuencia, para cubrir el objetivo que nos ocupa, no necesitamos añadir modificación ninguna al mismo:

Incrementos de funcionalidad potencialmente entregables

Permitir la corrección de errores encontrados con el mínimo impacto

 

Una necesidad que surge en todo proceso de desarrollo, relacionada con la gestión de la configuración y del código fuente, es la de habilitar un mecanismo que permita liberar versiones que solo corrigen errores y no añaden nueva funcionalidad.

 

Una situación habitual en equipos de desarrollo que utilizan esquemas de gestión de fuentes demasiado simplistas es la imposibilidad de liberar releases que solo incluyen correcciones de errores. Esto es importante pues muchas veces los clientes o usuarios están dispuestos a cambiar de versión en producción si saben que los impactos a los que se exponen sus sistemas están acotados. Esto se consigue con versiones menores, que solo corrigen errores y que no añaden nueva funcionalidad.

 

Otra situación habitual, en estos esquemas simplistas,  es que para recibir una corrección de un error, el cliente debe esperar a que los desarrolladores completen ciertas características, a que los testers estabilicen el software, que no solo incluye correcciones de errores, y a que en general toda la organización esté en condiciones de liberar una nueva versión. Este es un proceso, que a menudo, se prolonga más en el tiempo que el tiempo que los clientes están dispuestos a esperar nuestros parches.

 

Para permitir la corrección de errores de una manera ágil y operativa necesitamos dos cosas: una rama por cada versión soportada en la que podamos hacer correcciones de emergencia para una determinada release minimizando el impacto sobre el desarrollo en curso. Y un proceso claro de promoción de las correcciones de los errores que encontremos durante el desarrollo y la validación de software por parte de los testers.

 

Aparece así una nueva línea, habitualmente llamada RELEASE, que contiene el código desde el que liberaremos cada release. Habrá tantas ramas RELEASE como versiones a las que tengamos que dar mantenimiento. Sobre esta línea se puede hacer correcciones puntuales de errores si solo afectan a esta versión, pero la práctica recomendada a la hora de corregir errores es buscar la línea de código más antigua en la que el error se reproduce,  corregirlo en esa línea y luego propagar la corrección hacía líneas superiores en el proceso de desarrollo. Típicamente y salvo parches de urgencia o cuando la complejidad del proceso lo desaconseje, debemos corregir el bug sobre la línea principal de desarrollo o sobre la línea de característica si es que esta aun sigue viva. Luego escalar esta corrección, mediante la integración del changeset relacionado con el error, a la línea MAIN y de hay seguir el proceso de estabilización de la línea MAIN que dará lugar a la creación de una nueva línea RELEASE correspondiente con una determinada versión.

 

Con esto nuestro modelo, incluido el mecanismo de corrección de errores como sigue, quedaría definitivamente como sigue: Corrección de errores

Espero que este post os resulte útil a la hora de establecer una política de gestión de fuentes. Espero vuestros comentarios, preguntas y sugerencias sobre el tema.

11 comentarios en “Exprimiendo Scrum: Scrum y la gestión de la configuración (I)”

  1. Me ha encantado el post, porque precisamente ahora estoy empezando a usar subversion y una de las preguntas que me hacia era como organizar las ramas.

    Me gustaria aprender mas, ¿cuales son tus fuentes? ¿Me recomiendas algunos articulos sobre el tema?

  2. Felicidades, me ha gustado mucho el post. Además nos viene como anillo al dedo ya que la semana que viene tenemos previsto sentarnos para decidir nuestra estrategia de merging/branching y seguro que no es de mucha utilidad.
    Aprovecho para preguntar si conoces alguna herramienta que permita hacer instantánea del modelo de merging/branching en un instante determinado del tiempo ,al estilo de los gráficos que expones en el post por ejemplo (no se si es una pregunta muy tonta o no, pero es una duda que tengo)

    Un saludo!

  3. Hola Rodrigo,
    Excelente Post, gracias por compartir tu conocimiento.
    Me gustaría aprender más acerca de scrum,me recomendarías algún libro con casos prácticos??
    Gracias y felicidades!!!!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *