#HistoriaDeTrinchera: Planning de una User Story

Recurrentemente hablo con gente que me comenta de sus dificultades para completar el trabajo planificado en la iteración. En muchos de esos casos mi sensación es que el equipo incluye funcionalidades en su iteración sin tener suficientemente en claro su implicancia. Creo que muchos se han ido del extremo de especificar cada detalle de la funcionalidad en un documento tipo especificación de casos de uso, a directamente pasar al otro extremo y escribir un título y nada más. Es por esto que quiero compartir en este artículo el ejercicio que intentamos hacer en mi proyecto actual a la hora de armar nuestro backlog de iteración determinando las funcionalidades que trabajaremos.

Una de las particularidades de nuestro proyecto es que como parte del equipo tenemos una especialista en diseño de experiencia usuario (digo particularidad pero me parece que esto es cada vez más común). A su vez esa especialista es en simultáneo parte de otro equipo que trabaja en forma transversal en el diseño de la experiencia de varios productos de la organización. Es así que las funcionalidades (que usualmente llamamos user stories) se piensan desde un momento muy temprano teniendo presente la experiencia que se quiere ofrecer al usuario. De esta forma, cuando hablamos sobre una funcionalidad en una reunión de planificación generalmente ya contamos con un diseño de pantalla (o tal vez varias) que acompañan la conversación.

De la conversación sobre la user story buscamos esclarecer los siguientes puntos para poder agregarla al backlog de la iteración:

  • El escenario principal de uso y alguno de los escenarios alternativos más importantes. De ser posible, y si la complejidad lo amerita, ahi mismo expresamos estos escenarios en sintaxis Gherkin.
  • Las tareas necesarias para completar la story como ser: codear la pantalla, codear un nuevo servicio, codear componente para conectar con otro sistema, generar los datos de prueba, automatizar la prueba end-2-end, etc, etc
  • La dependencias de otras aplicaciones/apis y estados de las mismas (esa API que debemos consumir ¿ya está disponible en producción? ¿la está consumiendo algún otro equipo?)
  • La necesidad (o no) de hacer que la funcionalidad sea “apagable” o “segmentable”. Hay funcionalidades que son simples y de baja criticidad que apenas las terminamos pueden ser liberadas al público en general, pero hay otras que, ya sea por su complejidad o criticidad, se prefiere liberarlas gradualmente a distintos grupos de usuarios. En términos técnicos pretendemos identificar si la funcionalidad debe ser “toogleable”.

A medida que vamos viendo cada una estas cuestiones vamos tomando conciencia del tamaño y la complejidad de la funcionalidad y puede que en base a ello decidamos partir la funcionalidad en varios cortes (lo que comúnmente se conoce como slicing).

En algunos casos parte de estas cuestiones se hablan en una reunión de refinamiento que ocure previamente a la planning. A su vez dicha reunión nos permite identificar potenciales blockers para el desarrollo de alguna funcionalidad pedida. En algunos casos también ocurre que la funcionalidad pedida depende de funcionalidades provistas por alguna API desarrollada por otro equipo y que no se encuentra disponible aún o tal vez no provee todo lo que necesitamos. En estos casos en lugar agregar la funcionalidad en cuestión a nuestra iteración, agregamos una tarea de gestión para darle seguimiento a al desarrollo de esa API e incluso hacer algún prueba de concepto como para ir familiarizándonos.

Dos datos adicionales de contexto:

  • En las reuniones de refinamiento no participa necesariamente todo el equipo. Seguro están los especialistas de negocio, la especialista en UX, el facilitador y algunos devs. En general esta reunión dura 1 hora.
  • Las reuniones de planificación tiene 2 partes: una estratégica donde participa todo el equipo y una táctica donde solo participan los técnicos (devs & testers). Entre ambas se van entre 2 y 3 horas.

A partir de lo anterior resulta que para planificar una iteración de 2 semanas este el equipo requiere en total de unas 4 horas de trabajo conjunto.

Algunas de estas cuestiones puede que no coincidan exactamente con lo que recomiendan algunos libros y posiblemente a algunos lectores puede que le resulten impracticables en su propio contexto y lo entiendo. No es mi intención convencer a nadie de trabajar de esta de esta forma, simplemente pretendo compartir lo que a nosotros nos viene funcionando y nos permite entregar software todas las semanas.

Y un día no separamos (una historia de crecimiento orgánico)

Hasta aquí…

Comenzamos el proyecto con un equipo completamente nuevo. Según pasaron las iteraciones nos fuimos consolidando como equipo a la vez que sumamos nuevos miembros. De esta forma llegamos a completar la iteración 12 siendo 14 personas. Suficiente, hora de separarnos.

Previamente, allá por la iteración 7, había contado de la previsibilidad de este equipo, un propiedad que el equipo logró mantener a pesar de seguir creciendo. En términos generales, analizando las 12 iteraciones, vemos que la diferencia de trabajo planificado vs trabajo completado no supera el 18%. Esto significado que si este equipo planifica entregar 10 ítems, hay altas probabilidades que al final de la iteración haya completado al menos 8 ítems. El siguiente gráfico muestra el trabajo planificado vs. el trabajo completado para las últimas 3 iteraciones.

Creo que esta característica de previsibilidad es en gran medida consecuencia de un trabajo disciplinado y un crecimiento orgánico.

Algunas métricas de lo realizado hasta aquí:

  • 45 releases a producción
  • 6 meses de trabajo iterativo
  • 382 casos de prueba automatizados que incluyen pruebas unitarias, de integración y aceptación
  • Una cobertura de código superior al 80%

De aquí en más…

Separamos el equipo y separamos el código para permitir que cada equipo sea lo más autónomo posible, pudiendo regular su velocidad delivery sin dependencias. Cada equipo trabajará enfocado en su (sub)producto con sus propios repositorios, infraestructura, microservicio y microfrontend.

Ahora el gran desafío es ver si podemos lograr que ambos equipos mantengan el nivel de efectividad y desempeño logrado hasta el momento.

En un par de meses les cuento.

#HistoriaDeTrinchera: equipo completo

Al cabo de 6 iteraciones hemos completado el equipo. Resulta que al comenzar la sexta iteración se sumó el miembro faltante. Tenemos ahora cubiertos todos los roles/habilidades que consideramos necesarios para llevar adelante el proyecto y al mismo tiempo hemos alcanzado, a mi criterio (no estoy seguro que mis colegas compartan) el número máximo de personas que el equipo puede tener.

Nuestra expectativa es poder tener dentro del equipo todas las habilidades (y autorizaciones) para operar en un esquema de entrega continua dentro de ciertas restricciones organizacionales que por el momento no parecen estar abiertas a negociación (tema de otro post). En este sentido tenemos los siguientes roles/habilidades:

  • Developer
  • Tester
  • Diseñador de UI/UX
  • Facilitador
  • Product Owner
  • Infraestructura

Estos roles/habilidades son ocupados por personas que están en el día a día del proyecto y que como tal participan diariamente de las reuniones de sincronización (daily standups). Algunas aclaraciones que pueden resultar relevantes para el lector:

  • Developers: apuntamos a que puedan desarrollar una funcionalidad de punta a punta, lo cual implica tanto hacer tanto front (angular) como back (netCore) y tocar algunas cuestiones de infra como pipeline de CI/CD y generación de los correspondientes contenedores.
  • Testers: en el sentido de Agile, trabajan muy de la mano de la gente de negocio y con una visión funcional. Colaboran en la identificación/definición de casos y también en su automatización.
  • Diseñadores de UI/UX: diseñan/validan la experiencia del usuario y definen las pantallas. Trabajan muy de cerca con la gente del negocio y los usuarios. No codean, su trabajo llega hasta el maquetado con alguna herramienta tipo Miro, Marvel y Zeplin.
  • Facilitadores: llamados a veces Scrum Masters o coaches, ayudan a que el equipo mantenga el foco en el proceso y la entrega de valor, destraban impedimentos y mantienen los diálogos abiertos con otros equipos/áreas.
  • Product Owners: es gente con perfil de negocio que define el norte del producto, concentra los pedidos de los usuarios y los prioriza.
  • Infraestructura: más allá del control que tenga el equipo sobre la infraestructura es fundamental que el equipo entienda (y pueda definir y discutir) ciertas cuestiones de infraestructura porque pueden impactar en la implementación de algunas características/funcionalidades de la aplicación. En este caso particular, la organización tiene un área de DevOps con la cual nosotros como equipo de desarrollo trabajamos muy cerca en un ida y vuelta constante. Luego ese equipo de DevOps se encarga de la interacción con el resto de los sectores de infraestructura como seguridad, networking, etc.
    (este es un punto que puede resultar polémico y por ello le dedicaré un post aparte)

Todo este conjunto de roles/habilidades está repartido entre 12 personas, varias de ellas con asignación parcial (yo entre ellas). Para mi gusto ya son demasiadas personas y como algunos colegas coinciden con esto, es muy posible que en el corto/mediano plazo sumemos más gente y partamos el equipo en 2.

Un caso de Infra as Code

El manejo de infrastructura como código es relativamente simple cuando la infraestructura es Kubenernetes, pero cuando no es así la cuestión se puede tornar más compleja.

El proyecto en el que estoy trabajando actualmente no utiliza Kubernetes, sino servidores (VMs) con CentOS 7. El front (ember.js) es servido desde un Web Server Apache y el back (java) corre en un Wildfly (jboss). Por otro lado tenemos un SQL Server (el setup de la instancia está fuera de nuestro alcance, pero nosotros nos encargamos de manejar el esquema de datos)

Para manejar todo esto tenemos:

  • Scripts para levantar la VM en la plataforma de VMWare
  • Scripts Ansible para aprovisionar las VMs instalando y configurando Apache, Wildfly, Java, etc
  • Scripts flyway para evolucionar el esquema de base de datos

Estos scripts los utilizamos para administrar 4 ambientes:

  • Desarrollo / Integración
  • Demo
  • Test / Homologación
  • Producción

Adicionalmente a estos ambientes compartidos cada developer tiene una VM (vagrant) local en su máquina de desarrollo, que también es aprovisionada con los mencionados scritps. Este me parece que es un punto central en un esquema de infraestructura mutable: cada developer tiene en su máquina un ambiente para probar que tiene el mismo runtime que el ambiente productivo. Esto no es menor ni tampoco muy común, ya que en general el ambiente del developer tiene un sistema operativo desktop mientras que el resto de los ambientes tiene un sistema operativo server.

De esta forma, más allá de tener versionada la infraestructura, tenemos ambientes uniformes.