El desarrollo de software son conversaciones (III)

Antes que nada disculparme por la pausa estival. Tuve el propósito de seguir escribiendo durante las vacaciones, pero al final no sucedió. Quizás necesites refrescar los anteriores dos artículos:

En este tercer capítulo de la serie me concentraré en el proceso de refinamiento, es decir, en pasar de una idea aún demasiado ambigua hasta una especificación suficientemente detallada como para comenzar la traducción de la misma a un lenguaje formal y ejecutable.


Refinamiento

En general, fuera del desarrollo de software, solemos hablar del refinamiento como el proceso de eliminar impurezas o elementos no deseados. Me parece una metáfora muy acertada cuando la aplicamos a esas conversaciones cuyo objetivo es traducir ideas ambiguas o incompletas en otras lo suficientemente concretas como para empezar a construir el software correspondiente.

Cuando lo explico en el trabajo, me gusta ilustrarlo con la imagen que encabeza este artículo: una especie de embudo en el que entran elementos de diferentes colores y tamaños. Cada color representa que están relacionados con una idea original diferente, mientras que el tamaño viene a representar cómo de abordable es aún esa idea para el equipo. Buscamos refinarlas hasta dejarlas listas para que el proceso de construir el software correspondiente sea fluido y no nos obligue a detenernos para revisar o rehacer el trabajo. Intentar construir software para una idea demasiado “grande” nos lleva, sistemáticamente, a cometer errores, a interpretar incorrectamente, a asumir lo que alguien quería decir, a detenernos para resolver alguna de esas dudas, o a esperar que alguien nos proporcione algo que deberíamos haber acordado tener antes de empezar…

Definition of Ready

El refinamiento, pues, no se produce en un único momento sino que se trata de un proceso. De hecho, es un proceso que comenzó hace ya varias conversaciones, como hemos visto en los artículos anteriores. Para facilitar estas conversaciones es muy importante que, antes de comenzar, acordemos qué significa que una idea cualquiera está lista para comenzar su construcción. A esto le llamamos la Definición de Listo o de Preparado (Definition of Ready, si lo lees en inglés). Se trata de una lista de comprobaciones, en la que deben aparecer, como mínimo, aquellos criterios que nos permitan asegurarnos de que:

  1. entendemos qué necesidad tiene el usuario,
  2. hemos decidido con qué incremento de software queremos cubrir esa necesidad y cómo lo vamos a construir,
  3. hemos acordado cómo comprobar que ese incremento de software está acabado y listo para empezar a tener feedback. A esto, por cierto, lo llamamos Criterio de Aceptación.

(No olvides éso de “incremento de software”. Volveremos a ello más adelante)

Cada equipo puede tener una definición diferente, pues depende mucho de a qué se dedican, cómo están organizados, qué restricciones tienen, etc. Sin embargo, hay una técnica muy sencilla, a la vez que poderosa, que nos puede ayudar a orientar estas conversaciones: la historia de usuario.

Historias de usuario

No voy a entrar en los detalles técnicos de una historia de usuario, ya lo hice hace tiempo en otro artículo, pero sí en lo que tiene que ver con las conversaciones que ayuda a facilitar, que es de lo que va esta serie. Por ejemplo, toda vez que decidimos usar historias de usuario, en realidad estamos tomando una decisión ideológica importantísima: nuestro desarrollo se va a centrar en cubrir necesidades de los usuarios. Es la dichosa “customer centricity” de la que hablan muchos y que pocos identifican como una pieza angular del agilismo. La típica plantilla “Como <usuario> Quiero <funcionalidad> Para <necesidad>” nos está enfrentando al reto de empatizar con el usuario y tratar de buscar soluciones prácticas para sus necesidades. Si no lo hemos hecho hasta entonces, éste será el último momento responsable para nosotros.

Es frecuente que los equipos de desarrollo se encuentren en una reunión de refinamiento tratando de escribir una historia de usuario sin tener ni idea de cuál es el usuario, ni su necesidad. En ese caso, su queja suele ser: “Es que nos llegan las historias muy poco trabajadas. Necesitamos más detalles”. Bien, en realidad, ya te imaginas que no es ése el problema, sino la falta de participación de todo el equipo en las conversaciones anteriores, si es que éstas han sucedido siquiera. No poder escribir buenas historias de usuario no suele ser el problema sino el síntoma.

Criterio de aceptación

Una historia de usuario no está completa si no hablamos del criterio de aceptación (también lo encontrarás como Definition of Done). Son todas aquellas comprobaciones que haremos para asegurarnos de que la historia está acabada. Ojo, no se trata de un plan de pruebas exhaustivo, sino más bien de lo que haría un usuario cualquiera para ejecutar la funcionalidad y cubrir esa necesidad de la que hablamos en la plantilla de la historia.

Por ejemplo:

Como Paco (comprador compulsivo, ya registrado en la tienda)
Quiero ver de un vistazo los precios de los productos, incluyendo el coste de transporte
Para ayudarme en la decisión de compra

Esta historia queda incompleta si no decimos que el Criterio de aceptación es:

Cuando un usuario ya registrado pide un listado de productos, podrá ver el precio de cada uno, incluyendo el coste de transporte como una linea más de información en el detalle del listado, tal y como se muestra en el mockup adjunto. Si no hay coste de transporte, esto se indicará con “GRATIS” en vez de 0. No olvidar que el literal GRATIS deberá ser multiidioma.

De esta manera podremos comprobar más adelante si la historia ha sido construida tal y como todos esperamos o no. Es una especie de contrato entre el equipo de desarrollo y el dueño de producto, y por extensión con los clientes y demás stakeholders. Ya veremos en un artículo posterior cómo podremos usar este contrato para beneficio de todos, pero también cómo puede ser una herramienta de doble filo y dañar la confianza dentro del propio equipo.

En cualquier caso, el criterio de aceptación tiene un valor mucho más importante, pues también permite a los diferentes roles entender cuál debería ser su contribución al desarrollo de la historia de usuario y planificar consecuentemente. Fíjate que en el ejemplo hablo de un mockup, que no es más que una técnica más para facilitar la conversación y los acuerdos entre quienes diseñan la UX y el resto del equipo.

No sólo éso, el criterio de aceptación ayuda a identificar riesgos y a tomar las correspondientes decisiones para mitigarlos. Imagina que la arquitectura de la tienda en cuestión no permite incluir fácilmente el coste de transporte de cada producto y que incluirlo en cada uno de los elementos del listado podría provocar un retraso grande en el tiempo de respuesta a los usuarios. Esta conversación, que debe producirse durante el refinamiento, y no necesariamente sólo entre desarrolladores, puede llevar a la decisión de que o bien hay que hacer un gran cambio en el diseño interno de nuestro sistema o bien, incluso, esta funcionalidad no debe ser desarrollada.

También podríamos llegar a la conclusión de que debemos hacer algún tipo de investigación para averiguar si se puede desarrollar o no. Lo cuál podría significar que tenemos que posponer el refinamiento de esa historia hasta obtener la información necesaria. Cuidado con esto porque es fuente de frecuentes retrasos. Postergar el recabado de estos detalles no es buena idea. Mi consejo es que, tal y como salís del refinamiento, vayáis a buscar la información y que, en cuanto la tengáis, montéis un “refinamiento ad hoc” para así dejar esa historia lista cuanto antes. Si haces Kanban, tener un límite en tu WIP también en la columna de refinamiento os ayudará mucho para evitar que las historias se queden ahí durante mucho tiempo. Ten en cuenta que las conversaciones, si pasa mucho tiempo entre ellas, es más difícil de recordarlas, e incluso podemos llegar a olvidarlas para siempre.

Otra decisión posible sería hacer un spike, prueba de concepto, prototipo o cualquier otro pequeño desarrollo que permita reducir la incertidumbre técnica y hacer así un refinamiento más adelante teniendo ya en cuenta las conclusiones obtenidas. A veces, también hacemos lo mismo no sólo para aclarar dudas técnicas sino también de UX. De hecho, hay entornos donde se emplean diferentes técnicas de user research para usar los resultados como input para el refinamiento. También aquí debo hacerte una advertencia: no trates de prototipar todo antes de considerarlo desarrollable porque podrías caer en la trampa del perfeccionismo. Es válido construir una funcionalidad y, una vez la tienes acabada, decidir que no la pones en la calle. Es más, incluso es posible ponerla a disposición de los usuarios y, al ver que no la aceptan, retirarla. No es tan grave. De hecho, es lo mejor que te puede pasar porque se trata de feedback real. Pero bueno, de esto ya hablaremos en otro artículo más adelante.

Sea como sea, mi consejo es que incluyas siempre en tu Definition of Ready (DoR) una casilla para comprobar que cada historia tiene su Criterio de Aceptación o Definition of Done (DoD) pues las conversaciones que trae consigo son muy valiosas, especialmente porque se producen en un momento muy importante: cuando todo el equipo está decidiendo qué hay que hacer y cómo.

Diferentes granos de detalle: De Historias épicas a Tareas

Siguiendo con la metáfora del refinamiento, el proceso consiste en pasar de unas historias “de grano grueso” a unas historias “tamizadas”, listas para ser consumidas en las actividades que las transformarán en software: la programación, la maquetación, etc, que veremos en detalle en el próximo capítulo; ahí también se producen muchas conversaciones.

Si recuerdas del primer artículo de esta serie, las primerísimas conversaciones suelen estar poco estructuradas y en ellas apenas hay detalles. Todo es muy ambiguo. Con suerte tendremos una hipótesis en forma de Test Card o similar. Sin embargo, a medida que vamos avanzando en la conversación, vamos concretando algunas de las ideas y empezamos a orientarlas a cubrir necesidades de los usuarios. Quizás al final de una Agile Inception o de un User Story Mapping tengamos una colección de ideas algo más concretas. Si fueran historias, serían historias épicas. Desgraciadamente, en nuestro sector es demasiado común dotar de cierta heroicidad a los que trabajaban con este tipo de grano grueso, cuando en realidad son historias dramáticas que demuestran el gran desperdicio que provoca el no desmenuzar más los requisitos.

¿Pero cómo sabemos que una historia de usuario tienen un grano demasiado grueso? El Definition of Ready (DoR) ayuda mucho en esto. Si estáis empezando, acepta de entrada que vuestro DoR necesitará ir adaptándose hasta que sea el que funciona para vosotros. Y más adelante quizás también. Es normal pues aprendemos y nos adaptamos.

Otra técnica que puede ayudar al principio es estimar. Sí, estimar. Ya sabes, preguntarse “¿Es esto demasiado grande?”. En general no es buena idea preguntarse “¿Cómo de grande es esto?” porque la respuesta a esa pregunta no te ayuda. Sin embargo, “¿Esto es más o menos grande que esto otro?” sí que nos ayuda, porque podemos conectarlo con la experiencia de haber desarrollado historias anteriores y con las conversaciones que tuvieron lugar entonces. Utilizar escalas como las tallas de camiseta o similares es más que suficiente. No merece la pena perder más tiempo que el necesario para averiguar una cosa: ¿Estamos todos viendo las mismas dificultades?.

Tratar de predecir el coste del desarrollo que aún no hemos empezado es bastante inútil, especialmente si quieres condensarlo en un número. Sin embargo, utilizar las estimaciones para facilitar una conversación en el equipo y conseguir extraer las discrepancias, éso sí que nos ayudará a evitar problemas más adelante. Para responder a la pregunta de “¿Para cuándo estará acabado esto?” mejor lee este otro artículo.

A veces descubrimos que “estamos a punto de abrir un melón”, es decir, que descubrimos que una funcionalidad va a requerir más conversación de lo habitual y que el refinamiento debe alargarse. En ese caso podemos actuar de varias maneras:

  1. Seguir como si nada. Lógicamente, lo desaconsejo. 🙂
  2. “Abrir el melón” y entrar a discutir sobre todos los detalles hasta dejar la historia bien clarita, lo cuál, indefectiblemente tendrá el efecto de ocupar todo el timebox de vuestra reunión de refinamiento y llegar al final de la misma sin ninguna conclusión clara. Lógicamente, también desaconsejo esto. 😉
  3. Identificar cuál es la nueva necesidad, en qué es diferente de la que originó la historia de usuario en la que estáis refinando y escribir el titular de la misma (o las mismas, porque igual encontráis más de una). Priorizarlas en ese mismo momento y seguid el refinamiento por la que os quede más arriba. Tranquilos, es normal, lo que acabáis de hacer forma parte del refinamiento. A veces llamamos a estas conversaciones como “partir las historias” o incluso en inglés “slice and dice”. Es posible que ayude a facilitar esta conversación tener presente este poster que ayudaron a traducir algunos buenos amigos. ¡Ah! Y sí, claro, esto es lo que aconsejo hacer. 🙂

Ojo, que tan malo es no tener conversaciones como tener demasiadas. Es frecuente querer tener todos, absolutamente todos los detalles de una historia de usuario antes de empezar a desarrollar. Bien, esto puede llevarnos a una parálisis por análisis. Debemos tener un DoR suficientemente flexible como para que el refinamiento sea una conversación en la que salgamos enfocados porque entendemos qué hay que hacer y tenemos una idea suficiente sobre cómo lo vamos a hacer. Averiguar los detalles concretos forman parte del trabajo que hay que hacer a continuación. No sólo de programar vive el desarrollador.

Ya sé, estás pensando en todas esas veces en las que te has atascado en el desarrollo de una historia porque no habías averiguado algún detalle. Bueno, creo que en cada contexto debemos ir encontrando ese balance práctico entre ralentizar el refinamiento para encontrar información necesaria antes de empezar el desarrollo y ralentizar el desarrollo porque no podemos avanzar o porque introducimos defectos en el resultado final. Por ejemplo, a veces hay equipos que si no tienen los mockups del diseñador no pueden avanzar, pero otras veces hay equipos que con un dibujo en una pizarra o una servilleta tienen más que de sobra. Lo siento, no conozco una fórmula ni una receta perfecta para encontrar este equilibrio. Éso sí, estaría muy bien que si hay algo que a ti te funcione lo compartas en los comentarios de aquí abajo.

Con todo esto no quiero decir que no haya que hablar de cómo vamos a resolver una funcionalidad. Por ejemplo, en la Scrum Planning Meeting (si haces Scrum), es típico definir las tareas que se van a hacer para construir una historia de usuario dada. Incluso algunos hasta las estiman. Bueno, no entraré ahí, pero sí en que hay una cierta burocracia innecesaria en detallar las tareas y ponerlas en un tablero para hacerles seguimiento. Cuanto más larga sea esa lista de tareas, más evidente es que esa historia de usuario es demasiado grande.

La película

Creo que este video de Henrik Kniberg es un excelente complemento a lo que he venido contando hasta aquí.

 

En siguientes artículos seguiré el curso del flujo de construcción del software hablando de este rol del dueño de producto como facilitador de conversaciones. Espero que esté siendo útil. Ya sabes que cualquier comentario me ayudará a mejorar las siguientes entradas.