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