martes, 21 de marzo de 2017

Equipos, áreas e iteraciones en VSO

Organizar el trabajo es un mal necesario y tarde o temprano cualquier equipo de desarrollo tendrá que intentar abordar esta tarea con cierta rigurosidad. Ahora mismo, me ha tocado a mí y a otros pocos en mi empresa la “excitante” tarea de intentar poner algo de orden en el caos. Ya aviso que no tengo ninguna skill reseñable en cuanto a gestión de proyectos, de hecho, el lema de mi blog incluye la palabra “Desordenada”, fíjate tú, me he ahorrado el disclaimer.

La única herramienta que he usado hasta la fecha para llevar a cabo tan magna tarea ha sido Visual Studio Team Services https://www.visualstudio.com/es/vso/ (o Visual Studio Online o Team Foundation Service como se le conocía anteriormente, ya me han corregido en Twitter https://twitter.com/jc_quijano/status/844173841949691905). El flujo era sencillo, crear un nuevo proyecto y agregar, mejor o peor redactados, un buen saco de PBIs, a partir de ahí y fingiendo hacer SCRUM, organizar el trabajo en sprints y tirar pa’lante.

Lo cierto es que en este post no voy a plantear algo muy distinto, pero sí me he dado cuenta con el paso del tiempo y el notable y variopinto incremento de tareas a realizar, que los valores por defecto que propone VSO podrían no ser los más idóneos. Me ha costado bastante entender la relación entre Work Items, Iterations, Areas y Teams, y como he googleado bastante he pensado que, si lo dejo por escrito, yo mismo podré volver en un tiempo futuro para encontrar aquí el porqué de algunas decisiones. Es decir, si quieres entender cómo funciona VSO, o como creo yo que funciona, en relación a la pestaña “Work”, este es tu post, para todo lo demás recuerda, yo soy programador, no Project Manager.

Para hilar la explicación del post, nuestra empresa se llamará Acme y crearemos un proyecto con el mismo nombre y escogeremos el proceso SCRUM.

Recién creado, el nuevo proyecto contiene lo siguiente:

  • 7 Iterations en una estructura jerárquica. Su nodo principal es una Iteration llamada Acme del que cuelgan 6 Iterations llamadas Sprint 1-6.
  • 1 Area llamada Acme.
  • Un Team con el nombre del proyecto + Team. Es decir, Acme Team.
  • El equipo Acme Team tiene como área por defecto el área Acme y tiene asignadas las 6 iteraciones Sprint 1-6.

Como verás, es todo muy “Acme”, sobredosis de nombre.

En la pestaña Overview del proyecto https://acmecorporation.visualstudio.com/Acme/_admin tenemos los equipos (el segmento Acme/_admin es importante, nos dice que estamos a nivel de proyecto):

clip_image001

En la pestaña Work encontramos Iterations y Areas:

clip_image002

clip_image003

Si navegamos al equipo, podemos ver como el segmento de la url cambia desde Acme/_admin a Acme/Acme%20Team/_admin. Aunque la interfaz nos ayuda a saber dónde estamos, viendo la url salimos de dudas, ahora estamos en el equipo, no el proyecto.

En la pestaña Work del equipo encontramos de nuevo Iterations y Areas:

clip_image005

clip_image006

Lo cierto es que, si no creas más equipos en el proyecto, el trabajo que veas a nivel de proyecto es el mismo que verás a nivel de equipo, es decir, da igual si navegas a Acme/_workitems o a Acme/Acme%20Team/_workitems, la query que hay por debajo es la misma.

En el caso de “Backlog items”:

image

Y en el caso del Sprint 1 (por poner un ejemplo), el cambio más reseñable es que pasamos de Iteration Path Under Acme a Iteration Path Under Acme\Sprint 1

image

Es muy importante el operador de la condición, no es lo mismo Under que =, es una diferencia clave a la que hay que prestar atención.

Insisto en que si sólo hay un equipo no hay mucho donde rascar. Cuando se agoten las iteraciones iniciales (Sprint 1-6), se crea una nueva y se asigna al equipo para que esté disponible. Como el operador de Iteration Path para los elementos superiores “Filters for top level work Items” es “Under”, la nueva iteración se verá automáticamente y nuestra vida será plácida.

Sin embargo, si quieres dar cobijo bajo un mismo proyecto a distintos equipos o incluso a distintos proyectos (teniendo entonces un único proyecto en tu organización), las cosas se complican. Podrías usar etiquetas para organizar tu backlog… yo lo he hecho, lo reconozco, pero entender que es una iteración y un área y que relación mantienen con los Work Items y los equipos, te dará otras posibilidades.

A modo de resumen:

  • Un Work Item es un elemento de trabajo cuya propiedad “Work Item Type” determina de qué tipo es. Un Product Backlog Item es un Work Item… una Task o un Bug también lo son.
  • Un Work Item puede relacionarse con otro Work Item. Da igual si no tiene sentido, se puede. Cierto es que la interfaz nos sugiere/conduce hacía hacer las cosas bien, Epic -> Feature -> Product Backlog Item -> Task, pero si por algún extraño motivo te apetece agregar como hijo de una Task a un PBI, se puede.
  • Un Work Item siempre tiene asignado un “Iteration Path” y un “Area Path”.
  • Una iteración es un evento relacionado con el tiempo, normalmente será un sprint, pero podría ser cualquier otra cosa.
  • Un área es una división lógica del Backlog.
  • Una iteración no tiene nada que ver con un área, son entes separados, sólo se relacionan porque ambos son propiedades de un Work Item.
  • Un equipo tiene acceso a n iteraciones.
  • Un equipo tiene acceso a n áreas.
  • Por ende, un equipo verá los Work Items que tengan asignados esas iteraciones o áreas.

Si, por ejemplo, Acme Corporation tuviera dos productos, Cohetes e Imanes ¿Cómo organizar esto en un solo proyecto?

Lo primero sería crear un área por cada proyecto. Tendríamos 2 nuevas áreas hijas bajo el área inicial raíz “Acme”: Acme\Cohetes y Acme\Imanes. De esta forma, cuando agreguemos un nuevo Work Item le asignaríamos el área adecuada. El backlog empieza a tomar forma, ya podríamos dividirlo con una sencilla query y la condición Area Path = Acme\Cohetes.

Sin embargo, para asignar un área a un Work Item tiene que estar disponible en el equipo. Lo más perverso de la situación es que, aunque no esté el área asignada al equipo, podemos asignar el área a un Work Item… lo que hará que no lo veamos, ¿recuerdas la condición del backlog Area Path = Acme? Lo más sencillo es no hacerlo hasta que el equipo no tenga asignada esa área, momento en el cual la condición del backlog del equipo pasará a ser:

image

Porque esta es la verdad sobre las áreas, se agregarán tantas condiciones de igualdad al backlog como áreas tenga asignadas el equipo. Si queremos cambiar el operador a “Under”, se consigue marcando un área como “Include sub areas”, de este modo, si mañana creáramos Acme\Cohetes\Atómicos no sería necesaria agregar esta nueva área para que fuera visible en el backlog del equipo.

Lo único que queda por comentar sobre las áreas es que el área por defecto del equipo será la que se usará automáticamente cuando creemos un nuevo Work Item.

En este momento ya tenemos áreas, ya tenemos nuestro backlog dividido de forma lógica, pero para hablar de iteraciones primero hay que hablar de equipos.

¿De qué nos sirve tener el backlog dividido si al final lo percibimos todavía como un único e indivisible backlog (no queriendo por otra parte, depender de queries)? Para solucionarlo, crearemos 2 nuevos equipos a igualdad del primer nodo de las áreas lógicas que hemos creado, es decir, nuevo equipo Cohetes y nuevo equipo Imanes. Si asignamos al equipo Cohetes el área Acme\Cohetes (incluyendo sub-áreas) y al equipo Imanes el área Acme\Imanes (incluyendo sub-áreas), ahora cada uno verá en su backlog sólo lo que le concierne. Por otro lado, para ver el backlog completo, en el equipo por defecto simplemente marcamos el área raíz para que incluya sub-áreas.

La distribución quedaría así:

  • Acme Team – Acme (include sub-áreas)
  • Cohetes Team – Acme\Cohetes (include sub-áreas)
  • Imanes Team – Acme\Imanes (include sub-áreas)

Ni que decir tiene, que un usuario puede pertenecer a cualquier número de equipos, podría construir tanto cohetes como imanes.

Vale, ahora sí veo el backlog completo (Acme Team) y por separado el backlog de cohetes (Cohetes Team) y el backlog de Imanes (Imanes Team), pero tristemente hay que ponerse a trabajar… ahora toca el turno de las iteraciones.

Como hemos dicho antes, una iteración es un evento temporal con fechas de inicio y fin opcionales. Admite una estructura jerárquica, por lo que podríamos tener algo como lo siguiente:

  • Acme
    • Release 1
      • Sprint 1
      • Sprint 2

Los valores de Iteration Path para el anterior ejemplo serían Acme, Acme\Release 1, Acme\Release 1\Sprint 1 y Acme\Release 1\Sprint 2.

Para ver las iteraciones en un equipo, el equipo las tiene que tener asignadas. Podríamos asignar a Cohetes Team cualquier iteración de las anteriores, pero lo que no podemos hacer es tener una iteración hija y a la vez una iteración padre, es decir, no podemos asignar Acme\Release 1 y Acme\Release 1\Sprint 1 a la vez, si agregamos el sprint, el release se eliminará (pero si no agregamos el sprint, sí podríamos haber agregado el release, espero haberme explicado…).

Finalmente, en la pestaña Work y en el menú izquierdo aparecerán las iteraciones asignadas (una Current y el resto Futures).

¿Coinciden en el mismo tiempo el Sprint 1 para los 2 equipos? Usa el mismo, sin problemas, la información relativa a la capacidad, burdown chart, etc. es relativa al equipo actual. ¿No coincide? Usa iteraciones distintas. Lo que quiero decir es un tema muy flexible y las condiciones propias de tu negocio te harán tomar una u otra decisión. De nuevo, para ver todas las iteraciones a la vez, en el equipo por defecto deberían estar todas las iteraciones asignadas. La pena aquí es que sólo una iteración será la “Current”, con lo que para ver cómo van nuestros equipos tendremos que movernos entre una Current y varias Futures. Sin embargo, para cada equipo queda muy claro cuáles son sus iteraciones y verán sólo las suyas.

Respecto a iteraciones y en el contexto de un equipo, es importante entender las opciones “Default Iteration” y “Backlog iteration”.

Backlog iteration es la ruta a la iteración raíz a partir de la cual se podrán asignar iteraciones al equipo. Es decir, si la establecemos a Acme\Cohetes (porque creamos una iteración con este nombre), sólo podremos asignar iteraciones por debajo de Acme\Cohetes. Además, esto se traduce en una condición del backlog (no hablo aquí de sprints) como Iteration Path Under “Backlog iteration”. Con esta configuración ya podemos responder de forma precisa a la pregunta ¿Qué ve un equipo en su backlog? Ve Work Items de sus áreas asignadas y en iteraciones iguales o inferiores a “Backlog iteration”.

Además, Backlog iteration también será el valor por defecto para Iteration Path cuando agreguemos un Work Item desde el backlog (en sprints o en cualquier otra iteración, el valor por defecto será la propia iteración).

El campo “Default Iteration” es un poco raro, la verdad, sólo sirve para saber cuál será el valor por defecto para Iteration Path para un nuevo Work Item cuando se agregue desde el widget del dashboard principal o desde una query. Entiendo que aquí no hay contexto, no sabe si está en el backlog o en una iteración y por eso no puede tomar una decisión automáticamente. Por defecto vale @CurrentIteration, que es la iteración “Current”, así está bien, mejor no tocarlo.

Llegados a este punto, ya hemos resuelto como se relacionan Team Projects, Work Items, Teams, Iteration Paths y Areas.

Por sacarle punta al asunto, los inconvenientes que por ahora veo sobre tener equipos por proyecto serían:

  • La velocidad es por proyecto.
  • Si alguien trabaja al mismo tiempo en esprines en distintos equipos, tendrá que dividir su capacidad y estar al tanto de dos esprines, no sólo uno.
  • Con el tiempo y si el número de proyectos crece, podría haber más equipos que gente trabajando. ¡Awesome!

Bueno, espero que le sea de utilidad a alguien este mamotreto, a mí seguro que sí.

¡Un saludo!