Completamos la séptima semana/iteración de proyecto y creo que ya estamos acomodados como equipo. Venimos haciendo unos 6 o 7 ítems por iteración, lo cual equivale a unos 13 puntos. Estamos haciendo un buen slicing de ítems a punto tal que casi podríamos hablar de cantidad de ítems por iteración en lugar de puntos. El siguiente gráfico muestra la cantidad de puntos planificados (gris) vs. la cantidad de puntos entregados (verde). La primera iteración se ve como fuera de lugar porque se entregaron varios ítems que un miembro del equipo había estado trabajando unos días antes del inicio del proyecto.
Las piezas centrales de la arquitectura y el walking skeleton ya están construidos, parte de la solución ya está productiva y la próxima semana ejecutaremos las pruebas de performance.
Esta semana ya comencé gradualmente a desvincularme del equipo para en breve pasar a trabajar con otra célula del mismo producto.
Hace unas dos semanas comencé a trabajar en un nuevo proyecto. Yo en Argentina y el resto del equipo en Venezuela y de ahí el «Argenzuela», ¡ja!. En el equipo somos 3 Devs, 1 tester, «proxy» Product Owner (que está en el día a día) y un Product Owner con participación más esporádica.
Al margen del (mal) chiste el proyecto consiste en desarrollar la integración de una aplicación con un Sistema CRM (Customer Relationship Management).
En términos de tecnología estamos trabajando con Ruby y RabbitMQ. En términos de infraestructura la aplicación Ruby la corremos dockerizada en Heroku y para el Rabbit usamos el servicio de Amazon. Como herramientas de gestión/desarrollo estamos utilizando el stack de Atlassian: Jira, Confluence y Bitbucket.
Trabajamos «a la XP», iteraciones semanales, TDD, CI/CD, diseño simple, refactoring, mucho pairing y otras yerbas varias.
El proyecto tiene un par de desafíos técnicos y de negocio interesantes pero al margen de eso me gusta la dinámica que equipo que estamos construyendo. Continuará…
Estamos semana comenzamos a trabajar en la nueva aplicación móvil de Radiocut. A diferencia de la aplicación anterior que estaba construida con Cordova/Ionic, esta vez decidimos utilizar React Native.
Son varias las razones para trabajar con una tecnología de este tipo en lugar de trabajar directamente con tecnología nativa:
Somos un equipo chico, generalista y «multi tecnología», trabajar con tecnologías nativas sería demasiado esfuerzo ya que tendríamos que codear y mantener dos aplicaciones completamente distintas (una android y otra ios) en lenguajes distintos, Java/Kotlin y ObjectiveC/Swift ninguno de los cuales forma parte de nuestro stack actual.
Las características de la nuestra aplicación no requieren trabajar con tecnología nativa, creemos que casi todas las funcionalidades las podemos implementar sin mayores complicaciones sin tener que tocar código nativo.
Una vez decidido el uso de React Native hay dos cuestiones que debemos definir en forma temprana: el CLI y el lenguaje. El proyecto React Native se crea con una herramienta de línea de comandos (CLI) que genera código y simplifica el bootstrap del proyecto. En este sentido una opción es usar el CLI de React Native pero hay también otra opción: Expo CLI. Importante: ambos CLIs son herramientas JavaScript con lo cual para instalarlos solo necesitamos de Node/NPM.
Expo CLI nos ofrece un bootstrap simplificado, o sea, nos provee un proyecto base que ya cuenta con varias cuestiones «pre-configuradas». Al mismo tiempo no requiere que nos instalemos el tooling para desarrollo nativo (Android SDK/xCode) ya que el build final de nuestra aplicación se hace en el servicio cloud ofrecido por Expo.
Por su parte el CLI de React Native nos provee «menos asistencia», hay más cuestiones que tendremos que manejar nosotros mismos y al mismo tiempo tendremos que instalarnos el tooling para desarrollo nativo.
Comparativamente los puntos que tenemos que considerar para eligir el CLI son:
El binario generado por Expo termina típicamente siendo más pesado que el binario que genera el CLI de React Native.
Expo CLI nos simplifica muchas cuestiones y nos provee un mayor nivel de abstracción y por su parte el CLI de React Native nos «hace trabajar más» pero nos da un mayor control de la aplicación/código.
Al trabajar con Expo CLI dependemos del servicio cloud de Expo para la generación del binario final.
La forma en que estas 3 cuestiones impactan en cada proyecto son particulares de cada proyecto. En nuestro caso decidimos ir por el CLI de React Native.
Una vez elegido el CLI, podemos avanzar con la creación del proyecto y eso lleva a una nueva elección: el lenguaje. Podemos trabajar con TypeScript o JavaScript. En nuestro caso elegimos JavaScript ya estamos acostumbrados a trabajar con lenguajes de tipado dinámico y todo nuestro código client-side ya está escrito en JavaScript puro.
Hasta aquí, nuestros primeros pasos. En siguientes entregas iré compartiendo:
Hay muchas descripciones teóricas en libros, artículos y conferencias sobre cómo trabajar con la metodología Extreme Programming, pero muy pocos dando detalles. En este sentido un recurso excelente es el libro de Henrik Kniberg, Scrum and XP from Trenches. Al margen de ello, quiero compartir aquí algunos detalles de implementación de la forma en la que trabaja el equipo del cual soy parte actualmente.
Equipo (la gente está en todas las dailies):
5 Devs (skills de front, back, ci/cd, infra)
1 Tester
1 UX
1 facilitador
2 personas de negocio
Proceso:
Duración de iteración: 2 semanas calendario, time-boxed
Daily Stand-up: todos los días 9.15
Revisión de iteración & Demo: Jueves de 10:00 a 10:30 (cada 2 semanas)
Retrospectiva: Jueves de 10:30 a 11:30 (cada 2 semanas)
Planificación estratégica: Jueves de 11:45 a 13:00 (cada 2 semanas)
Planificación táctica: Jueves de 14:00 a 16:00 (cada 2 semanas)
Refinamiento: por el no tiene un horario ni cadencia fija, viene variando de iteración en iteración
Invision (el nombre aún no me cierra): martes de 11:00 a 12:00 tenemos esta reunión semanal donde coordinamos con otro equipo que desarrolla una API con la cual tenemos un importante dependencia
Prácticas de desarrollo:
Trunk-based Development, todo el equipo, todo el tiempo trabajando en la misma rama
Pair-Programming, todo el tiempo
TDD todo el tiempo en el código server-side (C#)
Test-Last en el código de client-side (angular)
Despliegue automatizado a todos los ambiente
Feature Toggling
Stack tecnológico:
Net Core 3.1
Angular 9
Gitlab (versionado de fuentes & pipeline)
Artifactory (versionado de binarios)
RunDeck (deploy automation)
Specflow, NUnit, Postman/Newman y Jess (test automation)
Visual Studio Code, Visual Studio, WebStorm & Rider (IDEs para todos los gustos pues tenemos gustos muy distintos)
Herramientas de gestión / colaboración
Microsoft Teams (chat & calls)
Miro & Zeplin (diseño & mockups)
Jira (backlog)
Confluence (wiki)
Algunas de estas cuestiones de esta forma de trabajo no me terminan de convencer (por ejemplo yo preferiría hacer iteraciones de 1 semana) pero por el momento nos viene funcionando bien, el negocio está contento y ningún miembro del equipo ha planteado desconformidades relevantes.
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.
Completamos la séptima iteración entregando menos de lo que habíamos planificado y eso generó cierto debate en la planning de la octava iteración, llevando incluso a que algunos miembros del equipo quieran replantear la forma de estimación.
Hasta el momento hacíamos lo siguiente:
Repasar el backlog candidato determinado por el Product Owner, asegurando que entendíamos cada uno de los ítems
Estimar «a ojo» los item que consideramos podríamos llegar a completar en la iteración por comenzar
Asignar puntos (1, 2 o 3) a cada uno de los items, principalmente para estar seguros que todos los miembros del equipo teníamos una idea similar de las implicancias/alcance de cada ítem. Importante: estos puntos no los utilizamos para determinar la cantidad de trabajo de la iteración, sino simplemente como un mecanismo de doble validación interna.
Con este mecanismo en la iteración 7 planificamos unos 23 items pero completamos unos 18.
Antes de continuar debo decir que:
En la gran mayoría de equipos que he estado involucrado «con problemas de estimación», resultó que en realidad era mucho más grave el problema de ejecución que el de estimación
Para equipos comprometidos, auto-organizados y trabajando en iteraciones cortas y con un esquema de continuous delivery no creo que valga la pena estimar «formalmente» con puntos/horas ni nada por el estilo más allá de la sensación del equipo
Dicho todo esto, mientras parte del equipo debatía sobre los ajustes al método de estimación/planificación, me puse a repasar el histórico de iteraciones en el Jira y confirmé mi sospecha viendo unos de los reportes provistos por la herramienta:
El nombre que la herramienta da a este gráfico es «Reporte de Velocidad» el mismo muestra en gris el plan del equipo al inicio de cada iteración y en verde lo efectivamente completado al final de la iteración. Se supone que a partir de este gráfico uno podría deducir una velocidad/capacidad del equipo que puede resultar útil a la hora de planificar.
Analizando este caso particular uno podría decir que este equipo puede entregar alrededor de 18 puntos por iteración. Sin embargo, ese no es el dato más importante de este gráfico para mí.
Lo que me resulta más relevante de este gráfico es la predecibilidad. Puede verse que independiente del número X planificado, este equipo entrega consistentemente con un desvió promedio de ~18 %, siendo este desvío en ocasiones positivo (se entrega más de lo planificado) y en ocasiones negativo (se entrega menos de lo planificado). Más aún, si eliminamos del cálculo la iteración 4 que fue particularmente corta en términos de días laborales (por feriados) y que tuvo una variación de equipo (se sumo una persona), el desvío promedio cae por debajo del 15%. Personalmente creo que es un grado de predecibilidad muy bueno, sobre todo si consideramos que el equipo tiene la capacidad (tanto a nivel proceso como de infraestructura) de entrega software potencialmente todos los días.
En general prefiero no hablar de la velocidad de un equipo pues creo que puede generar falsas expectativas por la sola terminología. Alguien fácilmente podría tentarse de pedirle al equipo que aumente su velocidad generando así presiones para el equipo. Y ni hablar de quienes pretenden comparar la velocidad de distintos equipos. Es por esto que prefiero no hablar de velocidad como una característica del equipo. Prefiero caracterizar al equipo por cuan predecible es.
En el camino nos encontramos con varios imprevistos relacionados principalmente con las aplicaciones existentes con las que teníamos que interactuar. Cuestiones principalmente de networking, seguridad y accesos. Todas cuestiones que intentaremos ir puliendo en las próximas iteraciones.
El siguiente gráfico resume la arquitectura productiva de nuestra aplicación:
Nuestra aplicación consiste en un frontend construido con Angular (servido por Nginx) y un backend construido con Net Core (aspnet/kestrel) que consume servicios WFC/SOAP que proveen acceso al core de la organización. Tanto front como back son empaquedados en imágenes docker que luego corren en Kubernetes. Dentro de Kubernetes tenemos pods de front y pods de back que en ambos casos corren en un esquema de sidecars con filebeat. Esto es: cada pod corre dos contenedores, uno con nuestra aplicación (front o back) y uno con filebeat que se encarga de leer los logs escritos por nuestra aplicación y mandarlos a Elastic/Kibana para tener así un acceso centralizado al log. Por otro lado, por fuera del cluster Kubernetes hay un conjunto de dispositivos de red (routes, balancers, firewalls, etc) y servidores de distintos tipo donde corren los servicios con los que interactua nuestra aplicación.
En próximos post compartiré algunos detalles de nuestra forma de trabajo y nuestro pipeline de delivery.
El jueves pasado completamos la primera iteración. Construimos una funcionalidad mínima pero que nos sirvió para sentar las bases del proyecto y mitigar muchos riesgos técnicos. Al mismo tiempo montamos la infraestructura de CI/CD y el ambiente de desarrollo.
En esta segunda iteración tenemos el objetivo de agregar un poco más de funcionalidad, ajustar la estética/pantallas de la aplicación e ir a producción. Para esto tenemos 8 días hábiles. Puede parecer más que suficiente pero yo tengo mis dudas. Ninguno de los presentes en la reunión de planificación conocía a ciencia cierta el procedimiento formal para ir a producción con una nueva aplicación. La complejidad radica en que la organización es una entidad financiera que está sujeta a ciertas normas y regulaciones generales definidas por una entidad controladora externa. Al mismo tiempo ocurre que la implementación de algunas de esas normas es en ciertos casos obsoleta, extremadamente burocrática y sin sentido.
Estábamos arrancando con el setup del proyecto y nos enteramos que el área arquitectura definió que el único que puede aprobar los merge-requests a master es el Maintainer. Curiosamente arquitectura asignó el rol de Maintainer en nuestro proyecto al Scrum Master, el único miembro del equipo (junto con el PO) que no codea, ¡ooops!
Ayer comenté esto en twitter y generó varias reacciones.
Lo que me incomoda de esta situación no es el hecho de quién puede aprobar los merge-request sino el hecho de que alguien externo al equipo defina cómo debe trabajar el equipo. Entiendo que haya ciertos lineamientos generales en cuestiones que puedan tener impacto fuera del equipo, pero cuestiones como el esquema de branching creo que no es una de esas cuestiones.
Al mismo tiempo quiero destacar que si bien recién estamos comenzando con el proyecto, la persona en el rol de Scrum Master me cae muy bien, creo que está haciendo un buen trabajo y si bien actualmente no codea lo hizo en el pasado.
Otra curiosidad es que en los lineamientos de arquitectura se asume en cierto modo que el equipo utilizará branches y merge-request, cuando en realidad la intención de nuestro equipo es hacer trunk-based development trabajando de pares para todo código productivo.
En fin, como conozco a uno de los referentes de arquitectura y me parece una persona bastante criteriosa y accesible lo llamé por teléfono para comentarle esta situación. Me explicó algo razonable: solo una persona por equipo tiene el permiso Maintainer y cuando se creo el proyecto el único miembro del equipo de desarrollo que estaba confirmado era el Scrum Master. Adicionalmente me explicó que lo que hizo arquitectura no fue establecer «reglas de piedra» sino lineamientos generales que surgieron del diálogo con diversos referentes de la organización y que pueden revisarse en cada caso particular. Esto también me resultó muy razonable. Más aún me parece muy sano cuando uno comienza un proyecto no se encuentre con la nada misma, está bueno tener algunos lineamientos que luego uno pueda debatir y eventualmente ajustar.
Cerrando la historia pinta que el equipo trabajará sobre un branch develop y luego en la salida a producción haremos el trámite de merge-master.
Esta semana estoy arrancando formalmente un nuevo proyecto. La semana pasada hicimos el descubrimiento de producto y como parte del mismo identificamos objetivos de negocio y métricas para medir el éxito. También definimos algunas cuestiones de estrategia tanto técnica como de negocio.
Entre los desafíos del proyecto hay algunas cuestiones que me parece relevante mencionar:
Un equipo de desarrollo distribuido en 2 ciudades y conformado por personas de 4 organizaciones distintas.
El uso de un conjunto de tecnologías de desarrollo (.net core y angular) en las que la mayoría del equipo no tiene experiencia.
El uso de una infraestructura de ejecución (docker y kubernetes) en la que la mayoría del equipo no tiene experiencia.
La necesidad de generar un entregable de valor en un tiempo máximo de 6 semanas.
La integración con una aplicación legacy.
Requerimientos concretos de accesibilidad.
El uso de ciertas prácticas de desarrollo de cara a intentar asegurar la calidad del entregable (continuous delivery, test-automation, infra as code, etc)
Mi participación en el proyecto tiene que ver principalmente con ayudar en los puntos 2, 3 y 7.
Como parte del trabajo de discovery (que duró 3 días) generamos también algunos acuerdos de trabajo:
Trabajaremos en iteraciones de 2 semanas
El jueves será el día de las ceremonias de planning/review/retro
La daily standup será 9.30
El trabajo lo organizaremos en Jira
Para la comunicación diaria utilizaremos Microsoft Teams
Para el código utilizaremos GitLab
Jenkins será nuestro Build Server
Me gusta mucho que la daily sea tempranito pero no me gustan tanto las iteraciones de 2 semanas, sinceramente prefiero iteraciones de 1 semana, pero en bueno, es algo con lo que puedo vivir.
A medida que el proyecto vaya avanzando iré compartiendo novedades en este espacio.