Tuesday, July 16, 2024

El coste basal del software

Traduccion del articulo original Basal Cost of Software
Traduccion realizada por https://x.com/simonvlc y publicada originalmente en su genial newsletter Estrategia de Producto: El Coste Basal del Software
---

En mi opinión, el coste de desarrollo de cada funcionalidad en un producto puede dividirse de la siguiente manera:

  1. El coste directo de desarrollo o coste inicial.
  2. Un coste semanal o mensual únicamente asociado con su existencia en el sistema. Haciendo una comparación con la Tasa Metabólica Basal del cuerpo humano, podríamos llamar a este segundo coste la Tasa Metabólica Basal o Coste Basal.

El Coste Basal se compone de dos partes diferenciadas:

  • El impacto directo en la capacidad del equipo debido a la complejidad añadida (nuevas dependencias, más código para entender, más posibilidades de bugs ocultos, etc.).
  • El impacto en el coste de desarrollo o evolución de otras funcionalidades debido a posibles incompatibilidades, acoplamiento, etc.

El coste inicial

Es el coste incurrido por el equipo durante el desarrollo inicial de la funcionalidad. Incluye el coste desde que el equipo comienza a trabajar en la funcionalidad hasta que el cliente la tiene disponible y comienza a usarla. Por supuesto, este proceso debería consistir en múltiples despliegues y lanzamientos parciales para obtener feedback y hacer los ajustes necesarios...

El Coste Basal

Tras el coste inicial de desarrollo, afrontamos también un coste continuo que reduce la capacidad del equipo para el desarrollo de nuevas funcionalidades (innovación).

Este coste, que continúa con el tiempo y solo termina con la eliminación de la funcionalidad o el fin de vida del producto, es el coste que paga el equipo por la existencia de ese código en el producto.

Es importante tener en cuenta que este no se refiere al coste de hacer modificaciones o corregir errores; se refiere al coste de simplemente tener el código allí...

¿Por qué se da este coste? ¿Por qué una funcionalidad que no evoluciona supone un coste? 

  • El equipo tiene que conocer ese código (dónde está, qué dependencias tiene, qué interactúa con él, cómo está diseñado...).
  • El conocimiento y las técnicas del equipo están en constante evolución. Cuando mejora en cualquiera de estos aspectos, deberá actualizar el código.
  • Cuando el equipo diseña una nueva funcionalidad, el código debe ser diseñado de manera que sea compatible con todas las anteriores y no genere problemas o regresiones. Y, por supuesto, este coste es proporcional a todas las que ya teníamos en el sistema.
  • Algo similar ocurre cuando un nuevo miembro se une al equipo. Este nuevo integrante debe aprender sobre todas las funcionalidades, por lo que el coste es proporcional a su número..

Y lo peor de todo, este sobrecoste es continuo hasta la "muerte" de la funcionalidad. Por ejemplo, hasta el fin de la vida del producto, hasta que ningún usuario la use, o hasta el fin del mundo (lo que ocurra primero).

Evolución del coste de una funcionalidad

Como hemos visto, el Coste Basal de una funcionalidad es más o menos constante durante su vida. Pero cada lenguaje, dependencia o tecnología que hayamos usado en su desarrollo, puede alcanzar un punto en el que ya no es utilizable por cualquier razón (dependencias obsoletas, problemas de seguridad, evolución normal que deprecia la versión del lenguaje que usamos, etc.). Desde este momento, el coste puede dispararse porque estamos obligados a actualizarlo, incluso aunque no queramos evolucionar la funcionalidad.

En resumen, el coste real puede ser representado por el siguiente gráfico:

El problema

Un error común es negar el Coste Basal y considerar que si no se hacen cambios, el coste de mantenimiento de una funcionalidad es cero. Supongo que esto proviene de utilizar metáforas de otras profesiones como la construcción, que no son aplicables al desarrollo de software.


La capacidad no es infinita

A pesar de que la capacidad de un equipo cambia (positiva o negativamente) con el paso del tiempo debido a distintos factores (conocimiento del negocio, técnicas, estrés…), esta es finita.

El Coste Basal acumulado de todas las funcionalidades de las que el equipo es responsable reduce la capacidad disponible para desarrollar nuevas funcionalidades (innovar).

Con el tiempo, podemos observar como la capacidad del equipo para innovar decae rápidamente:

Hasta el punto de que cuando la capacidad se agota, el equipo se encuentra en una situación en la que le es imposible innovar porque pasa todo su tiempo “manteniendo” las funcionalidades de las que es responsable.


O bien reduce su velocidad al desarrollar nuevas funcionalidades, acumulando coste basal, pero a menor ritmo.

Conclusiones

Las secciones anteriores destacan varios principios que debemos considerar para mejorar la eficiencia de nuestros equipos de producto.

  • Debemos minimizar el Coste Basal tanto como sea posible, logrando el impacto deseado con la menor cantidad de código posible.
    • Cuando sea posible, incluso sin añadirlo.
    • Iterando la funcionalidad, partiendo de una solución mínima, para adaptarla lo más posible a las necesidades del usuario.
    • Haciendo el software/diseño lo más simple posible. Debe ser fácil de evolucionar sin sobreingeniería (YAGNI).
  • Debemos eliminar cualquier funcionalidad del producto que no tenga el impacto deseado, eliminando así su Coste Basal.
  • Debemos monitorizar continuamente el código del equipo para detectar la obsolescencia de dependencias, lenguajes y tecnologías para evitar que el Coste Basal se dispare.

Veamos un ejemplo teórico sencillo para ayudar a transmitir el mensaje. Supongamos que un equipo acumula un 1% de Coste Basal por semana, lo que significa que, por cada 100 unidades de producto (código, características, mejoras), añade 1 unidad de Coste Basal. A medida que este se acumula, en 52 semanas (aproximadamente 1 año), el equipo solo podrá dedicar el 60% de su capacidad a nuevas funcionalidades/mejoras (innovación). En dos años, será apenas el 35%. Por supuesto, este ejemplo es una simplificación, pero destaca que negar este coste no es una opción viable.


Recordad: Simplificar — el arte de maximizar el trabajo no hecho — es esencial.

Relacionado y referencias

Otros artículos interesantes


Monday, July 01, 2024

Decidir lo más tarde Posible: Limites de Producto

Como mencionamos en el artículo anterior de la serie sobre Lean Software Development, continuaremos explorando técnicas que nos permiten tomar decisiones lo más tarde posible.

Empezamos por definir sistemáticamente Limites de Producto.

Al desarrollar un incremento de la solución que estamos implementando, es fundamental establecer límites concretos en todos los parámetros que puedan introducir complejidad. Esto nos permite centrarnos en lo que aporta valor ahora y posponer soluciones más sofisticadas, evitando el coste y la complejidad añadida. Con el tiempo, esos límites irán cambiando y nos obligarán a modificar la solución, pero con esta aproximación podremos decidir cada solución lo más tarde posible y evitar hasta ese momento el coste de desarrollo y evolución de esa solución más compleja.


Es crucial que al definir un límite, este se incluya en el código o solución para que, si se supera, la aplicación se comporte de manera controlada, avisando al equipo y, posiblemente, al usuario.


Ejemplos de límites que he usado:

  • Número de clientes/usuarios totales.
  • Número de clientes/usuarios concurrentes.
  • Tamaño máximo de ficheros que se pueden subir al sistema.
  • Cuotas por usuario (almacenamiento, requests, número de entidades, etc.).
  • Valores numéricos por cualquier concepto de negocio (del problema).
  • Tiempos de respuesta a las distintas peticiones.
  • Resoluciones/Dispositivos para la IU

Si no definimos claramente estos límites de manera numérica, estamos abriendo la puerta al diseño especulativo para resolver situaciones que aún no enfrentamos.


Ejemplos de uso de límites para "decidir lo más tarde posible"

Conocer y definir el número total de clientes en varias ocasiones me ha permitido ofrecer soluciones muy sencillas para la persistencia, que nos han sido útiles durante meses antes de necesitar cambios. Por ejemplo, si el número de usuarios es pequeño, usar persistencia en fichero y cargar la información a memoria es factible. También nos permite usar soluciones tipo SQLite y posponer la decisión de meter un motor de BD independiente.



Al limitar el tamaño de las solicitudes (en cuanto a volumen) y definir los escenarios de conexión, podemos ofrecer soluciones robustas y simples, procesando las solicitudes de forma síncrona. Esto permite posponer la necesidad de tener una solución asíncrona. Como ejemplo, en una ocasión teníamos que aceptar que el usuario subiese ficheros al sistema; la primera implementación solo permitía ficheros muy pequeños, esto nos permitió hacer una implementación sencilla y tener feedback muy rápido (menos de 2 días). Pasadas unas semanas, una vez que vimos que tenía sentido la funcionalidad, mejoramos la implementación para soportar ficheros más grandes.


En varias ocasiones hemos enfrentado situaciones donde cada usuario acumulaba almacenamiento (archivos/objetos). En estos casos, el definir un límite de producto para el total de almacenamiento para todos los usuarios, otro límite para cada usuario y otro límite para definir cuándo teníamos que empezar a preocuparnos por este problema, nos ayudó a posponer la implementación de cualquier medida de control y gestión de este almacenamiento hasta que se llegase a cualquiera de los límites definidos.



Para ilustrar el uso sistemático de estos límites con un ejemplo concreto, en Alea Soluciones lanzamos un nuevo producto de gestión/control de una red de fibra y los routers de los clientes finales en menos de 3 meses. Sabíamos que nuestros clientes en ese momento no tenían más de 1000-2000 usuarios. Sabíamos que los operadores del sistema de gestión no eran más de 2-3 personas concurrentes. Sabíamos que para tener más usuarios nuestros clientes tenían en muchos casos que desplegar fibra hasta la casa o al menos ir a la casa del usuario a instalar el router; esto implicaba que no era posible que creciesen a más de 2-5 usuarios por semana. Con este contexto, la primera versión del sistema inicial de gestión era un servidor web que procesaba todo de forma síncrona y con la información de usuarios en memoria y que simplemente persistía los cambios a un fichero cuando se necesitaba. Esto permitió que dedicásemos mucho tiempo adicional al resto de componentes del sistema (integración con cabeceras de fibra, sistema de configuración remota de los routers, sistema de monitorización de los routers, etc.). Evidentemente, el sistema fue evolucionando y fuimos mejorando ese sistema, pero siempre esperando al último momento responsable para cada decisión de introducir nueva tecnología.


Otro ejemplo sencillo es en ClarityAI, donde para crear un chat ops en Slack que ofreciera algunas capacidades internas de la plataforma, se definieron ciertos límites, tanto en tiempos de respuesta máximos como en volumen de información tratada. Al definir un tiempo de respuesta máximo alto (2s) pero menor del soportado por slack para la respuesta sincrona a comandos de slack (3s), pudimos posponer bastante tiempo la implementación de una solución asincrona. Esa aplicación trabaja con información de inventario de componentes técnicos (repositorios de código, repositorios docker, etc) y de equipos y personas. Vimos que nos era fácil definir unos maximos para cada uno de los elementos y vimos que en todos los casos el máximo estaba por debajo de 1000 elementos. Estos limites nos permitieron evitar bastante complejidad, simplemente apoyandonos en un backend NoCode (Airtable) como BD, que además nos proporcionaba un frontal de administración básico. Sabemos perfectamente que cuando superemos esos limites, tendremos que pensar en una solución más sofisticada y escalable, pero posponer esa decisión nos ha permitido desarrollar muy rápido en esa aplicación durante más de dos años y medio.


Recursos Relacionados:

Sunday, June 30, 2024

Lean Software Development: Decidir lo Más Tarde Posible

Lean Software Development parte de la premisa de que el desarrollo de software y productos digitales es un ejercicio constante de aprendizaje (ver amplificar el aprendizaje). Con esta premisa, es claro que cuanta más información tengamos antes de tomar una decisión, mayor será la calidad de la misma. Por tanto, decidir lo más tarde posible nos permite ser más efectivos. Al mismo tiempo existe un coste (o riesgo) asociado a no tomar una decisión que crece con el tiempo, por lo que debemos buscar el “último momento responsable”, que es el punto óptimo para tomar la decisión con la mayor información posible, sin que el coste de no tomarla supere el beneficio potencial de obtener más información y seguir postergándola.

Ventajas posponer decisiones y mantener opciones abiertas

Postergar decisiones es una estrategia fundamental en el desarrollo de software lean. Aunque no siempre es fácil y requiere práctica, esta táctica permite la creación de productos sostenibles y fáciles de evolucionar. Una de las principales ventajas de tomar decisiones más tarde es que nos brinda una mejor comprensión tanto del negocio como de la tecnología, lo que a su vez facilita la toma de decisiones más informadas y acertadas.

Además, retrasar decisiones conduce a soluciones más simples y pequeñas, lo cual reduce el esfuerzo necesario para implementarlas y evita el sobrecoste basal. Manteniendo nuestras opciones abiertas, nos enfocamos únicamente en lo que aporta valor real en el presente, evitando la sobre-ingeniería y el trabajo innecesario. Esta flexibilidad nos permite reaccionar de manera rápida y efectiva a cualquier cambio sin temor, lo que es crucial en un entorno tan dinámico como el desarrollo de software.

Algunas de las ventajas específicas de posponer decisiones incluyen:

  • Menos trabajo y desperdicio: Implementar solo lo necesario en el momento reduce el trabajo total y el desperdicio.
  • Menor esfuerzo en rehacer trabajo: Si es necesario cambiar algo, hay menos esfuerzo requerido ya que se ha evitado sobre-ingeniería.
  • Mayor flexibilidad y adaptabilidad: Mantener opciones abiertas nos permite adaptarnos rápidamente a nuevos requerimientos o cambios en el entorno.


Una arquitectura bien diseñada permite posponer decisiones importantes sin comprometer la calidad o la flexibilidad del producto. Esto no solo nos da la capacidad de tomar decisiones más informadas, sino que también facilita la creación de una buena arquitectura que, a su vez, permite posponer otras decisiones críticas en el futuro. En resumen, esta estrategia nos permite movernos con menos carga y mayor agilidad, mejorando nuestra capacidad para entregar valor continuamente.

Decisiones

Mis equipos son equipos empoderados (extremo a extremo) que tienen completa decision sobre como solucionar las problemas y en muchos casos incluso en decidir qué problemas solucionar. En un equipo así, se toman numerosas decisiones todos los días y de todo tipo. Decisiones sobre el problema, sobre potenciales soluciones, sobre implementaciones de esas soluciones, sobre la priorizacion relativa de dónde invertir (en solventar algo, en despejar incertidumbre sobre una decisión técnica o de producto, en decidir siguientes incrementos, etc).

Por ejemplo, al comenzar un nuevo producto o funcionalidad, el nivel de incertidumbre suele ser muy alto. En estos casos, priorizamos reducir esa incertidumbre, dividiendo decisiones y suposiciones críticas en partes más pequeñas, e invirtiendo en incrementos de producto para obtener más feedback y así reducir la incertidumbre.


A medida que recibimos retroalimentación, aprendemos más y ajustamos nuestras suposiciones/hipótesis en consecuencia. Este proceso iterativo nos ayuda a pasar de una gran incertidumbre a una mayor claridad y confianza.

Al validar continuamente los supuestos, reducimos los riesgos y tomamos decisiones más informadas. 

Todas estas decisiones se producen de forma continua y a todos los niveles. Es parte de la naturaleza de nuestra profesión.

Si tuviesemos que clasificar el tipo de decisiones a tomar, lo podriamos hacer de la siguiente forma:

  • Decisiones sobre el problema y oportunidad a explorar
    • Qué: Donde debemos invertir y por qué
    • Cómo: Qué solución o estrategia de implementación creemos que es adecuada para el caso seleccionado.
  • Decisiones sobre tecnologia e implementacion
    • A nivel de arquitectura y tecnologias usadas
    • A nivel de diseño de la solución a diferentes niveles

Es importante tener en cuenta que las decisiones nunca son independientes; siempre deben considerar el contexto y el conocimiento del equipo, así como el sistema o producto existente. Es como si viéramos los problemas y oportunidades como la diferencia en conocimiento o implementación, de lo que conocemos o tenemos y lo que queremos conseguir.

Es decir, que siempre se trata de hacer pequeños incrementos en la dirección y con el objetivo que necesitemos. A veces se trata de aportar valor al usuario, otras veces de reducir la incertidumbre de una decisión que debemos tomar. Siempre, es un incremento en el software (producto/sistema) o en el conocimiento que tiene el equipo.

Dividir decisiones para abordarlas individualmente

Una de las formas principales de incrementar nuestras posibilidades de posponer decisiones es dividir grandes decisiones en pequeñas decisiones y separar muy bien aquellas de facil reversibilidad de las que sean irreversibles (o muy dificiles de revertir).

Por lo tanto, trabajar decidiendo lo más tarde posible implica hacerlo en pasos o incrementos muy pequeños, lo cual está totalmente alineado con la mentalidad Lean (trabajo en lotes pequeños).

Este proceso de dividir es una práctica continua que permite al equipo afrontar desde donde va a invertir en el siguiente cuatrimestre hasta decidir qué es lo que va a hacer en las siguientes horas. Debemos verlo como una forma de pensar sistemática que se aplica de manera recurrente a todos los niveles.

Conclusiones

Decidir lo más tarde posible es una estrategia clave en el Lean Software Development que maximiza la calidad de las decisiones al aprovechar la mayor cantidad de información disponible. Esta práctica contribuye a la creación de productos más sostenibles, flexibles y adaptables.

Las principales ventajas son:

  • Reducción del desperdicio: Enfocarse solo en lo necesario minimiza el trabajo redundante y evita la sobre-ingeniería.
  • Mayor flexibilidad: Mantener opciones abiertas permite adaptarse rápidamente a cambios en el entorno o requisitos.
  • Decisiones más informadas: Postergar decisiones hasta el último momento responsable resulta en decisiones más acertadas y efectivas.
  • Incremento en la adaptabilidad: Facilita la implementación de soluciones simples y pequeñas, reduciendo el esfuerzo para realizar cambios y mejoras.

Es fundamental que los equipos empoderados adopten esta mentalidad y se acostumbren a dividir las decisiones en pasos manejables. Al hacerlo, pueden reducir la incertidumbre de manera incremental, validando continuamente sus supuestos y ajustando estrategias según el feedback recibido. Este enfoque iterativo disminuye riesgos y refuerza la capacidad del equipo para entregar valor continuo.

En los siguientes artículos, exploraremos estrategias y ejemplos concretos sobre cómo posponer decisiones de manera efectiva, proporcionando herramientas prácticas para implementar esta filosofía en tus proyectos de desarrollo de software.


Recursos relacionados


Sunday, June 23, 2024

Good talks/podcasts (June 2024 I)




These are the best podcasts/talks I've seen/listened to recently:
  • (Spanish) Impulsando el crecimiento organizacional a través de la Developer Experience (Angélica Lozano, José Rodríguez Huerta) [Devex, Engineering Culture] [Duration: 01:07] Interesante conversación sobre el funcionamiento y organización de MLean con Angélica CTO y fundadora. Interesantes ideas sobre como conectar la experiencia de desarrollo con las necesidades de la compañia, la organizacion de equipos, las particularidades del negocio, como balancean las distintas inversiones en ingenieria. 
  • Software Engineering F&*K Up Behind The Passport E-gate Failure" (Dave Farley) [Architecture, Resilience, Software Design] [Duration: 00:17] In this episode, Dave Farley talks about the issue, how poor software engineering led to this, how distributed systems come into it all, how to avoid something like this happening again and at the end of the video asks for answers on some concerning issues around the whole story.
  • Perspectives on effective product development culture (Jason Yip) [Culture, Engineering Culture, Product] [Duration: 00:39] Good description of what an efficient product development culture should be like. Jason talks about the pillars of that culture, the guiding principles, and even the main practices, including technical, product, and organizational practices.
  • Lean Code (Kevin Kelly) [Agile, Lean Software Development] [Duration: 01:05] (⭐⭐⭐⭐⭐) Interesting approach to lean software development focused on how to tackle agile development with this lean mindset. It contains a few interesting points.
  • Designing for Habitability (Sam Newman) [Platform, Platform engineering] [Duration: 00:27] Tips and tricks for creating platforms that truly accelerate the pace of innovation in companies.
  • Fighting User Requirements That CONSTANTLY Change (Dave Farley) [Nature of Software Development, Product] [Duration: 00:13] (⭐⭐⭐⭐⭐) Great description of the true nature of software development as an adaptive learning process of customer needs. A must.
  • Continuous Delivery vs. Gitflow & CD At Scale | Bryan Finster In The Engineering Room Ep. 11 (Bryan Finster, Dave Farley) [Continuous Delivery, Engineering Culture, Engineering Scalability] [Duration: 01:09] Interesting conversation about how to introduce CD as part of the engineering strategy in large companies and how having CD as part of the vision (not as a goal in itself) can generate a healthy engineering culture that continuously improves.
Reminder: All of these talks are interesting, even just listening to them.

Related:

Sunday, June 02, 2024

Talk slides / Lean Software Development: A more effective Agile

Yesterday, I had the pleasure of giving a talk at https://eventos.paradigmadigital.com/agile-real-life. My talk "Lean Software Development: A more effective Agile" explained how the teams I have been part of work. We use a combination of Lean Software Development, with Lean Product Development, and Extreme Programming.

I leave the presentation slides here in case someone might find it useful:

Link to the original doc

Related content and references:

Wednesday, May 15, 2024

Lean Software Development: Amplificar el Aprendizaje

En este nuevo artículo de la serie sobre Lean Software Development, nos vamos a centrar en la naturaleza del desarrollo de software y la importancia de optimizar nuestro proceso para el aprendizaje continuo.

Naturaleza del Desarrollo del Software

Independientemente del error clásico que solemos cometer en la industria de comparar el desarrollo de software con la construcción de edificios o los procesos de manufactura (ver  Construction engineering is NOT a good metaphor for software), lo cierto es que el desarrollo de un producto software es un proceso de adaptación de la solución a las necesidades cambiantes del usuario (o a nuestras hipotesis sobre las necesidades del usuario). Es decir, es el proceso de evolucionar de forma continua el software para adaptarse a esas necesidades.

Esta evolución es continua no solo porque las necesidades de nuestro cliente van evolucionando (estrategia, reglas de negocio, procesos) sino porque el entorno en el que nos movemos cambia de forma continua y constante (SaaS, competidores, IA, evolución de dispositivos). Esta evolución es parte de la naturaleza intrínseca del software, puesto que su gran ventaja es precisamente esa, la velocidad con la que puede evolucionar y adaptarse. Un software que no está evolucionando es un software muerto (o que nadie usa o que se ha quedado obsoleto).

designed by www.freepik.com

A diferencia de los procesos de producción y manufactura, donde la calidad es la conformidad a requerimientos establecidos, la calidad en software es adecuarnos a las necesidades de nuestros clientes. Estas necesidades cambian de forma continua, por lo que el software debe cambiar a su vez.

Podemos ver, por tanto, que en el centro de la naturaleza del desarrollo del software está el aprendizaje continuo y profundo sobre el problema o necesidad (cambiante) de nuestros clientes y sobre la adecuación de nuestra solución para resolver ese problema y necesidad.

Lean Software Development reconoce esta naturaleza del desarrollo del software y considera necesario amplificar el aprendizaje para optimizar el proceso de desarrollo de producto.

"A mature organization focuses on learning effectively and empowers the people who do the work to make decisions." Mary Poppendieck


Amplificar el Aprendizaje

El aprendizaje es la piedra angular del desarrollo de software efectivo. En el contexto de Lean Software Development, este principio se eleva como una guía fundamental para la mejora continua. Reconocer que el conocimiento es dinámico y que el aprendizaje es un proceso constante es crucial para el progreso en un entorno de desarrollo ágil.

Sin embargo, este aprendizaje no puede limitarse a personas o perfiles concretos; debe extenderse a todo el equipo, puesto que queremos que todo el equipo pueda aportar y ya hemos visto que el aprendizaje es parte de la naturaleza del desarrollo de software.

Amplificar el aprendizaje implica no solo entender lo que el cliente desea, sino también discernir lo que no necesita. Este discernimiento es crítico, ya que construir características o funcionalidades innecesarias es el mayor desperdicio en el desarrollo de software. Por lo tanto, el proceso de aprendizaje debe estar enfocado en la clarificación constante de las necesidades reales del cliente, evitando así el desperdicio y optimizando la entrega de valor.

"The biggest cause of failure in software-intensive systems is not technical failure; it’s building the wrong thing." Mary Poppendieck

Resumiendo, Lean Software Development nos recomienda:

  1. Reconocer el aprendizaje continuo y constante como el cuello de botella fundamental en el desarrollo de productos software.
  2. Aprender de las necesidades y problemas del cliente, identificando también lo que NO necesita.
  3. Optimizar el aprendizaje continuo por parte de TODO el equipo.


Y como herramientas para ampliar ese aprendizaje nos habla de:

  • Ciclos de retroalimentación (feedback loops)
  • Iteraciones
  • Sincronización e integración
  • Diseño Basado en Conjuntos de Soluciones" (Set-Based Development)

Aterrizando la amplificación del Aprendizaje

En los últimos 15 años trabajando con diferentes equipos, siempre he considerado que el aprendizaje es parte fundamental de la naturaleza de desarrollo de software. Mi enfoque ha consistido en fomentar ese aprendizaje continuo y amplificado que promueve el Lean Software Development.

A continuación indico las herramientas que he usado para amplificar el aprendizaje.

Equipos de producto empoderados

Estos equipos, basados en las necesidades y estrategias de negocio, tienen la capacidad de decidir qué problema soluciónar y cómo hacerlo. Son equipos con una verdadera mentalidad de producto, compuestos por Product Engineers que no solo se interesan por el problema o necesidad del cliente, sino que también buscan entenderlo profundamente y proponer las mejores soluciones.

Como bien describe John Cutler, estos son los llamados Product Teams.

https://amplitude.com/blog/journey-to-product-teams-infographic

Estos Product Teams tienen como parte de su responsabilidad entender y aprender sobre los problemas del cliente, usando ese aprendizaje para plantear las mejores soluciones. En estos equipos el aprendizaje es clave, y por ello usan practicas de descubrimiento de producto. En nuestro caso concreto, los miembros del equipo se suelen rotar para hacer entrevistas de usuario, facilitar sesiones de co-creación o para dar soporte. Todas estas sesiones nos proporcionan aprendizajes que se ponen en común con el resto del equipo y que nos permiten ir tomando decisiones sobre los siguientes pasos a dar.

Aunque conozco algunas técnicas más avanzadas que las que he indicado para hacer descubrimiento de producto, nunca las he puesto en práctica y nos ha bastado con que todos los miembros del equipo tengan una mentalidad de producto, se cuestionen siempre por qué hacemos las cosas y si las debemos hacer o no. Supongo que hemos podido tener un gran impacto y conseguir buenos aprendizajes sin usar prácticas sofisticadas de descubrimiento de producto gracias al tipo de productos en los que hemos estado involucrados (productos poco visuales, en algunos casos internos, o dirigidos a perfiles técnicos).

Ciclos de retroalimentación (feedback loops) 

Utilizamos Extreme Programming (XP) como base, que se enfoca en generar ciclos de retroalimentación lo más frecuentes y pequeños posibles para optimizar el proceso de desarrollo:

  • Comunicación constante: En nivel de mob o pareja (segundos).
  • Proceso de TDD (Test-Driven Development): Ciclos cortos de pruebas y desarrollo (minutos).
  • Tests de aceptación: Evaluación rápida de las funcionalidades (minutos).
  • Despliegues frecuentes: Implementación regular de mejoras (horas).
  • Planificación diaria: Revisión y ajuste de objetivos diarios (1 día).


http://www.extremeprogramming.org/introduction.html

Adicionalmente, complementamos estos ciclos de retroalimentación de XP con técnicas de Entrega y Despliegue Continuo (Continuous Deployment, CD), ampliando nuestra capacidad para integrar y validar cambios de manera casi instantánea.

“Extreme Programming is a team style of software development. Collaborative style of software development that emphasizes deferring as many decisions as possible and enabling that by increasing feedback loops at every possible level....
so if you get great feedback then you don't have to make good decisions because you can afford to just make a decision and you'll find out.”   Kent Beck

Por supuesto estos ciclos de retroalimentación no se producen solo en el proceso técnico de desarrollo de software, también se producen a a partir de la retroalimentación proporcionada por los clientes, donde podemos ver si nuestras hipotesis sobre lo que necesita el cliente y la solución propuesta están teniendo el impacto buscado.

Iteraciones

Aunque hemos dejado atrás el enfoque tradicional de hacer iteraciones, seguimos optimizando el flujo de entrega continua. Frecuentemente iteramos por distintas partes del producto, centrándonos siempre en las áreas más prioritarias en cada momento. Para nosotros, ninguna característica o funcionalidad está definitivamente completa; están en constante evolución, y es común volver a iterar sobre elementos ya desarrollados según la necesidad. (Ver https://productdeveloper.net/iterative-incremental-development/)

Sincronizacion e integración

Usamos la práctica de Integración Continua y Entrega Continua mediante el enfoque de Trunk Based Development. Esto permite que todo el equipo mantenga una visión completa e integrada del producto a diario, evitando el mantenimiento de ramas con código aislado por días o semanas. Solo existe una versión activa en la rama principal, lo que minimiza el desperdicio, evita conflictos y garantiza una visión común. 

Esta forma de trabajar permite que todo el equipo comparta la misma visión en todo momento del código (la solución) e impide que una persona o parte del equipo se aislen con una visión (y conocimiento distinto) durante dias trabajando en una rama de funcionalidad.

Diseño Basado en Conjuntos de Soluciones (set-Based Development)

En Lean Software Development, el término Diseño Basado en Conjuntos de soluciones (set-based development) describe una metodología que prioriza mantener abiertas múltiples opciones de diseño durante el proceso de desarrollo. Este enfoque permite acumular la mayor cantidad de información posible, no solo sobre un elemento específico del diseño, sino sobre cómo todos los elementos se integran. Contrario a la tradición de tomar decisiones de diseño tempranas basadas en la información disponible en ese momento, el set-based development favorece el aplazamiento de decisiones de diseño hasta contar con información más completa, lo cual es crucial para el desarrollo de software de alta calidad y flexible.

Este método se fundamenta en la realidad de que, en el desarrollo de software, las interacciones entre diferentes componentes no se pueden predecir con total certeza hasta que no se implementan y prueban. Por tanto, mantener abiertas opciones de diseño y evitar decisiones definitivas hasta obtener más datos resulta en un enfoque más eficaz para manejar proyectos de software complejos y de alta calidad.

En mis equipos, la práctica de mantener abiertas las opciones de diseño y posponer decisiones hasta obtener el máximo de información posible es una obsesión. He llegado a crear un taller específico para practicar esta metodología (Ver Taller Lean Posponer Decisiones). La clave para trabajar con opciones abiertas reside en enfatizar la simplicidad (XP), fomentar un diseño evolutivo y proceder en pasos muy pequeños que nos permitan tomar decisiones en el último momento responsable. Profundizaré más en este tema en un artículo completo dedicado a ello en la serie.

“La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial.” Principio del Manifiesto por el Desarrollo Ágil de Software

Otras Técnicas Útiles para Amplificar el Aprendizaje

En nuestro día a día, aplicamos estrategias como mob programming o pair programming, con rotaciones frecuentes de parejas. Esto facilita la rápida diseminación del conocimiento dentro del equipo y evita la formación de silos de información.

Además, empleamos con regularidad los Spikes de Extreme Programming, que son tareas con timeboxing dedicadas exclusivamente a explorar y aprender sobre aspectos específicos que necesitamos dominar, como una nueva técnica, biblioteca o tecnología.

Otra técnica que siempre me ha funcionado para mejorar y amplificar el aprendizaje es introducir Blameless postmortems tanto aplicados a incidencias en producción, como aplicados como retrospectiva de iniciativas. Ver CAS18 sobreviviendo en producción - gestión de incidencias y aprendizaje

Conclusiones

En resumen, nuestro enfoque consiste en priorizar el aprendizaje como un elemento fundamental, trabajar con ciclos de retroalimentación frecuentes y tomar decisiones basadas en lo que aprendemos continuamente. Este enfoque nos ayuda a adaptarnos rápidamente y a mejorar constantemente nuestra efectividad y eficiencia en el desarrollo de productos.

Referencias y enlaces relacionados

Sunday, April 21, 2024

Eliminar desperdicios en el desarrollo de software

En nuestro primer post, exploramos los orígenes y los principios fundamentales del Lean Software Development. En el segundo, introdujimos ciertos conceptos básicos que usaré durante toda la serie. Ahora, nos enfocaremos en el primero de estos principios: Eliminar el desperdicio. Es clave entender y reducir las actividades que no añaden valor para optimizar nuestros procesos de desarrollo y aumentar el valor que entregamos a nuestros clientes.

En el articulo describiré ejemplos y prácticas que he utilizado en diversos equipos ágiles desde hace años y es importante notar que las prácticas y ejemplos que mencionamos son específicos de nuestro contexto, como el desarrollo de producto y los equipos empoderados, y que suelen reforzarse mutuamente. Por ello, no es recomendable implementarlos de forma aislada. Por ejemplo, iniciar despliegues continuos sin un sistema de pruebas automáticas adecuado podría ser más perjudicial que beneficioso.

Adaptando los Principios del Lean Manufacturing al Desarrollo de Software

En el Lean Manufacturing original, se identificaban siete tipos principales de desperdicio: Inventario, Procesamiento extra, Sobreproducción, Transporte, Esperas, Movimientos y Defectos. Mary y Tom Poppendieck, basándose en su extenso conocimiento del Lean y del desarrollo de software, adaptaron estos conceptos para hacerlos más relevantes en este nuevo contexto. Por ejemplo, redefinieron el concepto de "Inventario" como "Trabajo parcialmente hecho", el “Procesamiento extra” como “Proceso extra”, la "Sobreproducción" como "Features extras", y el "Transporte" como "Cambio de tareas". Consideraron que los demás tipos de desperdicio mantienen su aplicabilidad directa en el desarrollo de software.



Identificando y Eliminando el Desperdicio

Para poder eliminar el desperdicio, el primer paso es capacitar al equipo sobre cómo identificar lo que constituye desperdicio. En este sentido, es importante:

  • Analizar desde la Perspectiva del Cliente: Siempre debemos preguntarnos si una actividad añade valor al cliente/usuario y si podemos eliminarla sin afectar a su percepción.
  • Fomentar una Cultura de Crítica Constructiva: Ser críticos con nuestras acciones y métodos permite al equipo analizar periódicamente su manera de trabajar para identificar y eliminar el desperdicio.
  • Considerar el Impacto a Largo Plazo: Es vital distinguir entre lo que puede parecer un desperdicio en el corto plazo pero no necesariamente lo es en el mediano o largo plazo, siempre con la satisfacción del cliente/usuario en mente.

Es fundamental clasificar los desperdicios identificados en dos categorías: aquellos que son necesarios por razones específicas, como regulaciones o leyes, y aquellos que podemos eliminar completamente o en parte sin comprometer la satisfacción del cliente/usuario. En el caso de los primeros, debemos enfocarnos en entender el motivo detrás de estas limitaciones para poder minimizar el desperdicio lo máximo posible. Para los segundos, es crucial adoptar una actitud más decisiva, buscando eliminarlos de manera sistemática.

Trabajo Parcialmente Hecho

En Lean Manufacturing, el inventario de piezas a medio hacer es físicamente visible y requiere organización y, en ocasiones, mantenimiento. A diferencia de esto, en nuestro contexto el "inventario" (código, conocimiento, información, análisis, etc.) no es tan visible, pero es igualmente costoso.

El valor real para el cliente o usuario surge únicamente cuando este accede a la nueva funcionalidad o cambio. A menudo, incluso en ese instante, el valor sigue siendo incierto hasta que recibimos retroalimentación. Por lo tanto, dado que el valor verdadero solo se potencializa en la etapa final, es crucial acortar el tiempo desde la concepción de la idea hasta su entrega. En otras palabras, debemos esforzarnos por reducir el trabajo en progreso y disminuir el lead time (tiempo de entrega). Como dice Dan North, el objetivo es minimizar el intervalo entre la idea inicial y el “gracias” del usuario.

Estas son las prácticas que usamos para eliminar el trabajo parcialmente hecho:

  • Analizamos/Preparamos trabajo en el backlog bajo demanda: Mantenemos el backlog para no más de un mes y, si crece, eliminamos iniciativas. Si es importante, volverá a surgir.
  • Vertical slicing radical: Tanto a nivel de producto como técnico, permitiéndonos desplegar incrementos en pocas horas o un día. Esto por supuesto requiere hacer CD / Entrega Continua.
  • Trunk Based Development: Evitamos trabajo parcial en feature branches y los problemas de merge.
  • Gestión extremo a extremo por nuestro equipo: Realizamos despliegues, validamos la calidad, monitorizamos el producto, etc. Evitando el tiempo de espera por otros equipos o especialistas.
  • Despliegue inmediato de mejoras: Tanto mejoras de usuario, que ofrecen feedback de negocio, como técnicas, que aportan feedback del sistema.

Como se muestra en el Diagrama de Flujo Cumulativo del equipo, mantenemos un backlog mínimo y gestionamos las tareas relacionadas solo cuando es necesario y en la menor cantidad posible.




Proceso Extra: Simplificación hacia el Valor

Alineándonos con el Manifiesto Ágil, Lean Software Development promueve que el avance principal se mida por el software de valor entregado al cliente. En este marco, cualquier elemento —como documentación excesiva, procesos redundantes, reuniones innecesarias o aprobaciones— que no contribuya directamente al valor para el cliente/usuario, debería ser evaluado para su eliminación.

Desde que adopté los principios ágiles, he colaborado con equipos para depurar nuestros procesos, descartando lo que no generaba valor. 

De esa experiencia destaco dos cambios significativos:

  • Transición de Scrum a Kanban: Scrum nos ayudó inicialmente, pero evolucionamos hacia Kanban para enfocarnos en un flujo de trabajo continuo. Esto redujo las reuniones y planificaciones extensas, favoreciendo sesiones más breves y enfocadas, adaptándonos al modelo Just In Time caracteristico de Lean.
  • Eliminación de Estimaciones: Priorizamos cambios pequeños y continuos, lo que nos permite prescindir de las estimaciones tradicionales. Aún hacemos estimaciones de alto nivel para grandes iniciativas, pero con un enfoque en minimizar el riesgo y la inversión de tiempo innecesaria.

Hemos descubierto que al trabajar en pasos pequeños y preparar solo lo inmediatamente necesario, minimizamos el re-trabajo (failure demand), puesto que no hacemos trabajo “especulativo”. Esto simplifica enormemente la priorización y gestión del backlog, permitiéndonos concentrarnos en lo esencial y ahorrar esfuerzos considerables.

En resumen: Adoptar un enfoque de hacer solo lo necesario y justo a tiempo (Just-In-Time) nos ha llevado a un proceso más eficiente, con menos retrabajo y una gestión de prioridades y backlog más ágil.


Aunque es imposible eliminar toda la documentación o burocracia asociadas a regulaciones y certificaciones de seguridad, es posible abordar estos requisitos de manera creativa para evitar trabajo adicional. En nuestro caso, adoptamos el desarrollo basado en Trunk (Trunk Based Development). Cada commit o push incluye a los coautores y desencadena una serie de pruebas exhaustivas. Esta metodología no solo satisface a los auditores sino que, de hecho, resulta ser más efectiva que los métodos tradicionales de revisión asincrónica (feature-branching + PRs) y la necesidad de aprobaciones explícitas para avanzar hacia la producción.


Funcionalidades y Código Extra

Este para mi junto con el trabajo parcialmente hecho son el desperdicio más significativo que tenemos en desarrollo de software y productos. Demasiado a menudo, software desarrollado durante meses termina sin usarse o es evitado por los usuarios por no cumplir sus expectativas. Este es el DESPERDICIO en el desarrollo de software. Como dijo Mary Poppendieck, "The biggest cause of failure in software-intensive systems is not technical failure; it's building the wrong thing."

Además de aplicar Lean Software Development, debemos utilizar otras técnicas para realmente entender las necesidades de nuestros usuarios y descubrir qué problemas merecen ser solucionados. Herramientas como Lean Product Management, Continuous Discovery e Impact Mapping son fundamentales en este proceso, aunque no las detallaremos en esta serie de artículos.

Suponiendo que hemos identificado un problema digno de ser solucionado y que tenemos clientes/usuarios con una necesidad clara, nuestro objetivo es resolver este problema/necesidad con la menor cantidad de software posible y lo más rápidamente que podamos. En nuestro caso, usamos las siguientes practicas:

  • Adoptamos el principio ágil de "La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial."
  • Vemos el software como un medio y no como un fin, buscando resolver las necesidades con la menor cantidad de software y tecnología posible.
  • Nos enfocamos en el valor para el cliente, asegurándonos de que cada iniciativa y funcionalidad se alinee con las necesidades reales de los usuarios.
  • Postergamos las decisiones técnicas y de producto tanto como sea posible, para aumentar las posibilidades de nunca tener que implementarlas o por lo menos no implementarlas en su totalidad. Siempre buscamos la versión mínima que nos es suficiente.
  • Empleamos Outside-In TDD, lo que asegura que solo hacemos el código mínimo necesario para implementar el caso de uso.
  • Seguimos el principio de YAGNI  (You Aren't Gonna Need It), centrados en la funcionalidad que es requerida ahora, sin caer en diseño o desarrollo especulativo.
  • Y cuando algo que hemos desarrollado deja de usarse o no cumple con su objetivo, lo eliminamos por completo o lo adaptamos hasta que vuelva a tener un impacto positivo.
  • Trabajamos en pasos muy pequeños (<1.5-2 días), presentando nuevos incrementos a los usuarios para obtener retroalimentación rápida que nos permite adaptarnos y decidir los siguientes pasos. Esto, a menudo, nos permite detener la inversión en una funcionalidad de la aplicación cuando es "lo suficientemente buena" para el usuario, evitando así desarrollos innecesarios.


Cambios de tarea

Cambiar de tarea frecuentemente puede interrumpir significativamente la productividad de un equipo. Cada cambio obliga a reiniciar el proceso mental, retrasando el reingreso al estado de "flujo" de trabajo. Para minimizar estos cambios, aplicamos varias estrategias:

  • Minimizar el WIP: La estrategia más efectiva para prevenir cambios de tarea frecuentes es reducir el Trabajo en Curso (WIP) a nivel de equipo. Nos esforzamos por concentrarnos en una, o máximo dos, iniciativas simultáneamente. El ensemble/mob programming es nuestra técnica predilecta para limitar el WIP, ya que cuando todo el equipo se enfoca en una única tarea, las interrupciones internas se eliminan naturalmente.
  • Revisiones de código continuas y sincronas:  Trabajando en ensemble/mob programming se eliminan todos los cambios de tarea que se generan cuando las revisiones de código son asíncronas. Ver Code reviews (Synchronous and Asynchronous) 
  • Vertical Slicing y Technical Slicing: Aplicando rigurosamente estas técnicas, podemos trabajar en incrementos realmente pequeños. Esto nos ayuda a preservar el flujo de trabajo hasta completar y desplegar un incremento. Naturalmente, después de cada despliegue, surge la posibilidad de cambiar de tarea sin el impacto negativo que implicaría hacerlo en medio de un incremento
  • Completitud de Tareas y Spikes: Nos aseguramos de que las tareas se pueden completar de principio a fin. Si vemos que no es posible hacemos un spike (http://www.extremeprogramming.org/rules/spike.html) para eliminar la incertidumbre o buscamos otras aproximaciones que no requieran interrumpirlas.
  • Técnica Pomodoro: Usamos Pomodoros para periodos de trabajo concentrado y descansos sincronizados del equipo.
  • Calidad a Todos los Niveles: La alta calidad previene interrupciones por fallos. Aplicamos TDD, ensemble/mob programming y otras prácticas de Extreme Programming para mantenerla.
  • Rotaciones en Operaciones/Soporte: Para equipos con funciones de soporte, implementamos rotaciones, concentrando a parte del equipo en trabajo emergente y al resto en iniciativas planificadas.

Esperas

Cuando analizamos en profundidad el proceso de desarrollo de producto, lo más usual es encontrar que cada incremento/idea/backlog item pasa casi todo el tiempo esperando. Esperando para tener respuestas a preguntas, esperando analizar más profundamente el problema, esperando tener feedback sobre el diseño, esperando la aprobación de los cambios de arquitectura, esperando que ciertos especialistas estén disponibles, esperando que alguien apruebe el cambio, esperando que se hagan revisiones de código, esperando que se active el feature toggle, esperando comunicar el cambio... Esperando, esperando, esperando. Evidentemente, si vemos el proceso desde el punto de vista del cliente/usuario, cualquier tipo de espera es simplemente desperdicio.

Para eliminar gran parte de estas esperas, estas son algunas de las tácticas que nos han funcionado en el pasado:

  • Asignar al equipo la responsabilidad de principio a fin para ir desde la definición del problema hasta la puesta en producción y operación de la solución. Y, si es posible, incluso darle la libertad de encontrar el problema que merezca la pena resolver. Esto implica encargarse de la gestión del producto, el desarrollo, la calidad, el despliegue y las operaciones.
  • Incluso aunque el equipo esté empoderado, a veces no dispone de todos los skills necesarios. En esos casos, tenemos que conseguir la colaboración de algún especialista, pero intentar siempre que el especialista nos ayude a mejorar nuestros skills en esa especialidad en vez de resolver el problema por nosotros. Esto no cubrirá todos los casos, pero hará que en los casos más básicos no necesitemos volver a requerir al especialista.
  • Por otro lado, cuanto más multidisciplinar sean los miembros del equipo, más fácil será cubrir las necesidades dentro del propio equipo. Esto no implica que todo el mundo sepa de todo, pero sí que fomentemos los perfiles en T (https://es.wikipedia.org/wiki/Habilidades_en_forma_de_T ).
  • A nivel técnico, la forma de eliminar sistemáticamente la mayor parte de las esperas es avanzar hacia la Entrega Continua / CD, lo que normalmente implica poner bastante peso en las prácticas técnicas ágiles (TDD, CI, Despliegue separado de Activación, etc.) y tener una confianza muy alta en nuestro testing automático.
  • Una de las formas más eficientes (eficiencia de flujo) es trabajar en mob/ensemble programming de forma que todo el conocimiento y los skills disponibles estén a la entera disposición de la única iniciativa en curso (en la que trabaja el mob/ensemble).
  • De nada sirve salir pronto a producción si luego permanecemos de forma pasiva esperando la retroalimentación del cliente/usuario. Es mucho más eficiente buscar esa retroalimentación de forma proactiva y disponer de instrumentación a nivel de producto y sistema para aprender lo antes posible.

Movimiento

Otro de los siete desperdicios básicos que considera Lean Manufacturing es el movimiento. En este contexto, resulta evidente que los movimientos que un operario debe realizar en una fábrica, ya sea entre máquinas, para recoger material o para hacer consultas, constituyen un claro desperdicio. En el caso de Lean Software Development, se decidió mantener también la categoría de movimiento, aunque en nuestro ámbito, este tipo de desperdicio no sea tan directo y evidente. 

En el libro original, el movimiento se refiere al esfuerzo necesario para acceder al cliente, obtener información del dominio, realizar hands-offs entre especialidades (ops, QA, seguridad), etc.

Muchas de las tácticas empleadas para eliminar las esperas también son válidas para reducir el desperdicio de movimiento, especialmente en lo que respecta a los handoff entre especialidades.

Adicionalmente, para eliminar otros tipos de movimientos, nos han resultado útiles las siguientes estrategias:

  • Proporcionar al equipo acceso directo al cliente/usuario final o a su representante más cercano. Una solución práctica puede ser asumir la responsabilidad de las operaciones, de manera que el equipo esté directamente expuesto a las quejas y necesidades de los clientes/usuarios.
  • Desarrollar herramientas específicas que permitan acceder de forma directa y eficiente a la información necesaria, evitando repetir procesos (por ejemplo, herramientas para extracción de datos, observabilidad, etc.).
  • Crear irradiadores de información para que sea fácil visualizar los avances o información relevante sin necesidad de buscar activamente (pizarras de gestión visual, notificaciones automáticas, etc.).

Defectos

Por último, Lean Software Development considera los defectos como una gran fuente de desperdicio. Desde mi experiencia, diría que los defectos son el segundo desperdicio más importante después de realizar actividades que no son necesarias (funcionalidades/código extra). Aunque, bien mirado, podríamos considerar que no hacer lo que necesita el cliente es también un tipo específico de defecto :).

Cada defecto que cometemos no solo genera el desperdicio del tiempo invertido en crear ese código incorrecto, sino también el tiempo dedicado a solucionarlo, el impacto en nuestra credibilidad ante el cliente/usuario y todo el esfuerzo desde la creación del problema hasta su resolución. Por lo tanto, no es solo importante evitar generar defectos, sino también encontrarlos cuanto antes, ya que el desperdicio/coste asociado aumenta de manera exponencial cuanto más tiempo tardamos en detectar el problema.

Con esto en mente, las tácticas y prácticas que solemos usar para minimizar este desperdicio son:

  • Minimizar en todo lo posible el código que necesitamos desarrollar para conseguir el impacto deseado. Como bien sabéis, menos código implica menos posibilidades de cometer errores.
  • Utilizar Outside-In TDD, comenzando por tests de aceptación del caso de uso. Esto, por definición, genera la mínima cantidad de código posible que además está bien testeado desde su creación.
  • Este proceso no cubre todos los escenarios y problemáticas, por lo que también es necesario crear ciertos tests de extremo a extremo y tener estrategias para temas específicos como análisis de seguridad, test de carga, test de rendimiento, etc.
  • Otro punto importante es probar los componentes de terceros que usamos para evitar problemas cuando actualizamos versiones o los utilizamos de manera diferente a la habitual. Ver Thin Infrastructure Wrappers.
  • Con todos los puntos anteriores tenemos un buen punto de partida, pero cada vez es más común depender de infraestructura y servicios de terceros (SaaS, clouds, etc.). En esos casos, se hace más imprescindible que nunca utilizar tácticas de testing en producción. Al fin y al cabo, a nuestros clientes/usuarios les da igual cuál haya sido la fuente del problema; solo les importa el impacto que ha tenido.


Conclusiones

Como se puede observar en las tácticas y prácticas que empleamos para minimizar el desperdicio, muchas de ellas se relacionan con tener prácticas de desarrollo sólidas (pair programming, TDD, BDD, revisiones continuas, CD, CI, etc.) que nos permiten desarrollar de manera sostenible. Otras se centran en evitar en la mayor medida posible realizar tareas innecesarias, enfocándonos en lo que realmente valora el cliente (que no siempre coincide con lo que pide), limitando el software a las necesidades actuales y trabajando en pasos muy pequeños para poder cambiar de dirección o cesar la inversión en algo tan pronto como sea necesario.

Trabajar en estos pasos tan pequeños y adaptarnos de forma continua nos permite aligerar mucho el proceso necesario: necesitamos poca gestión del backlog si tenemos muy poco en él; no hay que coordinar distintos flujos de trabajo si todos trabajamos en lo mismo al mismo tiempo; no hay que estructurar la comunicación ni los handoffs con otros equipos si los gestionamos nosotros mismos. Al final, se trata de simplificar todo lo más posible para hacer solo lo absolutamente necesario, siempre centrados en lo que realmente aporta valor. Esto implica, evidentemente, cuestionarnos constantemente lo que hacemos y cómo lo hacemos. Que algo haya sido útil hace un par de meses no significa que siga siéndolo. No es tan sencillo como parece, ya que requiere una profunda implicación en nuestro trabajo (pasión) y, al mismo tiempo, la capacidad de dejar ir lo que no aporta (desapego). Es vivir centrados en una ventana deslizante de lo que aporta valor ahora, de lo que nos es útil en el presente.

Recuerda que eliminar el desperdicio es solo el primer paso en el camino hacia el Lean Software Development. En nuestro próximo post, exploraremos cómo "Amplificar el aprendizaje" para garantizar la excelencia de nuestros productos. ¡Nos vemos pronto!



Saturday, April 20, 2024

CommitConf 2024 Taller Lean: Posponer decisiones (Defer commitment)

Esta mañana he tenido la suerte de poder facilitar un taller creado por @islomar y yo mismo para practicar el principio Lean de Posponer decisiones.

Me lo he pasado muy bien y se han generado muy buenas conversaciones.





Varias personas de las que han hecho el taller me han pedido las slides, y aunque no aportan mucho sin el taller, pueden venir bien como recordatorio a los que hayan estado, así que las dejo por aquí:


 



El taller es Creative Commons (CC BY-SA 4.0) así que para la gente que me ha preguntado, encantado de que lo puedan facilitar en sus empresas. Si alguien necesita el material original y algún consejo para la facilitación que me contacte y estaré encantado de ayudar.

Soporte


Si te gusta que deje este tipo de talleres en Creative Commons o que genere contenido en mi blog compartiendo mis neuras agradeceria algo de soporte, que siempre hace ilusión ver que a la gente le aporta, y ayuda a pagar el hosting y herramientas que uso. 


Relacionado:


Sunday, April 14, 2024

Conceptos Lean interesantes para desarrollo de software

 En esta entrega de nuestra serie sobre Lean Software Development, nos enfocaremos en explorar una serie de conceptos fundamentales que no solo enriquecerán nuestro diálogo a lo largo de los próximos artículos sino que también aspiran a despertar la curiosidad del lector para profundizar en ellos de manera independiente. El objetivo es doble: dotarnos de un lenguaje común para discutir principios y prácticas Lean en el desarrollo de software y, al mismo tiempo, incentivar una exploración autodidacta que enriquezca nuestra comprensión y aplicación de estos conceptos en el entorno laboral.

Valor

  • Valor en Lean: Se define desde la perspectiva del cliente. Cualquier acción que satisfaga una necesidad del cliente, solucione un problema o nos permita aprender sobre dicho problema o sobre el comportamiento de la solución, se considera de valor. Es crucial identificar y concentrarse en las actividades que generan valor para aumentar la eficiencia. Si algo no está desplegado y activado, su valor es cero. 
  • Cadena de Valor: Representa la secuencia completa de actividades necesarias para entregar un producto o servicio al cliente. En nuestro caso, la cadena de valor abarca desde entender el problema hasta que la solución (software) está en manos del cliente. Si varios equipos intervienen en esta cadena, es vital identificarlos y optimizar la cadena de valor completa. No basta con ser rápidos en el desarrollo si no podemos implementar adecuadamente la solución, o si ésta no es la correcta. Siempre debemos enfocarnos en optimizar toda la cadena de valor.
  • Flujo / Flow: Se refiere a la manera en que el trabajo avanza de forma continua a través de la cadena de valor. Un flujo óptimo se caracteriza por el movimiento constante del trabajo, sin interrupciones, bloqueos, ni cuellos de botella. El objetivo es mantener un flujo continuo y sostenible en el tiempo, poniendo especial atención en mejorar este flujo a lo largo de toda la cadena de valor.

Eficiencia

  • Eficiencia de Flujo: Esta métrica mide la proporción del tiempo que un ítem de trabajo es activamente procesado en comparación con el tiempo total desde que se inicia hasta que se entrega. Un flujo eficiente busca minimizar el tiempo inactivo. En otras palabras, evalúa la relación entre el tiempo activo de trabajo en un cambio y el tiempo que dicho cambio permanece bloqueado o en espera en una cola. El objetivo es reducir al máximo estos periodos de inactividad para agilizar la entrega.
  • Eficiencia de Recursos: A diferencia de la eficiencia de flujo, la eficiencia de recursos se centra en maximizar la utilización de los recursos disponibles, como personas y máquinas. Este enfoque tiende a mantener a los empleados lo más ocupados posible, lo cual frecuentemente conduce a la especialización de tareas y a la formación de colas de espera antes de cada especialidad. Esto garantiza que cada área (front-end, QA, back-end, operaciones, producto) siempre tenga trabajo. Sin embargo, puede resultar en que cada cambio tome más tiempo en estar disponible para el cliente, contraviniendo los objetivos de Lean Software Development.
  • Eficiencia en Lean: Aunque Lean reconoce ambos tipos de eficiencia, da prioridad a la eficiencia de flujo porque maximiza la velocidad de entrega al cliente. Esto no significa que se ignore la optimización de la eficiencia de recursos, pero la prioridad inicial es el cliente a través de la eficiencia de flujo. Adicionalmente, dado que Lean pone un gran énfasis en la eliminación de desperdicios, la eficiencia global alcanzada suele ser muy alta. Traduciendo a desarrollo de software, primero optimizamos el flujo para poder sacar los incrementos en el menor tiempo posible (eficiencia de flujo) y una vez que tenemos ese proceso funcionando de forma sostenible, optimizamos recursos y tiempo de personas (eficiencia de recursos). En siguientes articulos veremos como optimizar ese flujo continuo de entrega de valor mediante la Entrega Continua / CD y los equipos multi disciplinares. Este fantástico video explica perfectamente los tipos de eficiencia en Lean.


Métricas Lean

  • Throughput: El throughput (o tasa/ritmo/frecuencia de entrega) en una cadena de valor mide cuánto valor se genera para el cliente por unidad de tiempo. En un contexto de manufactura, esto podría referirse al número de piezas o elementos producidos por un proceso en una unidad de tiempo específica (día, hora, etc.). En el desarrollo de software, se refiere a cada incremento que desplegamos y que el cliente puede empezar a usar. Maximizar el throughput es crucial para incrementar la eficiencia en la entrega de valor.
  • Lead Time: Este término se refiere al tiempo total que transcurre desde que se identifica la necesidad de un producto o servicio hasta que éste es entregado al cliente. Reducir el lead time es fundamental para la satisfacción del cliente. En el caso de Lean Software Development, corresponde al tiempo desde que detectamos una necesidad hasta que la solución está disponible para el cliente.
  • Tiempo de Ciclo / Cycle Time: Mide el tiempo que tarda en completarse un ciclo de trabajo específico dentro del proceso de producción. Ofrece una perspectiva del rendimiento operativo interno. Para el desarrollo de software, el tiempo de ciclo se mide desde que comenzamos a trabajar en un incremento hasta que está desplegado y activo para el cliente. El objetivo es minimizar el tiempo de ciclo para obtener retroalimentación de manera más frecuente, lo cual es crucial para la mejora continua. Para más información sobre la importancia de trabajar en pequeños lotes, puedes consultar https://www.eferro.net/2021/01/small-batches-for-win-continuous.html.


  • Trabajo en Progreso (WIP): Este término se refiere a todos los ítems de trabajo que se han iniciado pero aún no se han completado. En el contexto del desarrollo de productos y software, el WIP no solo incluye el código en una rama en la que se está trabajando, sino todo el trabajo y contexto de cualquier incremento que no está desplegado y activado para el cliente. Esto abarca elementos en espera de revisión de código, validación de seguridad, o tareas que están analizadas pero aún no han comenzado. Esencialmente, cualquier trabajo del que el cliente aún no se ha beneficiado pero que hemos comenzado de alguna manera. Cuando se usa como métrica, sería el número de tareas que se encuentran en este estado.
  • Límite de Trabajo en Progreso (WIP Limit): Se refiere a la restricción establecida sobre la cantidad máxima de tareas en curso permitidas en un sistema. Este límite es crucial para mantener el enfoque, reducir el tiempo de entrega y mejorar la calidad, ya que previene la sobrecarga de trabajo y promueve la finalización de tareas antes de comenzar nuevas. Establecer estos límites ayuda al equipo a mejorar su forma de trabajar, enfocándose en entregar valor al cliente en lugar de abrir nuevas tareas cuando se encuentran bloqueos. Mantener un bajo nivel de trabajo en curso minimiza la necesidad de cambiar de tarea, reduciendo así el desperdicio asociado con el cambio de contexto frecuente.


Organización del trabajo / Flujo

  • Just-in-Time (JIT): Este principio se centra en producir y entregar exactamente lo que se necesita, en el momento que se necesita y en la cantidad necesaria. En el desarrollo de software, esto implica realizar muchas actividades solo cuando son necesarias y en pequeños lotes. A nivel de desarrollo, el JIT implica trabajar en pasos muy pequeños y siempre en respuesta a la necesidad actual. Por ejemplo, implementamos una funcionalidad solo cuando hay una demanda real, o proponemos una mejora de arquitectura cuando los requisitos del negocio o del cliente lo requieren. Trabajar de esta manera es muy eficiente, pero requiere flexibilidad en el proceso y buenas prácticas técnicas que permitan agilidad en el trabajo.
  • Procesamiento Pull: Este enfoque asegura que la producción se base en la demanda real, en contraposición al procesamiento Push, que produce según lo planificado. En desarrollo de software, trabajar con un enfoque Pull significa que iniciamos las tareas solo cuando existe una demanda específica del cliente o cuando se basan en hipótesis en negocios no validados. Esto mejora la eficiencia y reduce el exceso de producción. Contrastando con el método Push, que define un plan de trabajo y empuja las tareas independientemente de la demanda real.


Desperdicio / waste

  • Muda: Este término japonés significa "desperdicio". En Lean, se identifican siete tipos de muda que deben ser eliminados para optimizar los procesos: sobreproducción, tiempo de espera, transporte, sobreprocesamiento, inventario, movimientos y defectos. En el próximo artículo de esta serie, describiremos los principales tipos de desperdicio en el desarrollo de producto de software y exploraremos prácticas que nos ayudan a eliminarlos o minimizarlos.
  • Muri: Se refiere al concepto japonés de sobrecarga o esfuerzo innecesario. En el contexto Lean, muri implica una presión excesiva sobre los empleados y los procesos, lo que puede desembocar en ineficiencia y desgaste del personal. La meta de eliminar muri es asegurar que el trabajo y los recursos se optimicen sin sobrecargar el sistema, promoviendo un ambiente laboral eficiente y sostenible. En nuestros equipos, muri puede generarse por un exceso de carga cognitiva o por la presión para completar tareas en un proceso Push. En un proceso Pull, es menos probable que ocurra muri, ya que el WIP está limiteado y solo comenzamos una tarea cuando existe la capacidad disponible al haber concluido otra.
  • Mura: Significa inconsistencia o irregularidad. En Lean, mura se asocia con la variabilidad en los procesos de producción que conduce a ineficiencias y desperdicios. La estrategia para abordar mura incluye la estandarización de procesos y la nivelación de la carga de trabajo, lo que resulta en un flujo de trabajo más constante y predecible, mejorando así la eficiencia y la calidad del servicio o producto. Sin embargo, en desarrollo de software donde la alta variabilidad es inherente (demanda irregular, incertidumbre, alta complejidad, desconocimiento, necesidades emergentes), es más prioritario abrazar el cambio y ser adaptable (usando prácticas de desarrollo ágil), en lugar de intentar evitarlo.


Imagen usada con permiso del autor Jose Manuel Beas

Cambio y mejora

  • Kaizen: Esta filosofía japonesa, cuyo significado es "cambio para mejorar", es fundamental en el pensamiento Lean. Kaizen promueve la mejora continua a través de pequeños cambios graduales que, acumulativamente, resultan en grandes mejoras en eficiencia y satisfacción del cliente. Implica a todos los niveles de la organización y se centra en mejorar los procesos diarios, haciendo que cada empleado participe activamente en la sugerencia de mejoras. Una forma de implementar este proceso Kaizen es mediante retrospectivas y generando el espacio para implantar las mejoras identificadas por el equipo.
  • Kaikaku: En contraste con Kaizen, Kaikaku significa "reforma radical". Este enfoque busca implementar cambios grandes y disruptivos que mejoren significativamente el rendimiento y la eficiencia. Generalmente es iniciado desde la dirección de la empresa o de la unidad y puede llevar a innovaciones revolucionarias. Aunque Kaikaku puede resultar en mejoras substanciales, también conlleva mayores riesgos debido a la magnitud de los cambios que propone. Importante mencionar que el Kaikaku NO se refiere a los cambios técnicos u organizativos que son obligados por situaciones de alto riesgo para la supervivencia de la empresa (bancarrota técnica, caos organizativo, incidentes en producción, etc).
  • A3 Thinking: Este es un enfoque sistemático y estructurado para la resolución de problemas, utilizado dentro de la metodología Lean. A3 Thinking se ayuda de un documento del tamaño de una hoja de papel A3 para condensar el problema, el análisis, las soluciones propuestas y los planes de acción en una vista integral. Este proceso no solo fomenta el pensamiento crítico y la colaboración, sino que también mejora la comunicación entre los miembros del equipo, permitiendo abordar desafíos complejos de manera más efectiva y eficiente. En mi experiencia, el A3 Thinking es una muy buena herramienta para cambios significativos en pasos muy pequeños, sobre todo cuando las mejoras requieren un seguimiento muy detallado y continuo.


Recursos altamente recomendados:

Algunos de los conceptos descritos en este artículo, aunque fundamentales, pueden ser inicialmente contraintuitivos. La experiencia muestra que se suelen entender mejor mediante demostraciones visuales. Por esta razón, os recomiendo encarecidamente ver los siguientes videos, la mayoría de los cuales son bastante cortos, para profundizar y realmente comprender estos principios de manera práctica:

Eficiencia de recursos vs Eficiencia de flujo

WIP Limits:

General processes / Team Work:


Con estas recomendaciones terminamos este pequeño artículo sobre conceptos que nos pueden ser útiles para entender el resto de artículos de la serie sobre Lean Software Development.

En nuestra próxima entrega, nos enfocaremos en Eliminar Desperdicios, uno de los principios claves de Lean Software Development.

¡Nos vemos en la próxima entrega!


Recursos relacionados: