Charlando sobre slicing vertical

Hace unos días Agile Delivery organizó un evento en formato Lean Coffee en el que estuvimos unas cuantas personas hablando sobre slicing de producto de software. Lo del slicing viene a ser simplemente ir haciendo rebanadas para organizar el trabajo desde problemas grandes a más pequeños para hacerlos más manejables.

Con la visión waterfalera lo habitual era hacer slicing con un enfoque horizontal descomponiendo por tipo de actividad, por ejemplo: hacer el análisis, diseñar la UI cubriendo todas las casuísticas reflejadas en el análisis, diseñar la base de datos, implementar el frontend de la UI diseñada, programar la lógica de negocio de lo que se definió, hacer pruebas para que todo funciona tal y como se indicó en el análisis… y acabar desplegando a modo big bang como último paso. Así que pueden pasar muchos meses o años para empezar a obtener feedback de que lo que hemos construido aporta valor o para empezar a recuperar la inversión.

La visión agilista cambia esta perspectiva a algo que parece mucho más razonable para crear mejores productos de software, construirlos de forma iterativa e incremental. Para ilustrarlo, y aunque suene un poco vetusto, estos son los principios del manifiesto ágil que se refieren a ello:

  • Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.
  • Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.
  • Working software is the primary measure of progress.
  • Simplicity–the art of maximizing the amount of work not done–is essential.

Atención especial a ese art of maximizing the amount of work not done, principalmente desde el punto de vista de producto. Debemos intentar limitar al máximo el alcance de lo que construimos para que, con el mínimo esfuerzo posible, tratemos de conseguir el máximo valor o aprender lo máximo posible. Esto vendría a conseguirse a través de hacer slicing vertical para organizar el trabajo.

A día de hoy, aún con el boom de lo ágil que hay en el sector tech, es bastante habitual seguir viendo muchos vicios heredados del waterfall. Esto es porque aunque la teoría es simple, llevarlo a la práctica no lo suele ser. Requiere que las organizaciones y equipos tengan una mentalidad enfocada a producto y cierta capacidad técnica para llevarlo a cabo.

  • La mentalidad de producto ayuda a plantear esos slices. Esto es hacer que se focalicen mucho más en los objetivos a conseguir o en las hipótesis que se pretendan validar y que busquen el camino más corto para hacerlo, evitando convertir a los equipos en meros feature factories de quienes se esperan que implementen a pies juntillas lo que alguien les dice.

  • Ciertas capacidades técnicas son necesarias para que los equipos no se vean limitados o paralizados por esas cuestiones, además de para trabajar con más tranquilidad. Por ejemplo tener arquitecturas y diseños que absorban bien los cambios, confiar en los tests automáticos para comprobar que tanto lo nuevo como lo anterior sigue funcionando correctamente, poder entregar software de forma frecuente y con confianza…

En fin, os dejo el video de la conversación que tuvimos, a mi me resultó una sesión muy interesante y entretenida. Cerca del minuto 19 de la grabación es cuando se empieza a entrar en harina:

Salieron experiencias, consejos y referencias más que interesantes. Además pudimos enfrentar puntos de vista diferentes que creo que también aporta, ya que en eso del vertical slicing creo cada uno vamos explorando cosas diferentes que dependiendo de los contextos pueden funcionarnos mejor o peor.

La naturaleza del desarrollo de software, cerrando el círculo del valor

Estoy releyendo el libro de The Nature of Software Development. Keep It Simple, Make It Valuable, Build It Piece by Piece de Ron Jeffries, uno de esos libros donde te encuentras condensadas ideas que merecen ser revisadas de vez en cuando.

Este libro habla de la forma natural de hacer software, the natural way lo llama Jeffries, que viene a ser algo tan simple como focalizarse en entregar valor pronto y a menudo. Simple, que no fácil.

La naturaleza del desarrollo de software

Este no es un libro de recetas con trucos para hacerlo, si no de ideas sobre las que reflexionar y que anima a que explores por tu cuenta modos de hacerlo. Como muestra este es el capítulo resumen de la primera parte del libro llamada The circle of value.

Cerrando el círculo del valor:

  • Valor es lo que queremos. Las funcionalidades entregan valor. Entregar funcionalidades pronto nos da valor antes.
  • Gestionar observando el valor funciona mejor que gestionando fechas o artefactos que no entregan valor.
  • Planificar funcionalidad es bastante fácil de hacer. Estima si debes hacerlo. Seleccionar el trabajo basado en el “tiempo que hizo ayer” funciona mejor.
  • Construir por funcionalidades nos requiere construir un producto pequeño y completo cada pocas semanas. Ese producto debe funcionar siempre correctamente y debería estar siempre bien diseñado.
  • Desarrollo debe entregar funcionalidades reales que funcionen. El producto debe estar bien testeado. La personas de negocio y las de desarrollo contribuyen al testing. El producto debe estar bien diseñado. Los desarrolladores mantienen el diseño vivo todo el tiempo.

Esto es todo al respecto. Muy simple. Un compromiso desde la cima del negocio, hasta los managers y desarrolladores individuales, es todo lo necesario. ¡Vamos! ¡Enséñame el software!

Los principios DevOps: The Three Ways

Llevamos ya unos años en los que se habla de DevOps, un término que originalmente se acuñó para referirse a transformar el modo en el que se entrega software en las organizaciones basándose en ideas de Lean Manufacturing.

Pero en los últimos tiempos, al explotar su popularidad, parece haberse asumido por gran parte del sector como la forma de llamar a los equipos o ingenieros de plataforma, o en otros sitios simplemente como la forma moderna de llamar a los administradores de sistemas; ya que se asocia principal, y a veces únicamente, con despliegues automatizados o con montar infraestructura como código.

Personalmente, es algo que de vez en cuando he hablado con algunos compañeros de profesión, y aunque no es algo que me quite el sueño, sí me apena un poco el hecho de que con ello se pierda la parte más importante del mensaje: romper silos organizativos para centrarse en entregar valor.


Los Three Ways, que son mencionados en libros como The Phoenix Project o en The DevOps Handbook, vienen a ser los principios de los que derivan los comportamientos y patrones que nos ayudarán a romper esos silos y a poner foco en la entrega de valor:

  • The First Way: aumentar el flujo de entrega al cliente previniendo defectos.

  • The Second Way: amplificar los ciclos de feedback para prevenir problemas y mejorar la calidad en origen.

  • The Third Way: crear y fomentar una cultura de experimentación y aprendizaje continuos.

Representación de Los Three Ways de Devops

The First Way: aumentar el flujo de entrega

Hasta que algo no se está usando en producción por los usuarios y/o clientes no se está creando valor, así que deberíamos buscar desplegar de forma temprana y frecuente en producción incrementando la fiabilidad y calidad de lo entregado.

Sus principios son:

  • Hacer el trabajo visible. Típicamente con algún tipo de tablero (tipo kanban, sprint backlog…) donde tener el inventario de trabajo a realizar y su flujo entre “work centers”, permitiendo así detectar cuellos de botella entre ellos.
  • Limitar el WIP. Básicamente tener más foco para acabar antes y pasar el trabajo al siguiente “work center”.
  • Reducir el tamaño de de los paquetes de trabajo: Entregar menos funcionalidades pero con mayor frecuencia.
  • Reducir el número de traspasos: Reducir pasos donde se encole el trabajo y que alargue el tiempo de entrega.
  • Identificar y resolver continuamente los “constraints”: Para reducir tiempos de entrega necesitamos estar continuamente identificando el “constraint” del sistema y mejorar su capacidad de trabajo.

    In any value stream, there is always a direction of flow, and there is always one and only one constraint; any improvement not made at that constraint is an illusion. (Eliyahu M. Goldratt)

  • Eliminar las dificultades y desperdicios del flujo de valor: Cualquier cosa que cause retrasos de cara a la entrega al cliente o actividades que puedan evitarse sin afectar al resultado. En Implementing Lean Software Development categorizan los desperdicios en: Trabajo parcialmente hecho, procesos extra, funcionalidades extra, cambios de tareas, esperas, motion o esfuerzo de transporte/comunicación entre “work centers”, defectos, trabajo manual o no estándar y heroicidades.

The Second Way: amplificar los ciclos de feedback

Una vez entregado, necesitamos feedback rápido y constante, la meta es conseguir un sistema de trabajo cada vez más seguro y resiliente, detectando y resolviendo los problemas cuando son más pequeños y más fáciles de resolver. Pero los fallos son inevitables en sistemas complejos, cuando ocurren se deben asumir como oportunidades de aprendizaje frente a buscar o castigar culpables.

Sus principios son:

  • Ver los problemas en cuanto ocurren: Tener telemetría que muestre cómo se comportan los componentes del sistema en producción para detectar cuando no lo hacen como se espera.
  • Resolver los problemas para construir nuevo conocimiento: Una vez que un problema ocurre debemos resolverlo como un enjambre, movilizando a quienes haga falta para arreglarlo. Llegando a parar todo lo necesario del mismo modo que en el mundo de manufactura se utiliza una cuerda andon.
  • Empujar la calidad cerca del origen: Debemos encontrar y arreglar los problemas en cada área de control, las responsabilidades y toma de decisiones deben ocurrir donde se hace el trabajo.
  • Facilitar la optimización de los “work centers” posteriores: Diseñando para facilidad operacional, donde los atributos de calidad (rendimiento, configurabilidad, testabilidad…) tienen la misma importancia que las funcionalidades.

The Third Way: experimentación y aprendizaje continuos

El objetivo es crear un entorno de alta confianza, reforzando la idea de que estamos aprendiendo de por vida. Aplicando una aproximación científica, tanto para el desarrollo de producto como mejora de proceso, aprendiendo de aciertos y fallos. Además, transformando los aprendizajes locales en mejoras globales para toda la organización.

Sus principios son:

  • Facilitar el aprendizaje organizacional y una cultura de seguridad psicológica: Frente a buscar el error humano, buscar modos en la que se pueda rediseñar el sistema para que no vuelva a ocurrir este accidente.

    By removing blame, you remove fear; by removing fear, you enable honesty; honesty enables prevention. (Bethany Macri)

  • Institucionalizar la mejora del trabajo diario: Reservar tiempo explícito para pagar deuda técnica, arreglar defectos y áreas problemáticas.
  • Transformar descubrimientos locales en mejoras globales: Tratar de convertir la experiencia que obtienen equipos o individuos en conocimiento explícito para la organización para que sea fácil de utilizar (librerías, configuraciones, código…).
  • Inyectar patrones de resiliencia en el trabajo diario: Mejorando las operaciones diarias introduciendo tensión de forma intencionada buscando mejorar (chaos engineering, organizar game days).
  • Los líderes refuerzan la cultura de aprendizaje: Establecer objetivos que enmarquen los experimentos haciendo explícito el problema a resolver, la hipótesis, el método de testearla, la interpretación de los resultados y usar los aprendizajes en las siguientes iteraciones.

Junto la aplicación de las prácticas técnicas (pipelines de despliegue, testing automático, añadir telemetría y alertado, chaos engineering…) y mejorar en ellas; estos principios DevOps nos ayudarán a tener organizaciones donde al entregar valor de negocio antes, se hagan más predictibles y se reduzcan riesgos.

Lo que, en consecuencia, ayudará a reducir estrés en los equipos de tecnología y a que esas organizaciones sean lugares más habitables.

Disponible para ayudar a equipos

Ya sea desde el rol de mentor o de asesor, me encanta ayudar a equipos en todo el espectro que involucra el desarrollo de producto digital.

Esta inquietud tardó en despertar en mí, pero ha aumentado con el paso de los años. Arrancó primero con la iniciativa de Senpai Devs mentorizando a varias personas. Después haciendo algunas formaciones e intervenciones para ayudar a startups y corporaciones junto a mis compañeros de Coding Stones. Más tarde en Inditex donde, además de ejercer como tech-lead en mis equipos, pude aconsejar a algún otro equipo más. Incluso desde unos meses dedico algo de mi tiempo libre a hacer asesorías puntuales.

Ahora, tras mi paso por Devengo, quiero dedicar más tiempo a ayudar a equipos a crear mejor software y producto digital. De hecho, ya estoy cerrando fechas para arrancar un par de colaboraciones.

Haciendo una sesión de mob programming con código proyectado en la pared

¿Ayudar a equipos? ¿Cómo?

Lo de ayudar a equipos quizás queda algo abstracto. Principalmente las actividades que quiero hacer son mentorizar y aconsejar a equipos. Además de esto, una vez identificadas sus necesidades, preparar formaciones y talleres para que adquireran las bases de ciertas prácticas.

Mi intención es ayudar a mejorar extremo a extremo en la creación de producto digital: en el trabajo en equipo, en las prácticas técnicas y en la gestión de producto.

¿En qué puedo ayudar a tu organización o equipo?

Algunos dolores con los que puedo aportar valor son:

  • Habéis empezado a trabajar con procesos ágiles como scrum o kanban y los equipos siguen sin tener los resultados que esperabais. O tal vez estéis pensando en empezar con ello pero necesitáis ayuda para establecer las bases.
  • Tenéis problemas con la capacidad y calidad de entrega, porque en las revisiones, o incluso en producción, se encuentran excesivos bugs. Motivo por el cual queréis incorporar o mejorar en algunas prácticas técnicas. O necesitáis ayuda para identificar qué mejorar.
  • A los equipos les cuesta entregar. Se eternizan las historias de usuario en doing, o incluso quedan semanas bloqueadas.
  • Hay cierto desalineamiento, o incluso tensiones, a la hora de integrar a los diferentes roles del equipo. Típicamente cualquier permuta entre desarrolladores vs diseñadores vs product owners/managers vs administradores de sistemas vs…
  • Se ha acumulado demasiada deuda técnica, así que el legacy no os deja avanzar al ritmo esperado por el negocio.
  • No tenéis muy claro cómo cambiar la mentalidad de trabajar con enfoque a proyecto hacia enfoque a producto, tanto del propio equipo como por parte de stakeholders. Hay más preocupación y presión por cumplir con estimaciones que por lograr objetivos.
  • El negocio va como un tiro y estáis creciendo, eso implica cambiar parte de la arquitectura existente y analizar si hay que reorganizar los diferentes equipos que han ido surgiendo, incluso la forma de esos equipos.
  • En la organización se ve a los equipos de producto o tecnología como un impedimento para nuevas iniciativas y oportunidades de negocio, no como un colaborador y facilitador.

Si identificas alguno de esos problemas en tu equipo u organización, por mi parte estaría encantado de que hablemos para ver si encontramos una forma de colaborar.

Mejorando la velocidad de la suite de tests

Cuando tienes la buena costumbre de escribir tests, ya sea antes o después, vas generando una red de seguridad que nos da feedback para saber que los escenarios cubiertos siguen funcionando correctamente. Eso nos facilita el cambiar el código con mayor confianza ya sea para refactorizar o añadir alguna nueva funcionalidad.

Ese ciclo de feedback debería ser razonablemente corto, debería ayudarnos a concentrarnos y fluir en lo que estemos haciendo en ese momento. Si resulta lento seguramente acabaremos poniéndonos a hacer otras cosas mientras esperamos y seremos menos efectivos.

Tira cómica de XKCD de Compiling

En las suites de tests normalmente los principales cuellos de botella, además de los end-to-end, suelen ser los que hacen uso de sistemas externos como pueden ser la base de datos o el sistema de ficheros. Por eso, en la medida de lo posible, es saludable que las suites de tests traten de parecerse a la pirámide de test.

Pero aún así los proyectos van creciendo y de la mano lo hacen las suites de tests, por lo que ese feedback irremediablemente se va ralentizando. Hay soluciones que minimizan el problema, como usar herramientas que ejecutan algunos tests al guardar el código o usar tags en los tests para ejecutar sólo un subconjunto de ellos.

Pero eso no nos resolverá la raíz de los problemas, puede que incluso los enmascare. Lo mejor es dedicar un tiempo en analizar la suite de tests para detectar qué origina que sea lenta y ver si vale la pena intentar mejorarlo.

Medir y mejorar

Por ejemplo hace poco trabajando en el backend de Devengo, donde tenemos costumbre de escribir bastantes tests, tenía la percepción de que en unas pocas semanas los tiempos de ejecución de la suite de tests que ejecuta conjuntamente los unitarios y de integración habían degradado mucho. Tenía la hipótesis de que revisando los tests de integración podríamos encontrar puntos donde optimizar y obtener feedback antes.

Podría haberme puesto a lo loco a cambiar tests e ir probando si bajaban los tiempos, pero suele ser más productivo utilizar herramientas que te ayuden a detectar las fuentes de los problemas y tomar decisiones en base a los datos que te dan. Así que empecé dedicando algunos ratos de holgura en analizar la suit de tests con TestProf.

Con TestProf pude comprobar qué tipo de artefactos eran en los que se iba más tiempo y cuáles eran concretamente los tests más lentos, que era información bastante interesante. Pero lo más clarificador fue comprobar cómo nuestros tests hacían uso de las factorías de factory_bot que usamos para preparar los tests.

Evidenciaba que el uso de las associations estaban provocando que se estuvieran creando en cascada muchos elementos en la base de datos y que había unas pocas factorías en las que se iba notablemente más tiempo. Ya con esos KPIs es mucho más fácil tomar decisiones de por dónde empezar.

En la primera sentada decidí no tocar el código de producción y reducir el número de elementos que se creaban en cascada, ya que en muchos casos no eran necesarios. Así que los cambios fueron básicamente dos:

  • Minimizar el número de elementos en algunos usos de create_list para que esos tests cubrieran sólo casos límite.
  • Cambiar un buen número de tests para que en la propia preparación se crearan elementos de las associations usando el método create de forma explícita, de ese modo al pasar sus referencias a las factorías se evitaban generar muchas de las creaciones en cascada.

Eso supuso un reducción de entre 15-20% del tiempo. Aún siendo una mejora sustancial había mucho margen de mejora porque el mayor cuello de botella seguía siendo los tiempos de una factoría en concreto.

Tal y como me indicó Iván, estaba claro el principal sospechoso, ya que teníamos anotado un concern de deuda técnica desde hacía tiempo: una dependencia en un callback de ActiveRecord que había que quitar y mover a un sitio más apropiado. Así que en la segunda sentada trabajé en ese refactor y una vez hecho redujo significativamente los tiempos de ejecución, pasando de lanzar la suite en casi 2 minutos a algo menos de 30 segundos en mi máquina.

Conclusiones

Trata de buscar herramientas que te ayuden a medir antes de hacer cambios, es difícil ser consciente de si un cambio provoca mejoras sin ninguna referencia. De hecho, en algunos contextos incluso podría valer la pena instrumentalizar el efecto que tienen este tipo de mejoras en la productividad de los equipos.

A más rápido siempre es mejor pero, igual que con el porcentaje de cobertura, tampoco creo que haya que andar obsesionándose con ello. Así que preocúpate (de nuevo igual que con la baja cobertura) cuando la lentitud de tu suite te esté suponiendo un obstáculo para el flujo en tu trabajo.

Y recuerda que la suite de tests que vamos dejando tiene que aportar valor como red de seguridad para introducir cambios en el código. Así que ante todo debería ayudarnos a documentar lo que hace (y cómo está diseñado) el software y ser expresiva cuando falla.


Más referencias