Table of Contents
- Introducción
- A de Agile
- B de Backlog
- C de Ceremonias
- D de Diversidad
- E de Equipo
- F de Feedback
- G de Greenfield
- H de Historias de Usuario
- I de Incertidumbre
- J de Jira
- K de Kanban
- L de Lean Software Development
- M de Manifiesto Agile
- N de No Estimar
- O de Collective Ownership
- P de Prácticas Técnicas
- Q de Quality Assurance
- R de Retrospectiva
- S de Scrum
- U de Usuaria
- V de Rebanado Vertical
- W de Work in Progress
- X de Extreme Programming
- Y… todas las demás personas
- Z de Zero Bugs
Introducción
Si estás leyendo esto es muy posible que estés asistiendo a la PulpoCon 24. Y siguiendo con una tradición no escrita, hemos incluído un libro en el pack de bienvenida. La colección ya abarca cuatro títulos.
Es difícil establecer un patrón, pero si nos fijamos, resulta que el primer y tercer libro trataban algún tema técnico, con ejemplos de código y todo. Mientras que el segundo y este que tienes ahora en las manos, son más bien colecciones de pequeños ensayos sobre temas relacionados con el desarrollo de software.
El de este año, por otro lado, es verdaderamente especial, porque no habla de desarrollo de software desde la perspectiva técnica. Es un libro sobre el movimiento del desarrollo de software ágil. Sobre la forma en la que trabajamos en nuestros proyectos, equipos y empresas. Y lo hace con un formato un poco peculiar: un diccionario tramposo en el que intentamos tocar muchos temas, forzándolos para encajarlos en una estructura de alfabeto. Eso sí, de una manera superficial y con opiniones bastante marcadas, como verás.
La experiencia de trabajar con distintos equipos, negocios, empresas y metodologías, así como el estudio y reflexión sobre las mismas, nos ha llevado a emprender este proyecto un tanto extraño.
El meollo es que el desarrollo de software no es una actividad aislada, ni en el plano individual, ni en el engranaje empresarial. Posiblemente, la mayor aportación del agilismo haya sido constatar que el desarrollo de software es una actividad fundamentalmente social, con fines económicos, algo que ocurre en el contexto de colaboración creativa con un equipo mayor en el que diversas especialidades contribuyen a un fin común.
Al margen de los aciertos y errores del movimiento como tal y de las distintas metodologías que se atribuyen o merecen el calificativo de ágiles, pensamos que es necesario que hagamos una reflexión como desarrolladoras en torno a la forma en que colaboramos y nos implicamos en los proyectos en los que trabajamos.
Y esta es la motivación de este libro y el sentido de que vea la luz en el marco de esta conferencia.
A de Agile
Agile no es una metodología, ni un proceso, ni un framework. Creo que hasta es incorrecto decir que es una mentalidad o mindset. Quizá podríamos decir que Agile es una forma de reflexionar sobre el desarrollo de software. O, si lo prefieres, se trata de una filosofía para abordarlo.
Históricamente, podemos pensar que Agile nace con el Manifiesto Agile. Sin embargo, el Manifiesto fue más un punto de encuentro para diversos grupos y profesionales que ya habían desarrollado sus propias metodologías y frameworks, como extreme programming, scrum, crystal clear, o lean software development. Incluso DevOps podría considerarse una forma de Agile. Muchos de estos frameworks están inspirados u obtienen ideas de las metodologías Lean Manufacturing o el Toyota Production System, aplicadas a desarrollo de software.
¿Por qué Agile? Pues porque los equipos de desarrollo de software entendieron que las metodologías clásicas de la ingeniería no funcionaban bien cuando se aplicaban al software.
Por lo general, la ingeniería física require un diseño meticuloso y una planificación cuidadosa antes de lanzarse a implementar. No puedes empezar a construir un puente sin saber donde vas a poner los pilares, qué hay al otro lado, cómo se va a usar, qué peso va a tener que soportar, qué fuerzas pueden influir sobre él, como corrientes de agua o vientos, y un largo etcétera.
Dicho de un modo sencillo: la ingeniería física crea productos que han de acertar a la primera. Sin embargo, al requerir mucho tiempo de desarrollo y ejecución, es muy posible que cuando por fin han sido desplegados puedan haber ocurrido cambios en el entorno a los que ya no es posible adaptarse. Por eso, es necesario considerar muy cuidadosamente todas las variables en juego, partiendo de los requisitos del proyecto, pero también anticipando circunstancias futuras.
El software no tiene los mismos condicionantes. En comparación con cualquier ingeniería física, que trabaja con materiales sujetos a las leyes de la naturaleza, el software es mucho más libre. Puedes usar el software a medida que se construye, una vez que hay suficientes elementos desplegados. Incluso aunque esté incompleto puede proporcionar un valor. Además, es relativamente fácil de cambiar, lo que permite reaccionar cuando vemos que el negocio va transcurriendo de maneras que no habíamos previsto o, simplemente, cuando comprobamos que nos hemos equivocado en algo.
Para ello son fundamentales los ciclos de feedback, es decir, la información que obtenemos de diversas fuentes acerca del comportamiento del software. Cuanto más cortos, mejor. Y por cortos entendemos minutos mejor que horas, horas mejor que días, días mejor que semanas y así sucesivamente. Para lograrlo necesitamos incorporar, por un lado, a la cliente o usuaria en el equipo de desarrollo de forma que podamos tener conversaciones con ella cada vez que sea necesario. Por otro lado, incorporamos prácticas que nos faciliten el feedback, como pair-programming, test driven development, etc. Pero también implica entregar el software en pequeños lotes de funcionalidad, de tal modo que revertir lo desplegado o introducir cambios sea lo menos costoso posible.
Esta forma de abordar los proyectos de software puede parecer idílica, pero es perfectamente factible.
Hay que tener en cuenta es que no es algo que se pueda conseguir de la noche a la mañana. Requiere un proceso de aprendizaje. Implica hacerse consciente de como trabajas y reflexionar sobre cómo mejorar esa forma de trabajar. Por tanto, presupone una cierta capacidad de autocrítica, individual y grupal.
Es decir: un equipo no se vuelve Agile porque le adjudiquemos esa etiqueta, o por introducir una serie de prácticas descontextualizadamente. Ni siquiera por seguir un framework concreto. En vez de eso, un equipo aprende a trabajar de forma Agile a medida que desarrolla un proyecto.
No existe una receta para ser Agile salvo aplicar, quizá, los principios del Manifiesto. Por otro lado, disponemos de frameworks que buscan articular una forma de trabajar ágilmente. Pero estas metodologías no definen la agilidad.
En fin, si el manifesto te parece demasiado largo, quédate con esta definición de Allen Holub sobre Agile:
- Trabajad en lotes pequeños
- Hablad entre vosotras
- Mejorad la vida de la gente
Todo lo demás es basura y distracciones.
B de Backlog
En la metodología Scrum el backlog es, o debería ser, una lista de historias de usuario ordenada por prioridad. En otras palabras, un backlog es una lista de deseos que expresan los clientes sobre el producto que estamos desarrollando. Lo que no es, o no debería ser, es una lista de tareas, ni tampoco una colección de ideas interesantes para hacer en un futuro que nunca llega.
No es una lista de tareas porque cuando hablemos de historias de usuario, veremos que estas son la expresión breve de los deseos o necesidades del cliente y que se han de plantear como el inicio de una conversación, no como un final. O sea: la historia de usuario ni es una toma de requisitos, ni define lo que tenemos que hacer. Define la necesidad que tenemos que solventar.
El cliente, en el momento de formular una historia de usuario, no sabe como se va a materializar ese deseo. Es más, es nuestro cliente porque contrata nuestros servicios para construir lo que necesita. Ese es el trabajo del equipo de desarrollo, como veremos.
El Backlog según Scrum
Según la Guía de Scrum (nov 2020), el Backlog de producto es
El trabajo pendiente del producto es una lista emergente y ordenada de lo que se necesita para mejorar el producto. Es la única fuente de trabajo emprendida por el equipo Scrum.
Y también contempla el Backlog de sprint, que se compone básicamente de las historias de usuario que hemos decidido abordar en un período concreto de tiempo: el famoso sprint.
El Trabajo pendiente de Sprint se compone del objetivo sprint (por qué), el conjunto de elementos de trabajo pendiente de producto seleccionados para el Sprint (qué), así como un plan accionable para entregar el incremento (cómo).
En cualquier caso, esta lista de historias de usuario debería estar ordenada por valor decreciente. Cuando más arriba en la pila, más prioritaria, pues la función del backlog es responder a la pregunta: ¿qué deberíamos hacer a continuación? Y lo que deberíamos estar haciendo es lo que sea más importante para el cliente.
Hay más cosas en la Guía de Scrum que posiblemente te sorprendan, porque no se ven mucho:
Un backlog por producto, no un backlog por equipo. Lo más probable es que estés trabajando en un entorno en el que existe un backlog del equipo, incluso aunque haya varios equipos desarrollando el mismo producto. Esto genera dependencias, ineficiencias y silos, ya que ninguno de los equipos tendría una visión general. Un ejemplo del resultado es la típica situación de “estamos esperando a que otro equipo tenga…”, “el otro equipo no tiene planeado esto hasta dentro de…”, etc.
El product backlog debería ser único. Cada equipo tendría un sprint backlog propio con la que sería su aportación durante la iteración en curso.
Mira mamá, sin Backlog
Aunque mucha gente piensa que el backlog es connatural al trabajo ágil en realidad es solo una prescripción de la metodología Scrum. Un equipo Agile podría trabajar sin backlog. La idea puede sonar extraña, pero si tenemos una colaboración estrecha con el cliente, lo más probable es que sea relativamente fácil determinar en qué tendríamos que estar trabajando en este momento y a continuación.
El problema del backlog no es su existencia o no. El problema es usarlo como un contenedor para:
- Cualquier idea sobre el producto, con independencia de si se necesita o no.
- Tareas técnicas que el equipo considera que necesita realizar porque deuda técnica, etc.
- Bugs, porque por alguna razón podemos convivir con ellos hasta que nos parezca procedente abordarlos.
- Posibles opciones para soluciones técnicas que queremos estudiar algún día.
Por lo general, el resultado de usarlo para estos fines es un backlog enorme, que nunca tiene fin y cuyos items envejecen sin que nos demos cuenta, hasta el punto de que en algún momento dejan de ser relevantes.
Una práctica sana con un backlog es eliminar entradas. Así, por ejemplo, si un item no ha entrado en los últimos dos sprints debería descartarse, incluso habiendo sido refinado: si nadie echa de menos esa prestación ¿para qué preocuparse por ella?. Por supuesto, el tope de dos sprints es totalmente arbitrario, podría ser uno solo.
Ya puedo escuchar los gritos de horror: Pero si a lo mejor es una buena idea. Lo que pasa es que hay otras cosas que han sido más importantes y, por tanto, se han priorizado por encima de esa. Pues la respuesta que tengo es: si realmente es algo que aporta valor volverá en algún momento. Esto es algo que los equipos Lean suelen hacer: mantener un backlog muy actualizado, eliminando cualquier cosa que no se haya movido en el último mes.
Steve Jobs decía que para mantener el foco hay que decir no a muchas cosas, pero sobre todo a muchas buenas ideas. La moraleja de esta frase es precisamente que lo importante es identificar lo que tendríamos que estar haciendo ahora mismo. No lo que podríamos llegar a hacer algún día.
C de Ceremonias
La única vez en la que el Manifiesto Agile prescribe algo parecido a una actividad concreta es cuando dice que el equipo periódicamente reflexiona sobre su trabajo:
De forma periódica, el equipo reflexiona sobre como hacerse más efectivo, tras lo cual afina y ajusta su comportamiento de acuerdo a ello.
En Scrum esto se hace mediante la Retrospectiva del sprint. Al respecto, la Guía 2020 dice:
El propósito de la retrospectiva Sprint es planificar formas de aumentar la calidad y la eficacia.
De hecho, el Manifiesto tampoco dice que tenga que hacerse algo así como una reunión formal, aunque seguramente tiene sentido práctico fijar una reunión periódica para hacerlo. Aparte de eso, no se prescribe ninguna ceremonia. Puedes ser Agile sin estas cosas. Las ceremonias forman parte de los frameworks, y las más conocidas son, sin duda, las de Scrum.
Las ceremonias en Scrum
Entre los diferentes frameworks ágiles, Scrum prescribe una serie de eventos, cuatro de ellos más conocidos como ceremonias.
- Sprint: es el período de tiempo en que se articula la entrega constante de valor.
- Planificación de sprint: la reunión al principio del sprint en donde se deciden en equipo los objetivos y se organiza cómo se van a lograr. Se podría decir que es donde se crea el backlog de sprint.
- Scrum diario o Daily scrum: donde se adapta el backlog de sprint y se genera un plan para el día. No es una reunión para informar de lo que hemos hecho, cosa que debería quedar reflejada en otro lado, sino de lo que vamos a hacer y cómo.
- Revisión del sprint: se inspecciona lo conseguido en el sprint respecto al producto.
- Retrospectiva del sprint: se planifican formas de mejorar la calidad y la eficacia del trabajo.
¿Echas de menos el Refinamiento o Grooming? Pues lamento decirte que no es una ceremonia de Scrum, sino un proceso contínuo que se realiza a lo largo del sprint para descomponer y afinar más el trabajo pendiente. La palabra refinamiento solo aparece una vez en la Guía y no precisamente para denominar una ceremonia. Eso sí, existen muchos materiales que la citan como la “quinta ceremonia no oficial” de Scrum. Si no es oficial, no es Scrum.
Tampoco existe una ceremonia de Demostración. En todo caso, existe la entrega de valor.
Pero también podemos encontrar fácilmente menciones a las ceremonias Agile. No existen. Como hemos visto, las ceremonias solo existen en el contexto de frameworks específicos.
¿Hay ceremonias en otro frameworks?
Lo cierto es que ni Extreme Programming ni Lean Software Development prescriben este tipo de eventos o ceremonias. Eso no quiere decir que no sea necesario dedicar momentos a tomar decisiones sobre el trabajo que se va a llevar a cabo, o a revisar lo realizado.
Lo importante, en todo caso, no son las ceremonias per se, sino las necesidades que pretenden satisfacer. Así, por ejemplo:
- El sprint define un período al final del cual existe un compromiso de entrega de valor. El objetivo sería aportar un cierto nivel de predictibilidad, de modo que diferentes equipos de la empresa puedan sincronizarse. Es una forma de estimación, otro concepto que no existe en agile. De hecho, un equipo agile busca entregar el valor de forma sostenida, en pequeñas unidades y el ideal es que estas unidades requieran un esfuerzo similar y lograr la predictibilidad sabiendo que cada unidad de desarrollo se puede entregar en un tiempo fijo y muy corto.
- La planificación busca tomar decisiones acerca de como hacer lo que se haya decidido hacer. En Extreme Programming, esa decisión es el resultado de hablar con el cliente sobre qué necesita ahora.
- La reunión diaria o daily tiene el objetivo de organizar el trabajo necesario para esa jornada, identificando posibles problemas y formas de solucionarlos. En el fondo, la existencia de una daily parece implicar que cada persona del equipo trabaja separadamente. En Extreme Programming, se favorece el trabajo en parejas (pair-programming) o en equipo (mob-programming) como forma de prevenir ese tipo de problemas que se discuten o se resuelven en el momento.
- La revisión del sprint sería una forma de comprobar si se han conseguido los objetivos fijados en la planificación. Básicamente, lo que buscamos es saber si hemos estado trabajando en lo que nos habíamos propuesto.
- La retrospectiva tiene la función de analizar nuestra forma de trabajar y encontrar formas de mejorarla.
Hay algo en común en todos estos puntos: son momentos para la obtención de feedback y cada uno corresponde a distintos ciclos.
Fake o Dark scrum
El problema surge cuando convertimos estas ceremonias en rituales vacíos de su contenido.
- Cuando el sprint es un periodo de tiempo que o bien no significa nada porque no hay entrega de valor, o bien se convierte en un deadline, en un plazo.
- Cuando la planificación es solo la selección de las tarjetas/tareas que vamos a realizar.
- Cuando la daily scrum es una reunión de reporting en la que se cuenta lo que se ha hecho, y no se organiza el equipo para lo que hay que hacer.
- Cuando la revisión del sprint es un recuento de tareas hechas vs. tareas no completadas.
- Cuando la retrospectiva no se centra en la forma en que trabajamos y qué necesitamos para mejorarla, sino que se enfoca a otros temas.
D de Diversidad
A veces limitamos la definición de diversidad a la presencia o no de mujeres en los departamentos de tecnología, y particularmente en los equipos de desarrollo de software. Diversidad abarca esto y mucho más, si bien la falta de representación de mujeres en tecnología es especialmente dolorosa, sobre todo si pensamos que en sus orígenes la informática se consideraba una carrera femenina. Y no porque digamos que la primera programadora fue Ada Lovelace, sino porque en su momento el trabajo con ordenadores permitía una ocupación decorosa y adecuada para mujeres trabajadoras, aunque no dejaban de estar subordinadas a los hombres en muchos casos. Esto no obedecía a un punto de vista feminista, sino más bien todo lo contrario.
Gracias a eso, contamos con muchas mujeres referentes en el campo, que realizaron grandes aportaciones entre los años 40 y 70, como pueden ser, por citar alguna de las más conocidas:
- Grace Hopper, primera programadora del Mark I, creadora del primer compilador e inventora del lenguaje COBOL.
- Margaret Hamilton, que desarrolló sistemas de predicción meteorológica y diseñó el sistema de navegación del programa Apolo.
- Hady Lamar, desarrolló técnicas que constituyen la base de las comunicaciones inalámbricas actuales.
- Jude Milhon, activista hacker, pionera en la lucha por los derechos digitales y acuñadora del término cyberpunk.
- Evelyn Berezin, desarrolló el primer sistema informatizado de reservas para aerolíneas.
- Mary Allen Wilkes, primera persona en usar un ordenador en su casa y ¡teletrabajar!
Posteriormente, la profesión fue llenándose de varones hasta el punto de que la representación de mujeres alcanzó mínimos históricos. Hoy por hoy, dependiendo de las áreas, las cifras van mejorando, pero aún estamos lejos de un equilibrio.
Si vamos a eso, el Manifiesto Ágil es una buena ilustración: ni una sola persona que no fuese un varón blanco de entorno anglosajón.
Sin embargo, diversidad no es solo una cuestión de representación masculina frente a femenina, aunque sea un tema fundamental. También tenemos un problema de diversidad relacionado con otras características demográficas como la etnicidad o la edad, y por supuesto con la diversidad física e intelectual. Quizá lo más correcto sería hablar de la sobre-representación de un grupo socio-demográfico muy específico: varones blancos y relativamente jóvenes.
Es interesante pensar en las consecuencias de la falta de diversidad y cómo afrontarlo desde nuestras posiciones en la industria.
El problema de la representación
Se trata de una de estas situaciones que se retroalimenta. Si ya hay pocas mujeres en la industria, o pocas personas de una característica demográfica específica, menos aún serán visibles en publicaciones, eventos o medios. Esto refuerza ideas o estereotipos sobre qué tipo de personas son adecuadas para ejercer la profesión. Por tanto, atraerá a un cierto tipo de personas que querrían orientar su carrera hacia el desarrollo de software o la tecnología en general, ya que pueden identificarse con otras personas que actúan como modelos.
Para evitar esto tenemos que cargar un poco los dados. Algunos ejemplos:
Cuando se organizan eventos y conferencias es importante buscar activamente perfiles con poca representación para darles visibilidad. Lanzar un Call for Papers y esperar que se presenten personas que habitualmente se sienten excluídas de este tipo de convocatorias es ilusorio: no se van a presentar precisamente porque se sienten excluídas. En su lugar, tienes que dedicar un tiempo para descubrir personas interesantes e invitarlas a participar, cuidando de que su experiencia sea la mejor posible.
Y además, tienes que organizar tu evento teniendo en cuenta la inclusión en sus muchos aspectos, tienes que generar un entorno seguro y acogedor. Con tiempo y consistencia, lograrás que el evento se perciba como inclusivo y seguro.
A la hora de buscar talento no basta con publicar ofertas de trabajo en las distintas plataformas. Es necesario plantearse desde la redacción de la oferta en sí, hasta los medios y círculos en donde difundirlas. Por ejemplo: los varones tienden más a apuntarse en ofertas para las que no reúnen todos los requisitos, mientras que las mujeres tienden a no apuntarse si no se consideran preparadas en alguno de ellos.
Aparte de la compensación salarial, ¿ofreces beneficios que sean atractivos para todo tipo de personas? Tus actividades de team-building, ¿están pensadas para todas o solo para un cierto estereotipo? Pasar un día entero en la playa puede parecer divertido, pero para mucha más gente de la que piensas puede ser una experiencia desagradable por un montón de razones. Cerrar el bar de moda para tu empresa también suena como una gran idea, pero ¿qué hay de todas aquellas personas de tu equipo que no disfrutan en ese tipo de ambiente, que no beben alcohol, que son sensibles al ruido, etc.?
También tenemos que hablar de los procesos de selección. Puede que consigas candidatas diversas, pero ¿saldrán corriendo despavoridas tras la primera entrevistas? Esto es: ¿están tus procesos preparados para recibir candidaturas diversas? ¿Puedes proporcionar una flexibilidad en el proceso para ayudar a las candidatas a mostrar sus mejores capacidades?
Una crítica habitual a este tipo de propuestas es la de decir que se pretende seleccionar a una persona por ser mujer (o mayor de 40, o racializada…), no por su capacidad o mérito técnico, sino por cumplir una cuota. Y la respuesta es un no rotundo: lo que se busca es una persona que tenga la capacidad y mérito técnico requeridos y que, además, pertenezca a uno de estos colectivos.
Lo más sangrante, y desde un punto de vista bastante pragmático, es que varios estudios han mostrado las ventajas de trabajar con equipos diversos. En pocas palabras: las empresas que favorecen la diversidad e inclusión en sus equipos tienden a conseguir más beneficios. Al fin y al cabo, el mercado es diverso por naturaleza. Pero si lo miras con los ojos de un equipo uniforme puede que no sepas abordar esa diversidad, y tus productos o servicios no alcanzarán todo ese mercado potencial, sino el de los consumidores que se parezcan… a ti, un mercado que puede ser bastante más pequeño de lo deseable.
Uniformidad y endogamia
La falta de diversidad en los equipos genera un problema de endogamia que perjudicaría la innovación. Si juntamos personas de características y experiencia muy similares, lo más probable es que tiendan a proponer las mismas soluciones, ser más conformistas con sus propias decisiones y menos abiertos a sugerencias externas.
Esta endogamia también hace que los perfiles divergentes o discrepantes tengan más problemas de adaptación y facilita que, con el tiempo, prefieran buscar su futuro en otra parte. Recuerda que la cultura de un equipo y, en general de una empresa, son las personas que mantienes y las que dejas marchar. De hecho, la endogamia puede matar el talento. Ya puedes contratar a la mejor programadora del mundo, que si la pones en un equipo endogámico mediocre sin tomar otras medidas, el equipo no va a mejorar su rendimiento o su calidad. Lo más seguro es que en pocos meses esa persona esté trabajando para otra empresa. Y eso en el mejor de los casos.
Por su parte, los equipos que cuentan con perfiles diversos, con procedencias y experiencias vitales distintas, podrían ser más abiertos a explorar ideas innovadoras, o al menos a considerar más puntos de vista al analizar una situación. La existencia de diversidad en un equipo aumenta la conciencia de la diversidad en el mundo en general, lo que lo habilita precisamente para entender mejor el mercado al que se dirige. En estos equipos, lo normal es tener ideas diferentes y debatirlas.
E de Equipo
Digámoslo con claridad: juntar a un cierto número de personas y ponerlas a trabajar en el mismo lugar no es crear un equipo. Para que exista un equipo tiene que haber un objetivo común, unos valores e intereses compartidos. Un equipo tiene que ser algo más grande que la suma de sus componentes.
Se podría decir que un equipo tiene que actuar como una unidad. Incluso diría que como un organismo. Cada uno de sus componentes aporta sus propias capacidades al fin común. Como todo, esto implica que es necesario aprender a trabajar de una cierta manera.
Por lo general, todas las aproximaciones agile consideran que un equipo de desarrollo de software debe dotarse de todas las capacidades necesarias para cumplir sus objetivos de forma autónoma. Así, normalmente, queremos que haya personas con conocimientos en frontend, backend, sistemas, user experience y negocio.
Esto no siempre quiere decir que tenga que formar parte del equipo una persona de cada una de esas especialidades. Las que tienen que estar presentes son las capacidades y los conocimientos. Sin embargo, la complejidad de cada uno de los ámbitos hace que sea muy frecuente tener especialistas. En cualquier caso, también depende de la organización, su propia complejidad y, por qué no decirlo, de su capacidad económica.
En muchos casos, lo suyo sería que los equipos se formasen de esta manera, con los múltiples perfiles necesarios. Con el tiempo, el conocimiento debería transmitirse horizontalmente. Por ejemplo, las desarrolladoras aprenderían lo suficiente como para llegar a valorar la prioridad de una prestación en términos de negocio. La persona de producto, por su parte, podría entender el coste técnico de ciertas soluciones. Las desarrolladoras podrían ser capaces de trabajar tanto en backend como en frontend, y controlar aspectos de la infraestructura necesarios.
Este desarrollo es lo que se conoce como perfil en “T”: fuertes conocimientos de tu propia especialidad, y suficientes de las otras, tanto como para poder contribuir en ellas, aunque sea de una forma limitada.
Este tipo de perfiles “T” contribuye a reducir el bus factor en los equipos. El bus factor es un índice que nos dice cuantas personas del equipo tendrían que desaparecer súbitamente para que el proyecto se paralice porque poseen información o conocimiento crítico de forma exclusiva. Si no están, se pierde ese conocimiento. Este índice nos está indicando si el conocimiento fluye entre las personas del equipo.
Este bus factor se puede reducir de varias formas. En lo que toca al equipo de personas, se deben aplicar medidas que faciliten la diseminación del conocimiento, lo que acaba llevando a desarrollar estos perfiles “T” de los que hablábamos hace un momento. Algunos ejemplos:
Evitar la multitarea de equipo. El equipo debería trabajar conjuntamente en los mismos proyectos o historias de usuario, o al menos hasta el punto de que no se molesten entre sí.
Cuando las distintas personas del equipo trabajan en proyectos no relacionados, o mínimamente relacionados, tienden a generarse silos de conocimiento. Con el tiempo, las mismas personas tenderán a dedicarse a los mismos temas. Esto es por una cuestión de familiaridad y eficiencia. Si cada semana tienes que elegir entre trabajar en algo de lo que tienes experiencia previa y algo que te resulta totalmente nuevo, lo más seguro es que acabes escogiendo lo conocido. Además, el trabajo saldrá adelante más rápido.
Si escoges la tarea completamente nueva, aparte de trabajar más lentamente porque tienes que aprender lo necesario para poder ejecutarla, lo más seguro es que acabes pidiendo ayuda a alguien que tendrá que aparcar su propia tarea para dedicarte un tiempo. Esto acaba generando una sensación negativa de ineficiencia y bajo rendimiento.
Si el equipo practica revisiones de código asíncronas para poder mezclar los cambios se manifestarán otros problemas. Es difícil revisar un código del que no tienes contexto.
Trabajar regularmente en formatos de pair-programming o mob-programming. Estos son los más adecuados para favorecer la diseminación de conocimiento entre desarrolladores, pero también entre otros miembros del equipo.
Pair-programming es la práctica de trabajar en pareja para desarrollar una prestación en código. La idea básica es que una de las personas, o driver, se encargue de escribir el código y la otra navigator se ocupe de dirigirlo con un enfoque más estratégico. Estos roles se deben alternar, incluso dentro de la misma sesión. Hay diversas configuraciones para llevar a cabo sesiones de pair-programming, dependiendo del grado de experiencia de cada persona y de los objetivos de la sesión.
Mob-programming es una práctica similar, pero en este caso, es todo el equipo el que participa aportando ideas, haciendo preguntas, proponiendo soluciones, buscando información, etc. Una forma de conceptualizarlo es entender estas sesiones como conversaciones del equipo en las que se toman notas en forma de código. De hecho, se puede entrar y salir de la sesión, invitar a otras personas de otros equipos que puedan tener algo que ver con lo que estamos desarrollando, etc. Es una técnica ideal para los primeros pasos de diseño de una prestación, en los que se pueden ir estableciendo los componentes necesarios, los contratos entre distintas partes, etc.
Esto no quiere decir que tengamos que trabajar en uno de estos formatos todo el tiempo. Lo ideal es que el equipo entero trabaje conjuntamente en el análisis de la historia de usuario, definiendo sus criterios de aceptación, y los primeros pasos de diseño de la solución, hasta el punto en que el trabajo por especialidad tenga más sentido. Y así, sucesivamente, hasta que tengamos tareas muy acotadas que sea fácil realizar individualmente.
Diseñar soluciones sencillas, fáciles de entender y cambiar. En lo que respecta al código, lo ideal es que sea lo más expresivo y fácil de entender posible. El código, como expresión de un conocimiento del negocio, debería reflejar los conceptos y el lenguaje que manejamos en el equipo. Si el código no se puede entender, no es fácil ni económico intervenir en él. Por eso, las soluciones ingeniosas, pero incomprensibles, no son una buena idea.
Documentar procesos, decisiones, soluciones y diseños, y mantener al día esa documentación. La documentación debería estar siempre lo más cerca posible de donde se va a necesitar. En muchos, casos, la documentación se va a necesitar junto al código, lo cual nos permite establecer una espacie de reglas de preferencia a la hora de documentar:
- El código debería ser lo bastante expresivo como para que sea fácil entender qué hace y cómo, para lo cual son necesarios buenos nombres y el uso de patrones comunes.
- Los comentarios en el código tendrían la función de explicar decisiones concretas que se hayan aplicado. Si bien el código mismo describe qué hace y cómo lo hace, el porqué de escoger una cierta manera de hacer las cosas es difícil o imposible de expresar en código. Para eso, añadiremos comentarios.
- Architecture Decision Records (ADR): algunas decisiones se refieren no tanto a partes específicas del código, como a cuestiones de amplio alcance: estructura de la aplicación, organización del código, elección de una cierta tecnología, etc. Estas decisiones o recomendaciones se pueden registrar en documentos que viven en el propio repositorio del código.
- Readme: el archivo readme del proyecto debería contener una descripción del proyecto y sus objetivos, así como las instrucciones necesarias para trabajar y contribuir.
- Tooling: lo ideal es que automaticemos cuantos más pasos necesarios para configurar y empezar a trabajar con el proyecto, asegurando un entorno de desarrollo común, independiente de la persona que trabaje con él. Para eso podemos usar herramientas como Make, Docker, etc.
- How-to o recetas: en algunos casos, introducir documentos que expliquen como realizar ciertos procesos ayudará a que cualquier persona del equipo pueda ser autónoma y no dependa de alguien en exclusiva para realizarlo. Mejor aún si esto se encuentra automatizado. Típico ejemplo: herramientas para corregir datos, probar ciertas prestaciones sin riesgo para producción, etc.
- Otra documentación: La documentación que no está relacionada directamente con el código, puede alojarse en otros sistemas, para los cuales existe numerosa oferta. Lo ideal siempre es que sean herramientas fáciles de usar y que, idealmente, permitan integrar distintas fuentes de información.
F de Feedback
Todo en Agile gira en torno a bucles de feedback. O más bien espirales. Los bucles ágiles no consisten en girar sobre un mismo punto una y otra vez, sino un movimiento constante de autoevaluación, revisión del conocimiento y evolución. El desarrollo de software agile pretende ser espiral, o sea: incremental e iterativo.
Por desarrollo incremental entendemos un proceso en el que un producto se construye a base de añadir pequeños aumentos de funcionalidad de forma sostenida y relativamente predecible, en lugar de apostar todo a única entrega final del producto completo.
De este modo, se logran varios beneficios:
- Al desarrollar pequeñas cantidades de funcionalidad es relativamente fácil definir qué criterios de aceptación debe cumplir, podemos escribir código sencillo para implementarla, lo que reduce el tiempo de entrega y el riesgo asociado a la introducción de grandes cambios.
- Las entregas pequeñas nos facilitan identificar los defectos nada más poner una pieza de funcionalidad en producción. Si aparece un defecto, sabes que el origen tiene que estar en esa última entrega. Puedes volverla atrás fácilmente, o simplemente ver si puedes resolver el problema desplegando un arreglo.
- Una vez que ponemos una funcionalidad, aunque sea limitada, en producción, en manos de sus usuarias, podemos empezar a recibir feedback: ¿responde efectivamente a una demanda? ¿Está siendo usada? ¿Tiene limitaciones que las usuarias perciben? Con esta información podemos decidir nuestros pasos inmediatos: seguir con nuestro plan, hacer mejoras en la funcionalidad entregada, dejar ese camino, etc.
Desarrollo iterativo se refiere a que el proceso vuelve constantemente sobre el producto para refinar y ampliar su comportamiento. Al principio puede ser una idea sencilla y genérica, definida con trazos bastos, que nos permite poner a prueba una hipótesis de negocio sin arriesgar demasiada inversión y esfuerzo.
Cada nueva iteración se alimenta del feedback obtenido por la anterior, proporcionándonos información con la que tomar decisiones sobre nuestro siguiente paso: ¿qué es lo que ha funcionado? ¿Qué es lo que no? Y, por tanto, ¿qué deberíamos hacer para maximizar lo primero y minimizar lo segundo?
Feedback loops
En general, los frameworks ágiles abrazan la idea de feedback loop de una manera u otra. Scrum, por ejemplo, usa el sprint como la unidad de tiempo en la que se realiza una entrega o incremento y se obtiene feedback.
Pero si hay un framework que haya profundizado en la idea del bucle es Extreme Programming. Los bucles de feedback están definidos por el contexto en que se producen y están insertos en la propia forma de trabajar propuesta. En XP los ciclos de feedback comienzan en el mismo momento de escribir código:
- Puesto que XP promueve el uso de Test Driven Development, el primer ciclo de feedback nos lo proporciona el ciclo de TDD, que nos dice si estamos escribiendo el código necesario para hacer pasar el test que, a su vez, define el pequeño incremento de funcionalidad que estamos buscando. Este feedback es inmediato.
- Otra práctica técnica de XP es Pair-programming, en el que se produce creación y revisión colaborativa de código. Cada persona de la pareja propone ideas y las discuten inmediatamente, obteniendo feedback en segundos: ¿es una buena solución para este problema? ¿Es un patrón que nos brindará flexibilidad para cambios en el futuro? ¿O, en cambio, esconde un problema potencial?
- La ejecución de la suite completa de tests unitarios nos puede proporcionar feedback en minutos acerca del impacto de nuestros cambios en el conjunto del software.
- La negociación en las parejas de Pair-programming es una fase de algo más alto nivel de abstracción que la fase de código. Aquí se discuten aspectos más generales de diseño, que pueden discutirse en el equipo completo y que posiblemente consuman un tiempo que se puede medir en horas.
- La stand-up meeting (o daily en términos de scrum) nos proporciona un ciclo de feedback que dura un día, y que nos sirve para verificar que estamos usando los recursos de forma equilibrada y que estamos moviéndonos en la dirección adecuada.
- Los tests de aceptación, que definen la feature en desarrollo, nos proporcionan feedback acerca de si estamos construyendo el producto deseado. Este ciclo tiene se cumple en días.
- El plan de iteración, en el que se decide en qué vamos a estar trabajando, puede definir un ciclo de unas pocas semanas.
- El plan de release, en el que se decide qué se va a poner en manos de los usuarios, puede definir un ciclo de meses.
La duración de alguno de los ciclos puede variar dependiendo del tipo de producto. Por ejemplo, si estamos hablando de una aplicación web, prácticamente cada feature se puede habilitar en el momento, lo que hace que el ciclo de iteración y release coincidan.
Pero si se trata de una aplicación móvil, los ciclos son diferentes. Incluso publicando versiones con cierta frecuencia, acumulamos distintas features y mejoras para desplegarlas juntas.
En cualquier caso, estos bucles tienen sentido en el marco de prácticas concretas diseñadas justamente para que el feedback sea utilizado.
G de Greenfield
La mayor parte de tu vida de trabajo consistirá en incorporarte a proyectos que ya están en marcha. En ese sentido es bastante raro empezar a trabajar en algo completamente nuevo que el equipo tenga que construir desde cero.
Muchos equipos fuerzan ese empezar de cero cuando deciden rendirse con una implementación antigua y prefieren tomar el camino de volver a escribir un software sobre nuevas bases. A veces con una nueva arquitectura, en un lenguaje que consideran más apropiado y, posiblemente, usando algunas tecnologías nuevas y de moda.
Una esperanza general con respecto a este tipo de reescrituras y proyectos greenfield, es la de que “esta vez vamos a hacer las cosas bien”. Un bonito deseo que raramente se cumple.
¿Qué es lo que lleva a un proyecto nuevo a torcerse? Seguramente hay muchas causas interviniendo a la vez, en diferentes grados.
Sospecho que la más importante es que en realidad empezar un proyecto de cero no resuelve los problemas preexistentes que llevaron por mal camino al anterior.
Por ejemplo, si en tu empresa ha migrado de un monolito a micro-servicios y la cosa no ha ido muy bien, lo más seguro es que el problema venga de antes. Al fin y al cabo, si ya no estabáis gestionando bien la modularización del monolito, hay que pensar que los micro-servicios son muchísimo más difíciles.
Otro caso típico es cuando vuestro proyecto antiguo carecía de tests, lo que os impedía intervenir en él con seguridad. ¿Qué garantías tienes de que ahora los váis a tener? No es el primer proyecto nuevo en el que los tests se posponen, con la consecuencia de que al intentar introducirlos por fin, resulta difícil porque el diseño no está orientado a la testabilidad. Es decir, ¿a la hora de plantear un nuevo proyecto estamos teniendo en cuenta las capacidades técnicas necesarias para empezar con buen pie?
Una razón por la que los proyectos nuevos acaban igual de liados que aquellos a los que sustituyen es que olvidamos que todo código puesto en producción acumula un desfase con respecto al conocimiento de negocio. Esto es: el conocimiento de negocio que hemos representado en el código deja de estar al día con el conocimiento de negocio que maneja el equipo, y si no velamos por sincronizarlo, llegará un momento en que el desfase será tan grande que nos generará problemas. Esto tiene un nombre: deuda técnica.
A veces, el nuevo proyecto no es más que una traducción desde otro lenguaje de programación. No solamente se acumularán los problemas existentes, sino que se añadirán los derivados de intentar replicarlo con los paradigmas de otro lenguaje.
Una vieja conocida en estos casos es la Ley de Conway, que dice que una organización que produce software tiende a reproducir en él sus estructuras de comunicación. En consecuencia, reestructurar el software suele estar condenado al fracaso si no hay cambios en la propia organización. En ocasiones, se intenta aplicar la llamada Maniobra Inversa de Conway: transformar la estructura de la organización, a fin de impulsar cambios en la estructura del software.
Una de las preguntas que creo que no se hacen en los equipos que abordan nuevos proyectos, o transformaciones de proyectos existentes, es si poseen el conocimiento y la capacidad necesaria para llevar el proceso a buen puerto. ¿Cuántos proyectos se escriben otra vez de cero simplemente porque el equipo no sabe refactorizar de forma segura? ¿O porque el equipo no domina las técnicas de testing?
H de Historias de Usuario
Según Wikipedia, la idea de Historia de Usuario la introdujo Kent Beck en 1997, en el contexto del ya famoso proyecto Chrysler C3, en el cual definió las bases de lo que sería Extreme Programming, e introdujo prácticas técnicas como TDD o pair programming. En 1998, Alistair Cockburn, que estaba de visita en el proyecto y a quien conocerás por ser proponente de la Arquitectura Hexagonal, acuñó la frase “Una historia de usuario es la promesa de una conversación”.
Tengo que decir que me encanta la expresión, ya que describe algo que tendemos a olvidar. La Historia de Usuario no es una toma de requisitos, sino la expresión de un deseo o necesidad del cliente y, por tanto, la promesa o inicio de una conversación con este para entender esa necesidad y cómo se tiene que reflejar en el desarrollo del producto.
En 1999, Beck habla de las historias de usuario en la primera edición de su libro Extreme Programming Explained al describir el Planning Game. Esta es una reunión de planificación, en la que el equipo de desarrollo acuerda con el cliente qué historias deberían abordarse en la siguiente iteración del producto. Las historias se escriben en tarjetas, describiendo la necesidad expresada por el cliente, de forma que estas se manipulan físicamente, se ordenan, se apuntan detalles, etc.
Posteriormente, en 2001 Ron Jeffries propone un formato para la creación de Historias de Usuario, llamado “las 3 C”: Card, Conversation and Confirmation:
- Card o tarjeta: es un objeto físico en el que se registran las historias.
- Conversation: es la que sucede entre todas las personas interesadas e implicadas.
- Confirmation: para asegurar que se han alcanzado los objetivos de la conversación.
También en 2001, el equipo XP de Connextra introdujo un formato de Historia de Usuario que se ha hecho tremendamente popular y que seguramente te sonará:
- Como [Rol]
- Quiero [Requerimiento]
- A fin de [Razón]
Este formato lo puedes encontrar en el libro User Stories Applied: For Agile Software Development de Mike Cohn. El libro tiene ideas interesantes, aunque tengo la sensación de que el tratamiento de las historias de usuario se está complicando en demasía. ¿Por qué digo esto?
Las historias de usuario nacieron como un concepto útil para romper con la tradicional “toma de requisitos” heredada de los procesos de ingeniería física. Beck y otros se dieron cuenta de varios aspectos que caracterizan el desarrollo de software si lo comparamos con otros proyectos de ingeniería.
- El software es maleable y flexible, podemos cambiarlo tantas veces como necesitemos.
- No necesitamos un conocimiento preciso y exhaustivo de sus requerimientos al empezar los proyectos, podemos darnos tiempo para descubrirlos o establecerlos.
- De hecho, ni siquiera los propios clientes, sean internos o externos, tienen claros todos los detalles. Saben lo que quieren, pero no necesariamente como conseguirlo. La conversación es necesaria precisamente para profundizar en esos detalles.
La consecuencia de esto es que podemos empezar a trabajar con una idea general de la necesidad expresada por el cliente: la historia de usuario. Para implementarla, el equipo de desarrollo inicia una conversación con el cliente, a fin de ayudarle a expresar esa necesidad de una forma cada vez más concreta, preferiblemente describiendo qué es lo que espera obtener. Esto último es lo que entendemos como criterios de aceptación.
Cuando consideramos que sabemos lo suficiente podemos empezar a desarrollar el software. Durante el proceso descubriremos más puntos que necesitan aclaraciones, por lo que volveremos a hablar con la cliente. Mejor, si podemos mostrar esto en forma de software funcionando. Precisamente, porque tendrá carencias, la cliente podrá identificarlas y describirlas. Esto inicia un nuevo ciclo de desarrollo, en el que el objetivo es solucionar las limitaciones señaladas.
I de Incertidumbre
Muchas veces hemos escuchado o pronunciado la expresión “esta historia o tarea tiene mucha incertidumbre”. Hablar de incertidumbre es hablar de nuestra falta de conocimiento ante una demanda de desarrollo.
Cuando se nos pide estimar un desarrollo en realidad se nos está pidiendo, indirectamente, valorar el grado de incertidumbre que tenemos y es bastante evidente que cuando menos sepamos de ese asunto, más tendremos. Bien porque no sabemos cuál es el objetivo que se persigue, bien porque no sabemos cómo implementarlo técnicamente. No podemos estimar, porque sencillamente no sabemos qué nos vamos a encontrar.
De hecho, las estimaciones presuponen una especie de conocimiento omnisciente.
Una historia de usuario que no presenta incertidumbre es aquella en la que podemos entender lo que se quiere conseguir y en la que podemos definir una forma de lograrlo. Respecto a lo que se quiere conseguir, indica objetivos claros: qué se quiere que pase, qué se va a ganar haciéndolo, quién va a obtenerlo. Respecto a como lograrlo, indica que sabemos dónde y cómo intervenir y que el código existente está listo para aceptar esa intervención.
Como abordar la incertidumbre
¿Es posible contener o reducir la incertidumbre? Sí, podemos recurrir a una variedad de estrategias y técnicas para mantener la incertidumbre bajo control o reducirla significativamente.
La primera es aumentar nuestro conocimiento y entender qué es lo que realmente se quiere conseguir. Una historia de usuario es el inicio de una conversación. Como equipo de desarrollo necesitamos conversar con la cliente para entender qué es lo que necesita: ¿Qué tiene que pasar? ¿Cómo vamos a saber si ha pasado? ¿Por qué necesita que pase? ¿Quién se beneficia con ello y cuanto?
Imaginemos una historia de usuario que nos pide algo así como “Quiero fidelizar a los clientes de mi servicio”. La incertidumbre viene en parte por la indefinición. ¿Qué significa fidelizar en este contexto? ¿Qué compren más ese servicio? ¿Que se suscriban? ¿Que se suscriban a planes más caros? ¿Que lo usen con más frecuencia?. El deseo es concreto y específico, pero no define la manera de conseguirlo. Luego, no podemos implementarlo al carecer de ese conocimiento.
La incertidumbre suele aumentar con el tamaño de la historia, no tanto porque exista indefinición como por acotar su alcance. “Quiero poder vender mis productos por Internet a todo el mundo”, es una historia de usuario válida, con un deseo muy específico, pero presenta mucha incertidumbre. ¿Qué productos? ¿Quién podría comprarlos? ¿De cuántas consumidoras estamos hablando? ¿Cómo se van a entregar esos productos? ¿Cómo se van a pagar? La incertidumbre viene del hecho de que es necesario hacer muchas cosas y tomar muchas decisiones comerciales y técnicas.
Divide y vencerás
Una forma de abordar la incertidumbre es evitar abarcar toda la historia de usuario. En su lugar, se trataría de determinar una serie de hitos de incertidumbre mínima que, completados uno por uno, nos lleven al objetivo.
Por esa razón es importante aprender a dividir una historia tan grande en trozos que podamos abarcar: ¿es posible dirigirnos a un subconjunto de clientes potenciales? ¿Podemos empezar vendiendo productos para que se recojan en una tienda física? ¿Sería suficiente si limitamos las ventas a un único país? ¿O a una única gama de productos?
Cada uno de estos trozos nos permite despreocuparnos temporalmente de tener que dedicar esfuerzos a desarrollar elementos que pueden ser complejos, pero a la vez nos permiten probar si ciertas hipótesis de negocio son correctas. Desde la premisa más básica: ¿tiene interés el público por nuestros productos o servicios?, hasta detalles más concretos sobre su comportamiento.
J de Jira
Lo sabemos, suena mal hablar de un producto específico en un libro como este. Jira es la herramienta de seguimiento de proyectos más popular del sector, hasta el punto de haberse convertido en uno de esos estándares de facto. Por supuesto hay otras, pero no son tan usadas.
Diversas herramientas de software, librerías, frameworks etc., presumen de ser opinionated. Tienen una agenda: se jactan de tener una opinión fuerte sobre como se deben hacer las cosas y están construidas de manera que nos fuerzan a plegarnos a lo que sus creadoras consideran.
Jira presume de lo contrario. Este tipo de herramientas suele hacerlo. Su objetivo es agradar a cuantos más usuarios sea posible, desde gestores de proyecto a desarrolladores. Pero por esa misma razón, es una herramienta que ha contribuido como ninguna otra a desvirtuar la filosofía de trabajo ágil.
En realidad, no existe ningún software que sea neutral. Incluso el presumir de no tener opiniones fuertes es, en sí misma, una opinión fuerte. Y es que una opinión expresada en forma de herramienta, es siempre una opinión fuerte por aquello que te permite y por lo que no te permite hacer.
Existe un nivel de gestión que desconfía del desarrollo ágil de software. Precisamente, este movimiento nació para esquivar el control y el micro-management, es decir, el tener a alguien detrás de la espalda diciéndote lo que tendrías que estar haciendo. Las herramientas de gestión de proyectos como Jira favorecen devolver ese control a la cadena de mando.
Por supuesto, todo negocio necesita que existan unos circuitos de información que permitan conocer el estado de los proyectos. No hay negocio viable si fuese de otra forma. Y allí donde Agile propone confianza mutua y entrega de valor sostenible, muchos equipos directivos parecen esperar informes de progreso cada día. De nuevo, estas herramientas prometen proporcionar eso.
Sin embargo, a veces parece que la herramienta se haya convertido en un fin en sí misma. ¿Has tenido alguna vez la sensación de pasar más tiempo gestionando tarjetas que desarrollando? ¿Tenéis discusiones en el equipo sobre lo que debería ser una tarea, una subtarea o una historia de usuario?
La flexibilidad de la herramienta en su afán de contentar a todo el mundo, hace que se introduzcan elementos que no están ni siquiera en los frameworks ágiles más regulatorios como Scrum. De hecho, buena parte de la gestión del proyecto ocurre fuera del equipo de desarrollo, en un nivel que está más interesado en las capacidades de reporting y de seguimiento, y que se siente más seguro si existe un proceso.
De hecho, la herramienta tiende a proporcionar demasiados elementos ajenos a una auténtica forma de trabajar ágil. La posibilidad de tener épicas, tareas, subtareas o spikes, tareas subordinadas o enlazadas, puede complicar la priorización, restar visibilidad a ciertas problemáticas, o incluso favorecer malas prácticas como distribuir carga de trabajo de forma descontextualizada.
¿Recordamos el Manifiesto? Individuos sobre procesos.
K de Kanban
Kanban es el framework Agile que probablemente no sabes que estás usando. O bueno, al menos es casi seguro que estarás usando uno de sus artefactos característicos: el tablero Kanban. La metodología nació en Toyota, creada a finales de los años 40 del siglo XX por el ingeniero Taiichi Ōno, como parte de la gestión de stocks. Básicamente, se trataba de sincronizar la producción con la demanda real, dentro del Toyota Production System, del cual también nació Lean Software Development.
Este modelo se ha aplicado como metodología para la gestión de proyectos de desarrollo de software.
En tablero Kanban permite visualizar el estado de un proyecto mediante tarjetas que describen tareas individuales o work items organizadas en un sistema de columnas que muestran su estado. En el modelo más básico los estados son:
- To-do: lo que queremos hacer en algún momento en el futuro.
- Doing: lo que estamos haciendo ahora mismo.
- Done: lo que ya está completado.
Sin embargo, es frecuente que existan más estados en el tablero. Esto depende, en parte, de la resolución con que se quiera examinar el proceso. Por ejemplo, podríamos tener columnas para Testing, para Deployment, etc. Y hemos visto algunos tableros con tantas columnas que resulta difícil entender para qué sirve cada uno.
Estos estados se representan de izquierda a derecha, de modo que cada tarjeta comienza en la columna To-do y se mueve hacia la derecha, a la columna Doing, cuando nos ponemos a trabajar en ella. Una vez terminada, la volvemos a mover hacia la derecha para situarla en la columna Done y, ojalá, poder olvidarnos de ellas.
Un punto muy importante de Kanban es definir límites del trabajo en progreso. En cada columna se pueden poner un máximo de work items simultáneos. El objetivo de esto es favorecer el foco y la asignación de recursos: si un work item está en una columna de Doing quiere decir que se está trabajando en él. Si una columna está llena, los items en las columnas a la izquierda no se pueden mover. Esto sería señal de que quizá necesitamos más recursos para hacer avanzar los items en la columna llena. O, simplemente, que debemos priorizar el trabajo en los items de esa columna.
En cualquier caso, nos está diciendo que tenemos un problema y que debemos hacer algo para abordar esa situación.
Limita tu trabajo en curso para reducir tus obstáculos
Para algunas personas limitar el trabajo en progreso puede parecer contra productivo. Sin embargo, es todo lo contrario, ya que nos ayuda a establecer un flujo sostenible y constante, además de identificar cuellos de botella. Esto conecta el uso de Kanban con la teoría de constraints o limitadores. Esta teoría dice que un equipo que no consigue sus objetivos suele estar limitado por un conjunto reducido de obstáculos. Se trataría, pues, de identificar estos obstáculos y tomar medidas para abordarlo, que se agrupan en tres tipos:
- Exprimir: Centrar todos los esfuerzos en resolver la limitación, añadiendo recursos o personas, y pospón otros work items. Se trata de salir del problema cuanto antes.
- Subordinar: Asegurar que otros procesos puedan contribuir a reducir el cuello de botella.
- Elevar: Hacer cambios en el sistema para eliminar o reducir la limitación.
En muchos equipos que se quedan atascados en un proyecto, nos hemos encontrado con que se quejan de que les falta tiempo o que tienen que atender múltiples focos. Ambas señales apuntan a un problema de gestión del trabajo en curso. Cuando examinamos sus Kanbans lo que vemos son columnas que contienen muchos más work items de los que el equipo puede ocuparse con su capacidad.
Cuando ocurre esto es como 100 personas tratando de pasar por la misma puerta. Cuando lo hacen de una en una, tardan muy poquito tiempo. Pero cuando intentan hacerlo todas la vez, emplearán mucho más tiempo y muy probablemente se harán daño.
L de Lean Software Development
El framework de Lean Software Development es una adaptación del método Lean Manufacturing que, a su vez, se inspira en el Toyota Production System (TPS). Este sistema fue creado en los años 50 del siglo XX, para optimizar el proceso de producción industrial. Si hubiese que resumirlo en unas pocas frases podríamos decir que el TPS consiste en producir lo necesario, consumiendo lo justo y no gastar en lo que no necesitamos. Es una gran simplificación, pero condensa la idea principal, y hay que entenderlo en el contexto de la reconstrucción de Japón tras la Segunda Guerra Mundial.
La adaptación de estas ideas al desarrollo de software vino de la mano de Mary y Tom Poppendieck, concretado en su libro fundacional Lean Software Development: An Agile Toolkit. Este framework se basa en los siguientes principios:
Eliminar el desperdicio. Todo lo que no agregue valor al cliente es desperdicio y debe eliminarse. Esto se traduce, por ejemplo, en no desarrollar nada más que lo que se necesita, evitando buscar anticiparse a un futuro que no conocemos. Por tanto, es necesario aprender a discernir lo que es necesario de lo que no.
Desperdicio, en el ámbito Lean, abarca varias cosas. No desarrollar prestaciones innecesarias, es una de ellas. El trabajo terminado parcialmente es otra, lo que nos llevaría a utilizar diversas prácticas técnicas como adoptar Trunk Based Development, evitando ramas de código que vivan más allá de unas horas; TDD outside-in para añadir solo el código necesario con buena calidad y otras relacionadas.
También es desperdicio cuando un equipo tiene que hacer multitarea y se tiene un nivel de trabajo en progreso alto. Cuando se emprenden tareas de gran incertidumbre, o cuando las historias de usuario se dividen horizontalmente, generando dependencias y esperas.
Calidad desde el inicio. La calidad en el desarrollo del software tiene que estar presente desde el primer momento. No se puede esperar, pues eso genera deuda técnica y, por lo tanto, desperdicio en el futuro.
En ese sentido, los equipos que hacen Lean Software Development, suelen usar las prácticas técnicas ágiles que caracterizan Extreme Programming: TDD, Ensemble programming, Merciless Refactoring, etc.
Crear conocimiento. El desarrollo de software es un proceso de aprendizaje constante, tanto de lo que el cliente necesita como de lo que no necesita. Para ello son fundamentales los ciclos de feedback y una buena comunicación.
Retrasar decisiones: Los equipos tienen que retrasar decisiones en lo posible para mantener flexibilidad y adaptarse a los posibles cambios.
La idea es no empezar el desarrollo pensando en detalles como una tecnología concreta que podríamos llegar a necesitar, sino desarrollando la funcionalidad con el recurso más barato y fácil de cambiar posible, que me comprometa menos. Si llegado el caso, vemos que necesitamos una tecnología específica, siempre podremos adoptarla con la ventaja de tomar una decisión informada.
Para ello es útil definir límites de producto, que serían valores fijos de ciertos parámetros. Se desarrolla una solución sencilla que funcione dentro de esos límites y si llegado un momento se superan o se alcanza un cierto umbral de seguridad, nos planteamos una solución más potente.
Por ejemplo, si tenemos un servicio en que las usuarias suben documentos a un almacenamiento, podríamos poner un límite de tamaño de esos documentos, o de espacio total por usuaria, que nos permitan usar una solución barata que tal vez tenemos fácilmente disponible. Si con el tiempo vemos que se supera ese límite con demasiada frecuencia, es cuando podemos empezar a pensar en una alternativa de más capacidad. En estos casos es bueno definir también un umbral a partir del cual sí tenemos que plantear como mejorar esa prestación.
Entregar rápido: En otros capítulos hemos hablado de la necesidad de hacer entregas de valor frecuentes que hagan posible tener feedback cuanto antes, lo que nos facilita decidir nuestros siguientes pasos.
Para facilitar la entrega rápida se usa el Vertical Slicing, una técnica para decidir las iteraciones de una historia de usuario, de forma que cada una de ellas nos permita entregar valor. Pero también, se añaden prácticas como Trunk Based Development, Ensemble programming, etc., que permite reducir el tiempo de desarrollo, revisión de código y esperas.
Respetar a las personas: Se busca generar un ambiente de respeto y colaboración, independientemente de roles o experiencia, que permita a cada persona del equipo contribuir al éxito y aprender sobre el producto y el propio proceso de desarrollo.
También es necesario que los equipos como tales estén empoderados, o sea, que tengan la capacidad de decidir qué hacen y cómo lo hacen. Para ello, tienen que contar con las capacidades y conocimientos necesarios, lo que evita las dependencias y las esperas, que son una de las formas de desperdicio.
Visión de conjunto: El proceso de desarrollo se ha de considerar en su totalidad. El producto es algo más que la simple suma de las partes.
Lean Software Development, es un framework muy alineado con Extreme Programming, con el que comparte muchas ideas. Aparte del libro original, puedes aprender más en la web de Emilio Ferro
M de Manifiesto Agile
El Manifiesto por el Desarrollo Ágil de Software fue creado en 2001 por un grupo de 17 señores programadores reunidos en un resort de ski en Utah. Representaban diversas metodologías alternativas para el desarrollo de software y su objetivo era tratar de acordar una serie de elementos comunes, a pesar de las diferentes aproximaciones que traían de partida.
A ver: 17 señores programadores en un resort de ski en Utah no es probablemente una muestra demográfica representativa de un mundo diverso y dice mucho acerca de los potenciales sesgos del resultado de la reunión. Aun así, el documento final es un buen instrumento para la reflexión acerca de como trabajamos en el mundo del software y sigue estando vigente.
Introducción
El manifiesto comienza con la siguiente introducción:
Estamos descubriendo formas mejores de desarrollar software tanto por nuestra propia experiencia como ayudando a terceros. A través de este trabajo hemos aprendido a valorar:
Es muy importante acentuar el aspecto de trabajo en progreso expresado por las palabras “Estamos descubriendo formas mejores de desarrollar software”. No es “Hemos diseñado una forma mejor de desarrollar software”. Este punto es crucial, porque el Manifiesto no impone una forma de trabajar, sino que enfatiza que cada equipo debe esforzarse en buscar la forma adecuada para su contexto.
Valores
A continuación se enumeran los cuatro valores del agilismo:
- Individuos e interacciones sobre procesos y herramientas
- Software funcionando sobre documentación extensiva
- Colaboración con el cliente sobre negociación contractual
- Respuesta ante el cambio sobre seguir un plan
Y se hace una aclaración importante:
Esto es, aunque valoramos los elementos de la derecha, valoramos más los de la izquierda.
En otras palabras: el hecho de valorar más unos elementos sobre otros, no implica su negación. Es decir: procesos y herramientas son importantes, pero subordinados a los individuos. Es necesaria la documentación, pero valoramos más la entrega de software funcional. Tiene que haber una negociación de contratos con el cliente, pero en último término es esencial desarrollar una colaboración productiva con él. Y, por último, se necesita un plan y saber qué se quiere conseguir, pero es más importante ser capaz de responder al cambio que seguir ese plan de manera rígida.
Principios
Los valores ágiles generan un conjunto de principios:
Nuestra mayor prioridad es satisfacer al cliente mediante la entrega temprana y continua de software con valor.
Cuando hablamos de entrega de valor, estamos hablando siempre de valor de negocio. Lo que importa no el código, sino la funcionalidad que este habilita para el cliente.
Aceptamos que los requisitos cambien, incluso en etapas tardías del desarrollo. Los procesos Ágiles aprovechan el cambio para proporcionar ventaja competitiva al cliente.
Bajo este principio subyace la idea de que el cambio es necesario para adaptarse al mercado del negocio del cliente. Si el producto no funciona, el producto tiene que cambiar. Si el mercado se mueve en una dirección, el producto debería seguirla.
Entregamos software funcional frecuentemente, entre dos semanas y dos meses, con preferencia al periodo de tiempo más corto posible.
La entrega frecuente es fundamental para que el cliente pueda pivotar de forma eficaz. Cuanto más tiempo tarda el software en estar funcionando, más difícil es entender si va en la dirección correcta o debe cambiar. La mención al tiempo resulta extraña, pero seguramente los autores querían enfatizar la diferencia con proyectos que se demoran años en ser puestos en manos de sus usuarias.
Los responsables de negocio y los desarrolladores trabajamos juntos de forma cotidiana durante todo el proyecto.
Este punto señala la corresponsabilidad de desarrollo y negocio. No es que negocio le diga a desarrollo lo que tiene que hacer y ya. En lugar de eso, es reconocerse como formando parte de un mismo equipo en el que cada participante aporta su conocimiento y experiencia para resolver un problema.
Los proyectos se desarrollan en torno a individuos motivados. Hay que darles el entorno y el apoyo que necesitan, y confiarles la ejecución del trabajo.
El método más eficiente y efectivo de comunicar información al equipo de desarrollo y entre sus miembros es la conversación cara a cara.
El software funcionando es la medida principal de progreso.
Los procesos Ágiles promueven el desarrollo sostenible. Los promotores, desarrolladores y usuarios debemos ser capaces de mantener un ritmo constante de forma indefinida.
La idea de mantener un ritmo constante de forma indefinida puede sonar un poco ominosa. Pero es uno de los principios que se suele interpretar mal. Cuando decimos ritmo constante, no hablamos de velocidad, sino de la capacidad de entregar valor de una manera regular y, hasta cierto punto, predecible.
El equipo de desarrollo no debería luchar contra un sistema difícil de descifrar. El código tiene que expresar claramente las intenciones, los lugares donde extenderlo, etc. Debería ser sencillo, e incluso obvio, identificar qué cambios introducir para añadir valor.
La atención continua a la excelencia técnica y al buen diseño mejora la Agilidad.
Para ser ágiles tenemos que escribir software bien diseñado. Y para escribir software bien diseñado necesitamos dominar toda una serie de técnicas y conocimientos. La verdad es que esto es algo que no siempre es bien entendido. Todas hemos escuchado alguna vez la idea de que no importa empezar con una solución chapucera que se pueda sacar rápidamente y ya tendremos tiempo de arreglarla. Esto no es lo que dice Agile. En su lugar, Agile dice empezar con una solución simple, pero bien hecha.
Los atajos cortos suelen traer retrasos largos. Muchos equipos acaban reescribiendo un mismo producto una o más veces desde cero. Tanto porque la solución anterior estaba mal escrita, como por carecer de habilidades de refactor, testing y diseño de software. Lo que conocemos como prácticas técnicas ágiles.
Reescribir productos desde cero es una táctica arriesgada y cara. Hay que reproducir toda la funcionalidad del sistema original y realizar las migraciones necesarias, lo que puede dar lugar a pérdida de datos, downtime o tiempo sin funcionalidad. En muchísimos casos tener personas capaces de aplicar técnicas de refactoring progresivo hubiese permitido minimizar el riesgo del cambio, sin generar tiempos muertos.
La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial.
Maximizar el trabajo no realizado es un principio extraño, uno que no se capta a la primera tras leer su formulación. Intenta capturar una idea muy potente en una frase ingeniosa y breve. Nosotras podemos entenderla en dos formas principales:
- Optar por las soluciones más simples que puedan funcionar, que suena como una propuesta deseable.
- Evitar tener que realizar la mayor cantidad posible de trabajo, que suena contra la intuición.
Buscar las soluciones más simples posibles que puedan funcionar promueve escribir el software justo y necesario para resolver la demanda que tenemos ahora. Entre otras cosas, supone evitar en lo posible el sobre-diseño. Es decir, nos pide evitar añadir complejidad para abordar cuestiones que podrían llegar en el futuro. El caso es que como no podemos predecir el futuro, es mejor no adelantarse. Si nuestro software necesita añadir complejidad en algún momento, lo haremos cuando sea necesario.
Para ello, además de simple, el software tiene que ser fácil de cambiar. Si bien, no podemos predecir los acontecimientos del futuro, podemos hacer algunas suposiciones razonables sobre el mismo. Por ejemplo, podemos suponer que una tienda on-line querrá ofrecer diversas formas de pago, por lo que es bueno dotar al sistema de cierta flexibilidad para incorporarlos en el futuro con facilidad y seguridad. Sin embargo, los medios de pago requieren negociaciones, análisis de su demanda, suponen costes, etc., para poder usarlos, por lo que es preferible evitar implementaciones concretas de los mismos hasta no tener claro que los necesitamos y que los usaremos.
Por otro lado, no hay mejor trabajo que aquel que no hay que realizar. Esto nos puede llevar a pensar en la necesidad de automatizar cuantos más procesos rutinarios, mejor.
Las mejores arquitecturas, requisitos y diseños emergen de equipos autoorganizados.
Un punto muy importante del manifiesto Agile es que no existe una metodología Agile. Disponemos de diversos frameworks que comparten esta filosofía y establecen unas pautas metodológicas concretas. Pero la forma más genuina de ser Agile es que cada equipo decida cuál es la forma en la que trabaja mejor, que más encaja en su producto y sus personas.
Esto quiere decir que incluso en una misma empresa lo lógico sería que cada equipo de trabajo se autoorganice, sin necesidad de seguir un determinado framework común.
A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación ajustar y perfeccionar su comportamiento en consecuencia.
Esta podría ser la única prescripción concreta que propone el Manifiesto. Esta reflexión es la que solemos denominar retrospectiva y su único objetivo es evaluar y reconducir el proceso que el equipo sigue para ser más eficiente y trabajar mejor.
Las críticas a Agile
Se han publicado muchas críticas al movimiento Agile, algunas de ellas son incluso buenas críticas. Por desgracia, muchas de las que se pueden leer se equivocan en aspectos muy fundamentales. Por ejemplo, son frecuentes las críticas que en realidad se dirigen a alguno de los distintos frameworks, particularmente a Scrum. Y lo curioso es que, en ocasiones esas mismas críticas son compatibles con el Manifiesto Agile. También es cierto que muchas críticas obvian que el Manifiesto habla del desarrollo de software específicamente, no del desarrollo de producto o de negocio.
De hecho, gran parte de la crítica más sólida a Agile viene de las propias agilistas. Por ejemplo, esta cita del Blog de un apostol de Scrum y Kanban:
Otra versión del Manifiesto Ágil revisada que me gusta es la de Alexey Krivitky: “Después de 20 años tratando de entender y explicar el Manifiesto Ágil he llegado a esta versión simplificada que parece entregar el mensaje con menos palabras”.
Personas sobre procesos Producto sobre especulaciones Cocreación sobre política Realidad sobre planeshttps://scrum.menzinsky.com/2019/07/el-manifiesto-agil-deberia-de.html
Es muy interesante porque, siendo totalmente fiel a la intención del Manifiesto, resulta mucho más precisa y accionable que el original.
También podemos ver como una crítica en la línea Agile el Manifiesto por la Artesanía de software, que reza así:
Como aspirantes a Artesanos del Software estamos elevando el listón de desarrollo de software profesional practicando y ayudando a otros a aprender el oficio. A través de este trabajo hemos llegado a valorar:
No solo software que funciona, sino también software bien diseñado No solo responder al cambio, sino también agregar valor constantemente No solo individuos e interacciones, sino también una comunidad de profesionales No solo colaboración de clientes, sino también asociaciones productivasEs decir, en la búsqueda de los elementos de la izquierda, hemos encontrado indispensables los elementos de la derecha.
También podemos ver que completa y extiende la definición de cada uno de los cuatro valores.
El mismísimo Kent Beck propuso en 2011 una revisión del Manifiesto:
Visión y disciplina de equipo, por encima de individuos y su interacción Aprendizaje validado, por encima de software que funciona Descubrimiento con el cliente, por encima de la colaboración con el cliente Iniciar el cambio, por encima de la respuesta al cambiohttps://www.forbes.com/sites/stevedenning/2011/05/04/innovation-applying-inspect-adapt-to-the-agile-manifesto/
Se puede apreciar en todas estas nuevas formulaciones una tendencia: no se trata de negar el Manifiesto, sino de seguir profundizando en la visión ágil del desarrollo de software. Al fin y al cabo, una de las principales ideas de Agile es justamente la autoevaluación contínua, así que tiene mucho sentido que no consideremos el Manifiesto Agile como las tablas de la Ley, escritas en piedra, sino como una filosofía en progreso y definición constante.
N de No Estimar
La estimación sobre el coste de desarrollo de una feature o historia de usuario es uno de los temas que genera más discusiones en nuestro sector.
A la hora de decidir desarrollar una funcionalidad en el software tenemos que sopesar dos dimensiones fundamentales:
- El valor que puede aportar a la usuaria o cliente
- El coste de desarrollo
Estimar la aportación de valor
Siendo sincero, no he visto demasiada literatura acerca de cómo estimar o cuantificar la aportación de valor de una prestación del software. En ese sentido, creo que podríamos estar de acuerdo en algunos parámetros de la misma:
- Aporta una capacidad que antes no existía.
- Reduce el tiempo necesario para ejecutar un proceso de negocio.
- Potencialmente, permite generar una cierta cantidad de ingresos.
- Potencialmente, permite ahorrar una cierta cantidad en gastos.
Digo “potencialmente” en cuanto a la generación de ingresos o al ahorro de gastos porque eso se basa en suposiciones: que las usuarias están interesadas en la prestación, que los clientes pagarán por ella, que incrementará las ventas, etc.
En conclusión, el valor de una prestación también es una estimación que debería basarse en un análisis racional. Algo más elaborado que “el cliente/usuario lo quiere”. Para estas cosas los equipos tienen analistas de negocio y, si me apuras, product owners que entienden ese mercado y sus necesidades.
Estimar el coste de desarrollo
El coste de desarrollo es la otra dimensión a tener en cuenta y también es otra dimensión compleja. En último término todas las unidades de estimación del esfuerzo de desarrollo se basan en una medida de tiempo. La necesidad de estimar surge de la gestión de proyectos tradicional, con sus plazos y fechas de entrega. Se puede argumentar que un negocio viable necesita saber cuándo estará listo un proyecto, a fin de ajustar otros procesos de negocio como marketing, ventas, finanzas, etc.
Es muy difícil valorar cuánto cuesta realizar una tarea de programación. En una cadena de montaje es posible que puedas tener estimaciones bastante precisas de cuanto tiempo requiere realizar una fase e incluso optimizarla. Pero el desarrollo de software tiene otra naturaleza.
Por hacer una analogía. En una cadena de montaje de coches, hay que colocar unas piezas definidas en un chasis que está preparado para ello. Quitando imprevistos como que se hayan agotado las piezas o algún tipo de accidente, es relativamente fácil saber cuánto tiempo se consume en montarlas. En realidad, bastaría con obtener una buena muestra de medidas y calcular un índice de tendencia central, como la media o la mediana, para tener una estimación muy aceptable.
Pero en software… el software no tiene nada que ver. Para empezar puede que ese chasis no exista, o que la pieza que hay que añadir no encaje en el existente, puede que haya que rediseñar esa parte del chasis porque las necesidades han cambiado o puede que no esté preparado para añadir o cambiar esa pieza específica. En software esto ocurre porque cada vez que tenemos que modificar código la situación es diferente.
En resumen: el coste de desarrollo de software incluye un alto grado de incertidumbre.
Reducir el nivel de incertidumbre es el camino a seguir, pero no es fácil. No se puede reducir mediante técnicas de estimación más precisas. El ideal es llegar a dividir la funcionalidad en trozos más pequeños cuya expresión en código no tenga incertidumbre o sea mínima. Aunque entreguen una fracción del valor, se pueden ejecutar en un tiempo reducido.
Si llegamos a este tipo de fraccionamiento, es relativamente fácil predecir hasta donde vamos a llegar en un período de tiempo dado.
Otra forma de estimar el coste de desarrollo es mediante spikes o experimentos de código en los que probamos posibles soluciones de forma rápida y no tan rigurosa como la implementación final. El objetivo es entender lo que hay que hacer y, consecuentemente, hacerse una idea de lo costoso que podría ser.
La relación entre valor y coste
Ron Jeffreys representa el valor como la altura de un rectángulo y el coste como su anchura. De este modo, los rectángulos verticales indicarían una prestación que aporta mucho valor con poco esfuerzo. Por el contrario, los rectángulos horizontales nos estarían diciendo que el coste de desarrollo es muy alto con relación al valor que nos aporta.
Pero también nos dice que la situación óptima es cuando podemos desarrollar prestaciones con bajo coste aunque su aportación de valor sea relativamente baja. ¿Y esto por qué? Porque con ello generamos una entrega de valor contínua y sostenible. Eso sí, el valor debe ser perceptible por la usuaria final.
Esto nos proporciona un criterio relativamente sencillo para tomar decisiones sobre el desarrollo:
- Priorizar la entrega de valor aunque sea en unidades pequeñas pero visibles.
- En lugar de introducir tareas de alto coste, partirlas hasta descomponerlas en entregas de valor pequeñas pero de bajo coste.
Puntos de historia
Estimar es, literalmente, timar. Los puntos de historia para estimar el esfuerzo de una tarea se inventaron justamente para timar a los managers y no darles estimaciones de tiempo. El objetivo era tratar de librar a los equipos de desarrollo de la presión de los plazos de entrega. Obviamente, enseguida se buscó una traducción entre punto de historia y unidad de tiempo, así como diferentes escalas y rangos de puntos. En último término, muchos equipos eliminaron las estimaciones, al haberse convertido en poco más que en una superstición.
¿Es necesario un cierto grado de predictibilidad de la entrega de software? Por supuesto. Pero en lugar de desgastarse adivinando lo que nos costará realizar cualquier historia de usuario o tarea, es mejor aprender a definir entregas de valor lo bastante bien delimitadas como para poder ponerlas en producción en un tiempo predecible y corto.
O de Collective Ownership
La propiedad colectiva del código se refiere a que el código de un proyecto es de todo el equipo. Pertenece a toda persona que haya participado. Y, a la vez, no pertenece a nadie en particular.
Es una idea muy sencilla. El código representa el conocimiento colectivo del equipo sobre el problema que esa aplicación o sistema trata de resolver. El hecho de escribir el código en sí es, en varios sentidos, secundario. En realidad, lo que importa es el conocimiento que se expresa con ese código.
Que la propiedad del código sea colectiva es muy importante. Para empezar, es lo que permite que podamos actuar sobre ese código cuando sea necesario. El desarrollo debe producirse de tal manera que cualquier persona pueda intervenir cuando sea necesario, tanto para añadir una nueva prestación, como para arreglar un error, o para mejorar la estructura y diseño.
Nadie puede actuar como guardiana, o decidir quién tiene derecho a tocar qué. El gatekeeping va contra la productividad.
Esto implica una serie de derechos y deberes.
- El derecho a conocer el código y su funcionalidad: todas las personas que forman parte del equipo tienen derecho a conocer el código y lo que hace, para lo cual es necesario que esté bien organizado y diseñado. Es más prioritario que una documentación extensa, que corre el riesgo de quedar obsoleta muy pronto si no se mantiene sincronizada.
- El derecho a modificarlo: todas las personas que forman parte del equipo tienen derecho a modificarlo a fin de que el código mantenga una buena representación del conocimiento del equipo sobre su parte del negocio. Debería ser obvio que para poder ejercer este derecho es necesario conocerlo.
- El deber de mantener el código en buen estado: si nos limitamos a añadir prestaciones al código o modificarlo para corregir defectos, con el tiempo el código se deteriora. Para evitarlo, hay que mantenerlo activamente en buen estado, revisando su diseño y asegurándonos de que disponemos de puntos de cambio adecuados para hacerlo evolucionar.
- El deber de aceptar los cambios que hagan otras personas del equipo: la propiedad colectiva implica, como hemos señalado, que nadie tiene una autoridad especial para autorizar o no cambios en el código.
Control de cambios
Se podría argumentar que puede resultar peligroso: ¿qué pasa si alguien introduce por su cuenta y riesgo un cambio que destruye datos, introduce errores o modifica el comportamiento de tal forma que no se corresponde con el objetivo de la aplicación?
Aparte de una cuestión de responsabilidad individual, también disponemos de métodos para minimizar el riesgo de que en el código ocurran este tipo de problemas, ya sea por falta de conocimiento ya sea por malicia.
Separar el momento de publicación del software de la mezcla de cambios, introduciendo un paso extra en el que se puede verificar que todo funciona según lo previsto. Diremos que este es el método menos ágil de todos, pero tiene sus casos de uso.
Propuesta de cambios con autorización obligatoria: o sea, nuestras Pull Request (o Merge Request) y Code Review de toda la vida. La idea es que no sea posible mezclar un código sin que otra persona del equipo lo supervise, preferentemente tras haber revisado los cambios y haberse hecho una idea de su impacto. Es otro método muy discutido si queremos hablar de un proceso de desarrollo realmente ágil.
QA: Una buena suite de tests contribuye a hacer más difícil la introducción de cambios no deseados o que alteren el comportamiento del sistema. Cuanto más automatizada mejor, para que no se convierta en un cuello de botella.
Pair programming o mob-programming. La ventaja de estas metodologías es que introducen la revisión de código en el propio proceso de creación. De este modo, la revisión y autorización dejan de paralizar la entrega. Pero además, estas técnicas contribuyen a que se comparta el conocimiento sobre el código, así como la responsabilidad de las decisiones, lo que favorece la disminución de problemas como el bus factor, previniendo la formación de silos.
10x Engineer
De tanto en cuanto se pone de moda el concepto del 10x Engineer. Se trata de un concepto un tanto difuso que se aplicaría a aquellas personas con un rendimiento excepcionalmente alto, gracias a su motivación, conocimiento técnico y dedicación. Es un perfil que levanta polémicas: hay quien lo considera deseable y un ejemplo a seguir, y hay quien encuentra que es un peligro para los equipos, y empresas, que lo permiten.
En el contexto de este capítulo sobre Ownership en un libro que habla de Agilismo, un 10x Engineer (lo habitual es que sea varón, para qué nos vamos a engañar) es una figura que puede ser muy peligrosa.
Es frecuente que tome sus propias decisiones al respecto de la organización del código o de las tecnologías de las que depende. Así que, de un día para otro, las otras personas del equipo se pueden encontrar con cambios significativos del código a los que deben adaptarse.
Suele ocuparse de más de una tarea al mismo tiempo, lo que incrementa el trabajo en curso del equipo y puede generar bloqueos o retrasos en las entregas.
Tiende a trabajar solo y, con frecuencia, en horario no laboral, con lo que no contribuye a la distribución del conocimiento dentro del equipo. No da oportunidades a las técnicas de programación grupal (pair o mob) entre otras cosas porque considera que ralentizan su ritmo de trabajo.
Por otro lado, suele acumular mucho conocimiento del sistema, pero al no distribuirlo genera un silo, lo que a su vez provoca un bus factor muy acusado. Con el tiempo, el equipo se vuelve totalmente dependiente. Esta persona ejerce un liderazgo técnico, que puede ser implícito o reconocido con un rol de Tech Lead o similar, pero que está sustentado en la dependencia.
Uno de los problemas que derivan de tener un 10x Engineer en un equipo es la frustración que genera en otras personas, a las que reduce sus oportunidades: no ayuda a crecer a las que son junior, no deja espacio para que otros seniors puedan participar en temas relevantes y liderar en sus áreas de experiencia. En poco tiempo, estas personas están buscando oportunidades en otro equipo, si es posible, o en otra compañía en el peor de los casos.
Este tipo de perfiles resultan ser relativamente valiosos para la empresa en el corto plazo, porque en términos de producción hacen que las cosas salgan. Pero en el largo plazo, encierran una trampa que puede ser mortal. El 10x Engineer es valioso… mientras siga en la empresa. Si se marcha, puede dar lugar a una crisis importante. Pero quedándose, puede ser bloqueante para incorporar talento.
Una de las razones por las que el concepto de Collective Ownership es tan importante, es precisamente para prevenir este tipo de situaciones. Un equipo debe ser mejor que la suma de sus miembros, para lo cual todas las integrantes tienen que poder contribuir desde sus capacidades y desarrollarse. En un equipo en el que existe la figura del 10x Engineer, no existe Collective Ownership, pues todo el ownership posible pasa por esa persona concreta. No hace falta que tenga un rol específico, sino que la dinámica de trabajo lo refuerce.
En un equipo sano se busca una eficiencia en la entrega de valor que sea sostenible en el tiempo, no dependiendo de circunstancias particulares, o de que personas concretas estén presentes o ausentes.
P de Prácticas Técnicas
Las prácticas técnicas ágiles son una de las grandes olvidadas en los equipos de tecnología. “¿Y qué es eso?”, preguntarán muchas personas.
Las prácticas técnicas ágiles son un conjunto de destrezas y procedimientos que se aplican en el proceso de desarrollo de software y cuyo objetivo es mejorarlo en todas sus fases. Hay que tener en cuenta que en los equipos de desarrollo ágiles, las fases de diseño, especificación, implementación, pruebas y mantenimiento, se condensan en un espacio de tiempo y en un ámbito muy delimitado del proyecto: la historia de usuario, e incluso se pueden superponer en el tiempo.
Las prácticas técnicas nos permiten realizar una aproximación intencionada y metódica al desarrollo de software. La programación se percibe a veces como el producto de una especie de inspiración y, sin embargo, es necesario cultivar una serie de técnicas mediante las cuales escribir software de una forma eficiente.
Pedro Moreira Santos, Marco Consolaro y Alessandro Di Gioia, en su libro Agile Technical Practices Distilled, señalan cuatro prácticas técnicas fundamentales: TDD, pair programming, refactoring y diseño simple.
Pair programming
Pair programming es la práctica de trabajar dos personas (o más si se trata de mob-programming) con el objetivo de obtener software de calidad gracias al feedback inmediato. Al trabajar con otra persona esta nos puede ayudar a identificar problemas potenciales, ofrecernos aproximaciones alternativas, discutir y refinar conceptos, etc. Un beneficio extra de pair programming es que contribuye a que el conocimiento se distribuya de forma fluida entre los miembros del equipo.
En pair programming cada persona adopta un rol:
- Driver: es la persona que escribe el código en un momento dado.
- Navigator: responsable de revisar el código desde un punto de vista estratégico.
Existen varios formatos de trabajo en pair programming y técnicas para repartir los roles en una misma sesión.
- Chess clock: los roles se intercambian en un tiempo prefijado, o bien si hay una pausa natural en el proceso. Para eso puede ayudar la técnica Pomodoro.
- Ping-pong (combinada con TDD): una persona escribe un test que falle y pasa el rol de driver a la otra. Esta escribe el código para pasar el test y un nuevo test que falle, pasando de nuevo el driver.
- Strong-style: la persona que hace de driver tiene que confiar en lo que le indica la que hace de navigator. Puede hacer preguntas para aclarar lo que quiere hacer, pero el debate acerca de por qué debe suceder al final.
Las sesiones de pair programming pueden ser bastante fatigosas por lo que es importante utilizar herramientas para delimitar el tiempo y tener descansos. Para ello, la técnica Pomodoro puede ser muy útil.
Mob programming es un concepto similar, pero en lugar de ser dos personas, puede participar todo el equipo. Incluso personas externas si puede resultar útil. Las personas pueden entrar y salir de la sesión de mob programming libremente y contribuir a la discusión, mientras que alguien se encarga de escribir el código.
Test Driven Development
Test Driven Development (TDD) es una práctica técnica en la que definimos las especificaciones de un software mediante tests creados a partir de ejemplos del comportamiento deseado. El código de producción se escribe con el objetivo de hacer pasar esos tests.
Para empezar, escribimos una lista de todos los elementos de funcionalidad que queremos conseguir. Esta lista no es definitiva, pues podríamos darnos cuenta tanto de nuevas necesidades durante el desarrollo, como descubrir que algunas no las necesitamos, o al menos no como las habíamos definido.
Sin embargo, TDD no es escribir previamente la totalidad de especificaciones en forma de tests, sino que procedemos una por una. Es decir, escogemos un elemento de la lista, y escribimos un test que sea un ejemplo del mismo. A continuación, escribimos el código de producción justo y necesario para hacer pasar ese test.
Una vez conseguido, añadimos un nuevo ejemplo en forma de test que falle. Es decir, que el código de producción actual no sea capaz de hacerlo pasar. Cuando tenemos este test y vemos que falla por la razón adecuada, añadimos el código necesario para que este segundo test pase, a la vez que pasa el anterior también.
Una vez que hemos hecho pasar el último test, podemos revisar el código de producción para ver si es posible organizarlo mejor. Por ejemplo, identificando alguna regularidad del código que nos permita generalizar. Si es así, realizamos el cambio. Si no, pasamos al siguiente elemento de la lista, o introducimos un nuevo ejemplo para completar el que estemos trabajando.
Cada vez que introducimos código de producción para hacer pasar un test, debemos evitar que los tests anteriores fallen. De este modo, nos aseguramos de mantener la funcionalidad que ya hubiésemos conseguido implementar.
Cuando tenemos todos los tests pasando, podemos aplicar técnicas de refactoring a fin de mejorar la organización o diseño del código de producción.
Es importante no confundir Test Driven Development con Test de Quality Assurance. Ambas disciplinas usan las mismas herramientas, pero sus objetivos son diferentes. Sin embargo, el software escrito con TDD aporta varias cosas. Entre ellas:
- Una batería de tests de regresión, que será útil en QA, aunque no todos los test de TDD son significativos para QA.
- Un diseño de software más fácil de poner bajo tests.
Refactoring
Refactoring es un término muy abusado, que se aplica a cualquier proceso en el que cambiamos o reescribimos software. Pero en el ámbito de las prácticas técnicas ágiles, refactoring es un conjunto de técnicas que nos permite transformar el diseño de un código sin afectar a su comportamiento. El refactoring contribuye al buen diseño, el cual, a su vez, favorece la sostenibilidad a largo plazo del software y reduce el coste del cambio futuro.
Las técnicas de refactoring nos permiten cambiar un código sin interrumpir su funcionamiento ni detener su desarrollo. Una forma de asegurar esto, es tener tests que cubran la parte de código modificado. Un refactoring correctamente aplicado no hará fallar los tests en ningún momento.
De hecho, los mejores entornos de desarrollo incluyen numerosas herramientas que automatizan algunas de las técnicas específicas. Esto garantiza que los cambios sean inocuos y no afectan al comportamiento de tal modo que ni siquiera necesitaríamos verificarlo con tests. A este tipo de refactors se les suele llamar provable refactors, porque se ha verificado que aplicados correctamente no alteran la funcionalidad del software.
Los refactors son los cambios específicos que podemos aplicar. Pueden ser tan simples como cambiar el nombre de un símbolo en el código, como una variable o una función; o tan complejos como convertir una estructura condicional en un conjunto de objetos polimórficos.
Para aplicar refactor es importante aprender a identificar señales en el código que nos indiquen un problema potencial de diseño. A estas señales las denominamos code smells. Los code smells no son errores, pues el software no funciona mal, sino patrones de código que nos indicarían que algo podría tener un mejor diseño o que, llegado el momento, podría ser costoso entenderlo o cambiarlo.
Asi, por ejemplo, si tenemos dos variables que siempre van juntas (se pasan juntas a funciones, se asignan a la vez, se actualizan o recalculan a la vez, etc.) tenemos un smell llamado Data Clump y lo que este nos dice es que probablemente esas variables representan un único concepto, que estaría mejor reflejado en forma de objeto o de otra estructura de datos adecuada al lenguaje de programación.
Diseño simple
Las prácticas técnicas anteriores no sirven de mucho si no entendemos el diseño, en particular, lo que hace que un diseño sea simple. Kent Beck definió las siguientes reglas para ello. El código simple:
- Pasa sus tests: hace lo que dice.
- Minimiza la duplicación: define una fuente de verdad para cada pieza de funcionalidad.
- Maximiza la claridad: dice lo que hace.
- Usa la menor cantidad de elementos posibles: reduce la complejidad accidental.
Calistenia
La calistenia es una serie de reglas que cumplir cuando diseñamos software. En líneas generales, estas reglas nos indican ciertos patrones que debemos aplicar y son totalmente independientes de la finalidad del código.
Por ejemplo: mantener un solo nivel de indentación en cada bloque de código es una regla que podemos detectar fácilmente cuando la incumplimos. Para aplicarla, normalmente lo que haremos será extraer los fragmentos de código más internos a métodos o funciones con nombres descriptivos. Se generan varios beneficios:
- Cada uno de esos métodos o funciones será muy simple.
- Los distintos niveles de abstracción del código quedarán bien identificados y aislados.
- Será más fácil entender qué hace el código, pudiendo leerlo de forma general o descendiendo a los detalles si fuese necesario.
- Incluso podríamos identificar partes del código duplicadas o que podrían extraerse a otros objetos.
Podemos aplicar las reglas de calistenia en ejercicios de práctica deliberada a fin de educar nuestro sentido del diseño o bien intentar refactorizar nuestro código de producción con ellas como objetivo.
Acoplamiento vs. Cohesión
Connascence
El término Connascence intenta unificar las ideas de acoplamiento y cohesión de una forma más sistemática. Se dice que dos o más elementos de un sistema de software son connascentes si el cambio de un elemento conlleva el cambio de otros. Tiene tres dimensiones:
- Grado: es la cantidad de elementos que tienen que cambiar simultáneamente, cuanto más reducido más aceptable.
- Localidad: es la cercanía entre los elementos que cambian. Así, por ejemplo, sería aceptable si los elementos cambian el ámbito de una función, pero no si cambian entre distintas entidades.
- Fuerza: se refiere a la probabilidad de necesitar cambios en los elementos connascentes y el esfuerzo que supone.
Patrones
Los patrones de diseño describen problemas comunes del desarrollo de software junto con soluciones probadas. Por supuesto, aquí hay que citar el libro fundacional de The Gang of Four.
Es muy importante tener presente que un patrón de diseño no es una receta para aplicar ciegamente. El patrón tiene dos elementos y no tiene sentido que tengamos en cuenta uno solo de ellos.
El primer elemento es el problema. Un patrón de diseño describe un problema común que puede presentarse en cualquier proyecto de software. Por ejemplo: cómo añadir un número indefinido de funcionalidades a un objeto en tiempo de ejecución.
El segundo elemento es una propuesta de solución de ese problema que ha sido probada. Así, para el ejemplo anterior, una solución es envolver el objeto en otro (u otros) que implemente la misma interfaz, interceptando y modificando (decorando) su output. Este par concreto de problema y solución es conocido como Decorador.
La implementación que se describe en el patrón no es una receta, sino una guía. Esta implementación puede depender del lenguaje en que estemos trabajando y de la complejidad del propio problema.
Se han identificado infinidad de patrones, que se pueden clasificar en:
- De creación: nos ayudan a resolver problemas en la creación de objetos.
- Comportamentales: nos ayudan a resolver problemas en la comunicación entre objetos.
- Estructurales: reducen la complejidad del diseño de objetos mediante la composición.
Principios
Los principios de diseño de software son guías para tomar decisiones. No son normas escritas en piedra, pero tampoco son ocurrencias. La idea es que los tomemos en consideración para valorar si un software está bien escrito y es sostenible en el tiempo. Por lo general, si seguimos principios de diseño, el código tenderá a ser fácil de entender y de mantener.
Los principios pueden ayudarnos a decidir donde poner ciertas estructuras y comportamientos en su sistema de software. Esto es lo que nos proporcionan los llamados Principios o Patrones GRASP.
Los principios SOLID, por otro lado, están orientados a ayudarnos a diseñar software con bajo acoplamiento.
Pero existen muchos otros.
En ocasiones, podemos sentir que algunos principios se oponen o entorpecen a otros, por así decir. Como decíamos antes, los principios de diseño son criterios para tomar decisiones, no son leyes. En ocasiones, nos convendrá darle más peso a unos que otros. El diseño consiste en decidir qué compromisos estamos dispuestas a aceptar.
Q de Quality Assurance
El modelo agilista cuestiona la gestión de proyectos basada en etapas separadas como el modelo en cascada o waterfall. En este tipo de metodologías, por lo general, las fases deben transcurrir en su totalidad de forma secuencial y separada. Típicamente, estas fases son:
- Toma de requerimientos
- Diseño
- Implementación
- Pruebas
- Mantenimiento
La fase de pruebas es la que solemos asociar a Quality Assurance y al personal dedicado a testing. Pero esto es una simplificación. Sin embargo, ilustra un problema que es frecuente en el mundo de desarrollo de software: el peligro de los compartimentos estancos entre distintas especialidades en el proyecto.
El cambio que proponen los frameworks ágiles al respecto de estas fases las resitúa. El proyecto se considera un trabajo iterativo e incremental, donde cada incremento de valor se completa integrando todas las fases entre ellas, pero sobre un ámbito muy pequeño. Existe toma de requisitos, pero se prefiere expresarla mediante tests. Existe una fase de diseño, que se ejecuta antes y durante el desarrollo. Por supuesto, existe la fase de implementación. Y la de mantenimiento es permanente durante la vida del proyecto. ¿Y las pruebas? Por supuesto, también están presentes, pero no queremos que exista una fase que detenga la entrega de valor.
Por esa razón, en muchos equipos ágiles no existe o se ha redefinido la figura de Tester o QA. No siempre para bien.
Como hemos mencionado en otros momentos, un equipo ágil debe ser autónomo en el sentido de poseer todas las capacidades necesarias para realizar su trabajo. Eso incluye la Quality Assurance, o sea, asegurarse de que está construyendo correctamente el producto correcto. Y como otras capacidades, no implica necesariamente que existe la figura especialista que hace un trabajo separado del resto del equipo.
En cualquier caso, la calidad debería estar presente desde el inicio de todo el proceso, incluyendo el diseño. Dado que vamos a construir este producto de esta manera… ¿Cómo vamos a saber que lo estamos haciendo bien?
Si bien las desarrolladoras del equipo deben saber escribir tests, puede que necesiten ayuda para escribir buenos tests y que sean los adecuados. Dicho esto, QA no es solo poner tests en un proyecto de código. Ni mucho menos. Y esto es algo que muchos equipos nos han entendido bien.
Para empezar, la calidad se refiere globalmente al producto y no únicamente al software que lo hace posible. Hay muchas empresas que hacen software y limitan el equipo de QA solo a ese ámbito, pero no entienden la calidad de forma holística. Que el software funcione bien es importante y disponer de un plan de testing para verificarlo, también, pero no sirve de nada si el producto es una porquería.
Ciñéndonos solo a la parte de software, desde el punto de vista ágil, deben quedar claro dos puntos:
- Agilidad no es lanzar software de mala calidad para probar ideas de negocio, con la esperanza de arreglarlo en el futuro. En realidad, agilidad es construir productos de software de alta calidad que nacen simples (con pocas prestaciones, dirigidos a un público definido) y crecen en complejidad a medida que las hipótesis de negocio se confirman.
- El proceso de Quality Assurance no debe interponerse en la capacidad de entregar valor, por lo que es necesario integrarlo en todo el desarrollo: desde el diseño a la implementación. Pero eso no es sinónimo de añadir tests al código para pasar un pipeline, sino integrar prácticas técnicas que nos ayudan a escribir software de calidad.
Todo esto nos debe llevar a una reflexión sobre si los equipos de desarrollo lo estamos haciendo realmente bien.
Por otro lado, en los últimos años se han ido imponiendo, con mayor o menor fortuna, arquitecturas basadas en micro-servicios que se comunican mediante API y eventos. Esto ha incrementado la dificultad de garantizar la calidad global de nuestros productos y servicios de software.
Así, diseñar sistema de calidad que permitan entender si nuestro sistema funciona como es debido se ha vuelto una tarea que excede las capacidades de los equipos. Incluso si los equipos están bien dimensionados para gestionar los micro-servicios que les corresponden, cosa que no ocurre siempre, pierden la visión de conjunto necesaria para saber como asegurar la calidad del sistema completa.
Y aquí también tenemos una oportunidad para la especialidad de QA.
R de Retrospectiva
Hemos dedicado un capítulo de este libro a los ciclos de feedback y cómo son un elemento fundamental en cualquier práctica ágil que se precie. En general, esos ciclos de feedback se refieren a si estamos construyendo el producto que queremos o debemos construir. Los ciclos se basan en el propósito de lograr una entrega de valor contínua y sostenible, que nos lleva a plantear un estilo de desarrollo iterativo e incremental.
Además de eso, el Manifiesto Agile recomienda lo siguiente:
A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación ajustar y perfeccionar su comportamiento en consecuencia.
Esta reflexión es lo que algunos frameworks establecen como Retrospectiva, que es un término de Scrum para denominar una ceremonia que tiene justamente ese objetivo.
La Retrospectiva, por tanto, sería la actividad en la que el equipo analiza la forma en la que ha trabajado a fin de detectar áreas de mejora y lograr mayor eficiencia en el futuro. Esto se hace de forma periódica. En Scrum se hace al final del sprint.
¿Y qué se puede hacer en una retrospectiva? Como acabamos de decir, lo que querríamos obtener de una retrospectiva es un conjunto de propuestas accionables que nos puedan permitir mejorar nuestra capacidad de entrega sostenible de valor.
Como es fácil adivinar, esto tiene mucho que ver con identificar los limitadores que estén impidiendo alcanzar el ritmo de entrega deseable, algo de lo que hablamos en el capítulo dedicado al WIP o trabajo en progreso.
Métricas DORA y retrospectivas
Una forma bastante objetiva de abordar esto es mediante las métricas DORA:
Frecuencia de implementación (Deployment Frequency). Se trataría de la cantidad de veces que desplegamos a producción por unidad de tiempo. Los equipos de mayor rendimiento pueden llegar a desplegar varias veces al día, y la frecuencia baja hasta aquellos que lo hacen una vez cada varios meses.
Esto tiene dos implicaciones importantes. Para incrementar la frecuencia de implementación es necesario reducir el tamaño de las entregas, lo que contribuye a reducir el riesgo de introducir errores y facilita el resolverlos cuanto antes. También es más fácil que tales entregas estén bien testeadas. Por otro lado, esta capacidad habilita al equipo para desplegar a demanda, en cualquier momento en que tenga sentido hacerlo.
Un ejercicio interesante en una retrospectiva sería entender por qué se hacen entregas poco frecuentes y muy grandes y cómo podríamos mejorarlo.
Plazo de ejecución para cambios (Lead Time For Changes). Es el tiempo que tarda un commit con cambios en llegar a producción. Si tienes un proceso de pull/merge request con revisión de código, este tiempo puede llegar a ser de horas o días, a lo que habrá que sumar el tiempo de despliegue.
Por tanto, los esfuerzos para mejorar esta métrica pueden conducir a varias acciones:
- Automatizar la revisión de calidad de código en todo lo que se pueda: linters, análisis estáticos, buena suite de tests, etc.
- Reducir el tiempo de espera entre que se hace el commit y es revisado, algo que se puede facilitar si las entregas de código son pequeñas y acotadas, de manera que revisarlas sea trivial.
- Reemplazar la revisión asíncrona de código por metodologías de pair o mob programming, que nos permitan eliminar de facto el tiempo de espera por la aprobación de los cambios, sin comprometer la calidad del código.
- Aparte de eso, trabajar para optimizar el pipeline de despliegue es otra mejora que puede ayudar.
Tasa de fallos de cambio (Change Failure Rate). Esta métrica nos habla de las entregas que necesitan ser corregidas tras el despliegue, bien porque se han introducido errores, bien porque han fallado cosas inesperadamente, etc. Lo ideal sería poder desplegar algo y olvidarnos de ello, pero el mundo no funciona así, por lo que una tasa inferior al 15% se considera muy buena.
Obviamente, es una tasa que nos interesa tener lo más baja posible, pero es importante entender qué cosas hacen que se eleve.
- Si es nuestro código el que introduce errores, es posible que no tengamos una buena suite de tests, o que no estemos entendiendo el problema que se nos ha pedido resolver.
- Si es la infraestructura la que falla, ¿la tenemos bien dimensionada? ¿Nuestro código está bien optimizado o estamos introduciendo problemas técnicos inadvertidamente?
Tiempo medio de restauración (o MTTR Mean Time To Restore). Este es el tiempo que se tarda entre detectar un fallo y poner el sistema otra vez en funcionamiento, que en los mejores equipos sería de menos de una hora.
En general, consideramos esta métrica mirando el tiempo que tardamos en ejecutar un rollback, o sea, la restauración del sistema a una versión anterior que sí funcionase. Para esto se pueden utilizar varios sistemas. Uno de los más simples es desplegar esa versión anterior. Un poco más sofisticados, pero realmente rápidos, son aquellos que nos permiten hacer que el sistema apunte a la versión deseada que sigue disponible.
Para poder optimizar el tiempo de restauración, es necesario tomar algunas medidas facilitadoras. Para empezar, implementar sistemas en los pipelines de despliegue que aborten en el caso de que fallen los tests. Si desplegamos cambios en bases de datos, es importante hacerlo de forma que no se rompa inesperadamente. Por ejemplo, si introduces una columna nueva para reemplazar el uso de otra, no elimines esta última en el mismo despliegue hasta tener la seguridad de que funciona.
Utilizar herramientas de feature flags nos permite desplegar código y activarlo o desactivarlo rápidamente si detectamos que funciona mal. En ese caso, podemos mantener el código antiguo hasta tener la seguridad de que ya no se está usando. En general, trabajar como si estuviésemos haciendo Trunk Based Development nos puede ayudar a reducir riesgos en los despliegues.
S de Scrum
Creado por Ken Schwaber y Jeff Sutherland en los años 90, Scrum se ha convertido en un framework tan extendido que la mayoría de la gente lo identifica erróneamente con Agile. Tanto Schawber como Sutherland son firmantes originales del Manifiesto Ágil, que es de 2001. Es importante tener en mente lo que hemos mencionado en el capítulo dedicado a Agile: Scrum es una más de las propuestas metodológicas de desarrollo de software cuyos proponentes buscaron un punto de encuentro en el Manifiesto. Es importante entender que Scrum no nace de Agile.
Scrum está codificado en una Guía, cuya primera versión data de 2010. Y es importante señalar esa codificación, porque los propios autores mencionan que si no la sigues de pe a pa, no estás haciendo Scrum y si no funciona, no es su culpa:
La Guía Scrum contiene la definición de Scrum. Cada elemento del marco sirve a un propósito específico que es esencial para el valor global y los resultados realizados con Scrum. Cambiar el diseño o las ideas básicas de Scrum, dejar fuera los elementos, o no seguir las reglas de Scrum, cubre los problemas y limita los beneficios de Scrum, potencialmente incluso haciéndolo inútil.
Así que cuando te digan “aquí hacemos Scrum a nuestro modo”, la realidad es que no se está haciendo Scrum. Es otra cosa que se le parece.
Y, ojo, no estoy diciendo que eso esté mal. De hecho, Agile dice que cada equipo debe buscar la forma de trabajar que mejor le vaya. Así que si a un equipo le funciona para tener una entrega de valor constante y sostenible, miel sobre hojuelas.
Pero, ¿qué es Scrum?
Scrum es un framework, o sea, la codificación de ciertas prácticas metodológicas que, realizadas de forma sistemática, deberían conducir a una entrega sostenida de valor en equipos de desarrollo de software. Esta codificación se concreta en la Guía Oficial de Scrum, que es su única referencia válida.
Scrum es una metodología relativamente simple y diría que bien aplicada puede ser una buena forma de que un equipo que no sabe trabajar ágilmente pueda empezar a aprender. Con el tiempo, un equipo genuinamente ágil probablemente abandonará Scrum porque puede llegar un punto en que la metodología suponga un freno.
Scrum a grandes rasgos
No hay nada mejor que leerse la guía de scrum para entender cómo funciona. Así que aquí vamos a centrarnos solo en sus elementos más característicos y muy a grandes rasgos. La guía de Scrum (edición de 2020) tiene tan solo 17 páginas.
Equipo
El equipo de desarrollo Scrum está formado por Scrum Master (SM), Propietaria de Producto (Product Owner o PO) y desarrolladoras. Se trata de un equipo multifuncional, o sea: tiene todas las habilidades necesarias para crear valor. Y es autogestionado, por lo que toma sus propias decisiones. La recomendación es que el equipo sea pequeño: no más de 10 personas.
Si los equipos son demasiado grandes, deberán reorganizarse como equipos más pequeños, compartiendo el mismo objetivo de producto y Propietaria de Producto.
Roles
Desarrolladoras: la función de las desarrolladoras es construir el incremento de valor del producto, para lo cual deben crear un plan, llamado Backlog de Sprint, trabajar con calidad y adaptar el plan diario.
Propietaria de Producto o Product Owner: su tarea básicamente consiste en maximizar el valor del producto resultante, para lo cual gestiona el Backlog, partiendo de las peticiones y necesidades de todas las partes interesadas en el producto (stakeholders). El Backlog es el registro del trabajo pendiente, de las cosas que habría que hacer para que el producto aporte valor. Contrariamente a lo que se ve en algunos equipos, el rol de PR no implica dirigir el equipo o decidir lo que hay que hacer. La figura tiene sentido en tanto y cuanto no es posible tener a la cliente o usuaria real en conversación con el equipo. Una buena Product Owner puede ser un gran recurso a la hora de entender qué es lo más valioso que el equipo debería estar haciendo, algo que sí aporta a un equipo ágil.
Scrum Master: su tarea es velar por el proceso Scrum, ayudando tanto a desarrolladoras, como propietaria del producto y stakeholders. Es un rol muy poco comprendida, en gran parte porque no se sigue Scrum por la guía.
La crítica a Scrum
Muchos proponentes de Agile reniegan de Scrum, no sin buenos motivos. Esto ocurre por varias razones, pero quizá las más importantes sean:
- El énfasis en el proceso, mientras que Agile pone las personas por encima de los procesos. Lo que dice Agile es que cada equipo debe buscar, constantemente, su propio forma de trabajar.
- Ha sido secuestrado por el management como forma de control del trabajo de los equipos de desarrollo.
- Las certificaciones han prostituido la naturaleza ágil de Scrum.
- Se han confundido roles, tales como el de product owner o el de scrum master, con puestos. La necesidad de dotar de sentido a estos puestos, ha creado nuevas capas de management intermedio y burocracia… Justo lo que Agile trataba de evitar.
U de Usuaria
Todo software tiene al menos una usuaria a la que servir. Por tanto, diseñamos y construimos software para servir a esas usuarias, pero no solo para ellas. No siempre coinciden las figuras de usuarias y clientes, aunque es frecuente utilizarlas de forma indistinta. Simplificando mucho, diríamos que cliente es quien paga por nuestro producto o servicio. A veces, cliente y usuaria son las mismas personas, a veces son diferentes.
Así, por ejemplo, hay ocasiones en las que la persona usuaria de nuestro software no es nuestra cliente. Imagina que la aplicación en la que trabajas es usada por el departamento de atención telefónica de la empresa. O bien nuestro cliente puede ser una compañía, y las usuarias son sus empleadas. O, por descontado, puede que nuestro producto sea utilizado por nuestras clientes directamente. Se pueden dar muchas combinaciones.
Pero en realidad, en todos estos casos, hay más grupos que son clientes de nuestro equipo en mayor o menor grado. En ocasiones abarcamos todos estos grupos con el término stakeholders, palabra que viene a denominar a toda persona que tiene algún interés en nuestro producto y que puede tener algo que decir sobre él, lo que nos incluye. Claro que cada una de ellas tiene un interés diferente que se manifiesta en distinto grado.
Este es un aspecto que, a veces, se olvida. Es decir, el equipo de desarrollo tiene que atender distintas demandas que no siempre están perfectamente alineadas.
Las usuarias del producto estarán especialmente interesadas en que funcione bien, que sea fácil de entender y utilizar, que les permita realizar sus objetivos con la mayor eficacia posible. Son las que van a lidiar con ese diseño de interfaz, o con el tiempo que tarda en ejecutarse alguna acción, o con un defecto que genera resultados inadecuados.
Si clientes y usuarias no son las mismas personas entran otras consideraciones en juego. La decisión de optar por nuestro producto la realizan personas diferentes a las que lo van a utilizar, con otras prioridades. Las clientes pueden estar más preocupadas por el precio, la posibilidad de recibir soporte o la política de actualizaciones. ¿Y si son distintos clientes con distintas demandas?
Además de clientes y usuarias como destinatarias del software, tenemos que atender intereses internos a nuestra empresa. Si desde el punto de vista del agilismo lo que buscamos es una entrega de valor sostenible, podemos encontramos con limitaciones derivadas de los intereses y estrategias de la empresa. Creo que nos hacemos una idea de la complejidad que esto supone, no tanto de implementación, como de toma de decisiones: la forma en que introduzcamos una prestación beneficiosa para las usuarias puede depender de la forma en que la explotaremos comercialmente.
Atendiendo a la arquitectura de nuestros sistemas, también podemos tener que dar soporte a clientes internos por razones más técnicas. En entornos de micro servicios, es frecuente que un equipo deje de ostentar el ownership completo de un producto, siendo responsable de una parte exponiendo servicios a otras, o bien consumiendo.
Todo esto conlleva una complejidad en la toma de decisiones. Debemos atender muchos intereses diversos, no necesariamente contrapuestos, para lo cual tendremos que saber encontrar un equilibrio. Esto supone, como desarrolladoras, aspirar a tener una visión de conjunto. No podemos limitarnos al contexto reducido de nuestro producto o equipo, sino entender muy bien su rol y posición dentro de la estrategia general del negocio.
Como recalcamos en otras partes de este libro: como desarrolladoras, la parte técnica es solo un elemento más de nuestro trabajo, que debemos poner al servicio de todas nuestras clientes.
V de Rebanado Vertical
En la ingeniería física es frecuente que un sistema se divida en subsistemas o componentes y que cada uno de ellos sea construído de forma separada. Cuando todos los elementos están disponibles, se ensambla el sistema completo. Por esa razón, es muy importante establecer unas especificaciones muy precisas y esforzarse en cumplirlas. En caso contrario, se producirán problemas, que pueden ser muy graves y difíciles de solucionar.
El objetivo, por supuesto, es optimizar y aprovechar las ventajas de la especialización y de la estandarización. La especialización permite que los fabricantes de un componente aprovechen su conocimiento y experiencia, ahorrando tiempo de aprendizaje y diseño. La estandarización, por otro lado, facilita que se puedan recurrir a distintos proveedores del mismo tipo de componente y que puedan inter-operar.
Este modelo se aplica con cierta asiduidad en ingeniería de software y plantea compromisos y desafíos.
Así, por ejemplo, en un proyecto de software podemos identificar especialidades como Frontend, Mobile, Desktop, Backend, Bases de Datos, Data, y Sistemas o Infraestructura. A cada una de ellas le asignamos responsabilidades y personal diferente.
Por esa razón, en las metodologías ágiles se suele insistir en la idea de que un equipo debe configurarse de modo que posea todas las capacidades necesarias para desarrollar su producto o proyecto. De ahí que un equipo ágil normalmente incluya una representación de todas estas especialidades… O al menos de algunas, ya que es cierto que algunos perfiles se comparten entre equipos, como puede ser Sistemas o Data, por poner un ejemplo.
Posiblemente, esto último ocurre porque se trata de aspectos del proyecto que cambian con poca frecuencia. Son importantes a la hora de ponerlo en marcha, pero no necesitamos cambiar cosas constantemente como ocurre con el código.
Pero ciñámonos al código. Es relativamente frecuente que los proyectos de software se diseñen también organizados por componentes. Esto es habitual cuando se utiliza una metodología waterfall en la que existe una fase de diseño previa, tras la recogida de requisitos, en las que se planifican todos y cada uno de los componentes del sistema. En ese contexto, parece natural distribuir el trabajo entre varios equipos, cada uno encargado de un componente.
Este enfoque es generalmente rechazado en los frameworks ágiles por varias razones. La primera es que suele llevar a una entrega tardía de valor. Se desarrollan los componentes y hay que resolver todos los posibles problemas de integración antes de ser capaces de poner el software en producción y a disposición del público.
En consecuencia pueden producirse algunos efectos indeseados:
- No sabemos si el producto funcionará. Es una pregunta a la que solo podremos dar respuesta cuando todos los componentes estén terminados e integrados.
- No tenemos feedback temprano, puesto que el software no está en producción. Si la hipótesis de negocio no es correcta, no lo vamos a saber. Si la oportunidad de negocio ha pasado y una empresa competidora ha salido antes, es posible que hayamos perdido el mercado.
Esta aproximación es lo que se conoce como rebanado o slicing horizontal: una prestación o proyecto se divide en componentes o fases que se desarrollan en paralelo y el producto se entrega después de una fase de integración.
Los frameworks ágiles suelen preferir un tipo de rebanado o slicing vertical. En lugar de dividir una prestación o proyecto en componentes, proponen una aproximación distinta basada entregas de valor, iterativas e incrementales. En lugar de preguntarse: ¿qué piezas necesito para construir esta funcionalidad?, la cuestión es más bien: ¿qué necesito hacer para entregar al menos una mínima parte de la funcionalidad que aporte valor? Intentaré explicarlo con un ejemplo.
Supongamos que tenemos una tienda de material para modelismo: maquetas, pinturas, herramientas, libros, etc. y queremos vender online.
Lo primero que necesitamos es una web que se pueda visitar, lo que implica disponer de una infraestructura adecuada, y una aplicación básica que pueda exponer una landing page, tal vez con acceso a un catálogo de productos. Como queremos vender, podríamos incluir un simple formulario de pedido en el que el cliente anote los productos deseados y una forma de contacto. Es cierto: toda la gestión de la venta tendríamos que hacerla a mano, pero al mismo tiempo estamos obteniendo información:
- ¿Existe interés en nuestra tienda?
- ¿Qué tipo de productos se piden más?
- ¿Qué tipo de clientes tenemos?
- ¿Desde dónde nos contactan?
Esta información nos puede ayudar a tomar decisiones para priorizar los siguientes pasos. Entonces se repite la pregunta: ¿qué necesito hacer para entregar al menos una mínima parte de la funcionalidad que aporte valor?
Así, por ejemplo, me interesará probablemente introducir un carrito de compra y un catálogo de productos. Pero a lo mejor, gracias a la información recibida, puedo ver que hay interés en herramientas, pero no en libros, así que puedo dedicar mis esfuerzos a esas gamas de productos.
En una siguiente iteración podríamos empezar a plantear introducir un medio de pago. La decisión de cuál en concreto puede venir determinada por lo que hayamos aprendido de interactuar con nuestros clientes. De este modo, nos aseguramos de introducir una integración con aquella pasarela de pago que sí va a ser usada.
Estas capas de funcionalidad implican diversos componentes, porque atraviesan todos los estratos de la arquitectura de la solución, por eso se le llama rebanado vertical. Así, en lugar de desarrollar componentes muy detallados, lo que vamos añadiendo es funcionalidad de extremo a extremo a medida que la necesitamos. Para hacer esto bien, es necesario escribir código simple sobre el que sea fácil intervenir, lo cual requiere un refactor constante de modo que el código se abra a introducir cambios cuando sea preciso.
W de Work in Progress
WIP es el acrónimo en inglés de Trabajo en Progreso o Work In Progress. El trabajo en progreso en un equipo es todo el trabajo que está en marcha, pero sin terminar.
La gestión del WIP es fundamental en un equipo ágil o de alto rendimiento, porque es uno de los factores que determina la capacidad de entrega. Y, por lo general, la gestión del WIP consiste en limitarlo y reducirlo lo máximo posible.
Esto puede sonar un poco anti intuitivo, parece que si somos capaces de trabajar en varias cosas a la vez en paralelo, deberíamos poder acabarlas todas más o menos a la vez. Así que un equipo de n personas, podría abordar n proyectos o tareas simultáneas. Decimos que su capacidad es de n. Lo razonable, entonces, sería que un equipo en un momento dado limita su trabajo en progreso a n ítems o tareas.
Sin embargo, muchas veces resulta que las cuentas no acaban de salir. Por ejemplo, si un equipo está formado por cinco desarrolladoras, se asume que su capacidad es de cinco tareas simultáneas y su límite de trabajo en progreso sería de cinco ítems. Todo cuadra perfectamente, ¿verdad? Pues, no.
No todo es programar
Resulta que una de las desarrolladoras es la manager del equipo, por lo que entre sus funciones están participar en reuniones de coordinación con otros managers, las reuniones de seguimiento de las personas a su cargo y otras tareas asociadas a su rol. Su posibilidad de aportar al flujo de trabajo está reducida, asi que si asume tareas del equipo lo normal es que siempre lleve retraso o no las pueda realizar. Eso sin contar, que frecuentemente tiene que resolver dudas y preguntas del resto del equipo por cuestiones técnicas o de negocio.
En consecuencia, sería mucho más realista asumir que la capacidad y el límite del WIP del equipo es cuatro. También es importante tener en cuenta la capacidad efectiva. Por ejemplo, si una persona en junior o muy nueva en el equipo es posible que no tenga aún autonomía para completar tareas por sí misma. En ese caso, quizá deberíamos plantearnos que esta persona trabaje siempre junto con otra de más experiencia, de tal forma que la capacidad del equipo sería tres, y consecuentemente el límite del WIP.
Bueno, esto parece solucionar el problema. Pero… No tan deprisa.
Dividir en tareas por encima de nuestras posibilidades
Supongamos que un equipo de capacidad cuatro ha decidido trabajar en dos historias de usuario. Estas historias se han dividido en tareas y cada desarrolladora se asigna una tarea. De este modo tendríamos cuatro tareas en marcha. Son posibles varias configuraciones, por ejemplo, que hayan iniciado dos tareas de cada historia de usuario, o cuatro de una. Incluso tres de una y una de la otra.
En ese caso, es posible que unas tareas bloqueen otras. O sea: si trabajamos paralelamente en dos tareas de la misma historia podría ocurrir que una consista en desarrollar un elemento que es requerido por la otra. Esto haría necesario detener una de las tareas para esperar por la otra. En ese caso, estamos desperdiciando tiempo.
Se podría aducir aquí que, mientras una tarea está bloqueada, podemos iniciar otra. Pero esto no reduce el WIP, sino que lo aumenta, porque la tarea bloqueada sigue siendo trabajo en progreso, aunque esté parada. En nuestro ejemplo, pasaríamos de un WIP de cuatro a cinco, superando el límite que habíamos definido.
El límite de WIP, por tanto, no depende únicamente del número de personas, sino también de la relación entre las tareas. De hecho, los mayores problemas con el WIP suelen ocurrir en equipos que trabajan por tareas y no por historias de usuario.
Otro problema, relacionado tiene que ver con el cambio de contexto. Cuando una desarrolladora termina una tarea y se asigna otra que está en un proyecto o historia de usuario diferente, tiene que emplear un tiempo en adaptarse al nuevo contexto. En algunos equipos, podría implicar incluso trabajar en una base de código diferente. Este tiempo de adaptación es tiempo en el que la tarea no progresa. De nuevo: desperdicio.
Organizarse en historias de usuario
Una forma de limitar el WIP de manera eficiente es definirlo como historias de usuario simultáneas en lugar de tareas. En este punto quizá sea necesario hacer algunas definiciones.
Ya hablamos de historias de usuario en otro capítulo de este libro, pero podemos pensar en ellas como proyectos concretos para poner una prestación funcionando en manos de los clientes. Las tareas serían la construcción de las piezas necesarias para completar esos proyectos.
Las tareas tienen sentido en el contexto de la historia de usuario. Por ejemplo, en la historia de usuario “los clientes pueden pagar su pedido con Paypal”, puede haber tareas como:
- Añadir un componente en la página web para seleccionar pago con Paypal.
- Desarrollar la integración para redirigir al cliente a su cuenta de Paypal si escoge este medio.
- Procesar la respuesta del medio de pago para marcar el pedido como confirmado y pagado e iniciar el proceso de envío.
- Añadir una página de confirmación del pedido pagado con este medio.
- Enviar una notificación.
- Mostrar una página indicando que no se ha podido realizar el pago, si es el caso.
Estas tareas son dependientes entre sí y pueden generar bloqueos. Pero podemos ver que unas corresponden a la especialidad de frontend, y otras a la de backend, lo que nos proporciona un criterio de asignación de recursos. Dos personas, una por especialidad, podrían trabajar juntas en la historia de usuario, estableciendo contratos para la comunicación entre ambas partes. Según los casos, podríamos decidir que necesitamos más personas trabajando en esta historia. Pero si no es así, contamos con otras dos personas que pueden estar trabajando con otra historia.
En este caso, el límite de WIP podría ser de dos historias de usuario simultáneas. Durante esta iteración solo deberíamos estar trabajando en esas dos historias.
Lo curioso del asunto es que la historia que acabamos de describir abarca seis tareas. ¿No es algo contradictorio? Resulta que reduciendo el WIP podríamos tener más productividad.
Esto se explica por varias razones. Por un lado, la historia de usuario proporciona un contexto único durante toda la iteración para las desarrolladoras participantes. No tienen que cambiar entre contextos, no tienen que entender como encaja cada tarea en cada momento. De hecho, puede que desarrollen una compresión de la historia de usuario que les permita hacer una partición más conveniente de las tareas.
Los bloqueos entre tareas son más fáciles de prevenir, evitar o gestionar. Por ejemplo, si la tarea implica frontend y backend, pueden acordarse contratos de las API que expone el backend, de tal forma que el frontend puede trabajar con stubs, o incluso tirando peticiones contra endpoints “tontos”, mientras el backend se ocupa de otros elementos. Gracias a esto es posible paralelizar el desarrollo.
Lo que ocurre es que cuando distribuimos las personas del equipo para trabajar en historias de usuario, lo que estamos haciendo se parece a crear equipos enfocados (task force) que tienen un objetivo claro y un límite del WIP igual a uno. Si es necesario añadir personas, el límite de WIP se mantiene igual. Pero solo podemos añadir personas hasta un punto en que no se molesten.
Es importante coordinar el límite del WIP con la definición de objetivos. Si tenemos varias historias de usuario en una iteración, una de ellas tiene que ser la prioritaria y tenemos que asignarle todos los recursos que admita para que se pueda entregar en esa iteración.
De hecho, las preguntas más importantes que un equipo debe hacerse son:
- ¿Qué es lo más importante que deberíamos estar haciendo ahora? Que básicamente, coincide con lo que es más importante para el cliente.
- ¿Qué es lo que NO tendríamos que estar haciendo ahora? Que es cualquier otra cosa.
Para lograr una buena asignación de la capacidad del equipo puede ser de mucha ayuda utilizar técnicas de Rebanado Vertical de las historias de usuario (Vertical Slicing).
X de Extreme Programming
Entre los diferentes frameworks de los que se nutrió el Manifiesto Ágil, Extreme Programming destaca por ser uno de los más influyentes. No solo en el nacimiento de Agile, sino por su énfasis en unas prácticas técnicas que han ido incorporándose, con mayor o menor fortuna, en los equipos de desarrollo.
Kanban o Scrum, siendo también metodologías ágiles, podría decirse que están más orientadas a la gestión de proyectos en general. De hecho el Kanban que usamos en desarrollo de software es una adaptación de un proceso industrial.
Puedes aplicar ambas metodologías en entornos distintos a la programación y, de hecho, es relativamente habitual ver como equipos de otras áreas de una empresa adoptan alguna de ellas. Además, encajan bastante bien con estructuras organizativas con una cierta jerarquía y que buscan definir procesos, algo que satisface a algunas visiones más tradicionales de la dirección de proyectos.
La gran difusión de Scrum, para qué nos vamos a engañar, es gracias a que permite un cierto grado de supervisión a las capas de management, lo que resulta tranquilizador para estas, aunque puede redundar, precisamente, en una pérdida de agilidad.
Extreme programming, por su parte, nace específicamente para equipos de desarrollo de software. No solo porque lo indica su nombre, sino porque pone el énfasis en aspectos y prácticas técnicas y en la búsqueda de la excelencia en las mismas. Así, cuestiones como la integración contínua, test driven development, pair programming, uso de estándares de escritura de código, diseño simple, propiedad colectiva, refactoring, etc., nacen en este enfoque o son prácticas primarias del mismo.
Un aspecto llamativo de Extreme Programming es que no postula una guía de procedimientos al estilo de Scrum, sino que habla de Actividades, Valores y Prácticas. También usa el concepto de Whole Team, que debería resultar obvio: todo el equipo contribuye al proyecto.
Así todo, observando ambas metodologías de forma superficial podríamos encontrar muchas similitudes. En las dos se busca un desarrollo iterativo e incremental, existe una planificación de lo que debe hacerse, se persigue entrega de valor y se reflexiona sobre el proceso seguido para mejorarlo. Es cuando profundizamos cuando encontramos las diferencias.
La gran mayoría de veces los equipos que se autodefinen como ágiles utilizan una mezcla de elementos de Scrum y de Extreme Programming, lo que puede resultar confuso. Scrum pone foco en un proceso bastante reglamentado, con roles y momentos definidos, algo en lo que Extreme Programming no pone tanto acento. Pero Scrum es más management friendly, y tiene una guía de implementación muy precisa.
Así, por ejemplo, Scrum tiende a favorecer una aproximación al desarrollo basada en tareas y en la distribución de la carga de trabajo para alcanzar el objetivo previsto en el sprint o plazo de la iteración. Extreme programming prefiere trabajar a partir de las Historias de Usuario, y el equipo se organiza para contribuir a completarlas, haciendo uso de diferentes prácticas técnicas. Estas prácticas buscan generar software de calidad de forma sostenida y sostenible.
Posiblemente, sea el énfasis en las prácticas técnicas lo que hace resaltar las diferencias. Ambos frameworks giran en torno a definir qué hacer, por qué y cuándo, pero solo Extreme Programming enfatiza el cómo. Para ello, propone un conjunto de prácticas que, de alguna manera, materializan eso. Veamos algunos ejemplos:
Test Driven Development hace describir los requisitos de una historia de usuario con una representación formal y ejecutable (tests) que nos permiten saber, en todo momento, si estamos desarrollando el software que deseamos, pues proporciona feedback inmediato. Además, define el límite de lo que es necesario desarrollar, contribuyendo a reducir la cantidad de trabajo en progreso.
Pair programming y Mob programming, permiten que las contribuciones de código tengan una revisión instantánea, garantizando que las soluciones propuestas sean las mejores que el equipo puede aportar. Además, contribuyen a que el equipo disemine el conocimiento necesario, no solo de las soluciones técnicas, sino la comprensión del negocio en el que se está trabajando. Esto es lo que permite desarrollar la propiedad colectiva, reduciendo el riesgo de fugas de conocimiento cuando una persona sale del equipo por la razón que sea.
Integración contínua, ayuda a mantener una alta velocidad de desarrollo al eliminar los cuellos de botella provocados por conflictos cuando se están desarrollando diferentes partes del código en paralelo. Cuanto antes integramos los cambios, menos posibilidades hay de conflictos, más fácil es reutilizar soluciones, etc. Si los cambios son pequeños, se reduce tanto el riesgo de defectos como el riesgo de conflictos. En consecuencia, son necesarias menos acciones de mantenimiento. Y en caso de que aparezcan problemas, son más fáciles de diagnosticar.
Spikes. En XP los spikes son experimentos en código para tratar de valor la incertidumbre asociada a una solución. Esto es, se prueban ideas para tratar de anticipar su coste y las dificultades de implementación. Cuando se han obtenido conclusiones, se tira ese código y se hace la implementación real.
Extreme programming pone el acento en que no es posible un desarrollo ágil de software sin incidir en estas prácticas técnicas. Un framework ágil, sea cual sea, no puede obviar la excelencia técnica como requisito para lograr la entrega sostenida de valor
Y… todas las demás personas
No nos engañemos. Sigue estando vigente el estereotipo de las programadoras como personas solitarias, resolviendo complejos problemas mientras teclean febrilmente en un ordenador. Pero es un estereotipo, y la realidad, como casi siempre, es mucho más interesante.
También tenemos otro tópico, más frecuente por desgracia, en la que los equipos de desarrollo son vistos, y se ven a sí mismos, como meros ejecutores, sin voz ni voto, de las decisiones de negocio.
Ni lo uno, ni lo otro
Una de las cosas que nos ha mostrado el movimiento ágil es precisamente que el desarrollo de software es una actividad eminentemente social, nunca individual, en la que el código es tan solo una parte más en la construcción de un producto o servicio. Y en la que el equipo de desarrollo forma parte integral del proceso.
Ese producto o servicio trata de satisfacer una necesidad de una cliente potencial de un cierto negocio. Negocio que debe generar los ingresos necesarios como para hacer sostenible el producto, y producir beneficios tras cubrir los gastos e inversiones necesarios.
Un negocio existe porque alguien ha detectado una necesidad y ha sido capaz de entender qué producto podría satisfacerla lo bastante bien como para convencer a inversoras para inyectar dinero y para convencer a clientes para usarlo y pagar por ello.
Convertir una idea en un negocio funcionando requiere del esfuerzo coordinado de muchas personas ejerciendo diversos roles y aportando infinidad de saberes. Como desarrolladoras tenemos que interactuar con gran parte de ellas y entender que nuestro trabajo no consiste en resolver un problema técnico: consiste en resolver un problema de negocio. En otras palabras: programamos para que nuestra empresa gane dinero.
El software es algo que la empresa necesita para poder desarrollar su actividad. Es cierto que puede contribuir de una manera especialmente importante por algo de lo que hemos hablado en otro momento: el software es plástico y adaptable, lo que permite plasmar ideas y prestaciones que serían imposibles de otro modo y que pueden ser clave para diferenciarse y competir con los otros cientos de empresas que se dedican exactamente al mismo negocio. Pero el software no es lo que la empresa vende, excepto que te dediques a eso. Lo que la empresa vende es un cierto producto o un cierto servicio y tiene que convencer al público de que el suyo es el más conveniente.
Cada vez que se desarrolla una prestación del software han tenido que participar analistas de negocio para identificar una demanda de la misma por parte de los clientes potenciales, y se ha tenido que valorar la posibilidad de darle respuesta, examinado los beneficios potenciales y los costes previsibles. Ha sido necesario que expertas averigüen qué ofrecer para satisfacer esa necesidad. Especialistas en experiencia de usuario que diseñen la forma en que esa prestación sea fácil de entender y usar para el público. Personas de marketing que elaboren un plan para darla a conocer y divulgarla. Y, por supuesto, desarrolladoras para implementarla. Y seguro que me dejo más personas necesarias.
Todo este proceso requiere negociaciones y discusiones. No basta con descubrir una necesidad que nuestro producto podría satisfacer e implementarla. ¿Es relevante? ¿Cuánto nos va a costar? ¿Es mejor esa idea o esta otra? ¿Tenemos la capacidad para ofrecer esa prestación? ¿Nos va a diferenciar de la competencia? ¿Y cómo la vamos a hacer más atractiva? ¿Qué requisitos legales y regulatorios debemos cumplir?
Desde el punto de vista de un equipo de desarrollo cada prestación nueva puede requerir un distinto tipo de esfuerzo. En muchos casos, una prestación implica básicamente añadir el código necesario para ponerla en manos de sus potenciales usuarias. Otras veces, requiere realizar cambios significativos en la infraestructura que le da soporte. O iniciar un sistema nuevo. O el cambio nos pide reestructurar equipos y proyectos.
Por supuesto, todos estos elementos, y muchos más, entran en juego en la negociación. El equipo de desarrollo no puede hacer lo que le venga en gana, ni el equipo de negocios puede esperar que sus peticiones se conviertan en realidad tal cual las imaginan. En realidad, no debería darse una separación estanca como la que refleja el fragmento anterior. En su lugar, es necesario desarrollar una relación colaborativa.
Esto es por lo que el Manifiesto Ágil habla de colaboración, y no de contratos, o se usan términos como cocreación, asociación productiva o descubrimiento conjunto, en sus diversas revisiones críticas.
Los equipos de desarrollo no son entes aislados y, si bien su trabajo es materializar los productos y servicios que diseña la empresa, deben tener voz y participación. Es necesario saber concretar los requisitos técnicos necesarios para implementar una prestación, a fin de ofrecer tanto una estimación de costes, como poner sobre la mesa expectativas realistas sobre los productos y como implementarlos y desplegarlos.
Por eso mismo, son fundamentales dos cuestiones:
Los equipos de desarrollo deben conocer el negocio y deben conocer los productos. Tienen que entender cómo gana dinero la empresa y, por tanto, ser capaces de dirigir sus esfuerzos para contribuir a ello. Parafraseando a Luis Artola, en su libro Software Economics, como desarrolladoras debemos saber que trabajamos en reducir riesgos, pagar deuda, controlar costes y añadir valor.
Por su parte, el resto de la empresa tiene que entender la tecnología y como contribuye al desarrollo del negocio, lo que incluye también sus limitaciones y procesos. Porque la tecnología también incluye riesgos, deudas, costes y aporta valor.
¿Tiene sentido mantener una distinción entre equipos de tecnología y equipos de negocios?
Z de Zero Bugs
Todas conocemos la historia del primer bug: una polilla atrapada en un relé, hallazgo que se atribuye a Grace Hooper, aunque sería más correcto atribuirlo en conjunto al equipo que estaba trabajando en ese ordenador.
Qué es un bug
Solemos definir un bug como un mal funcionamiento de un sistema de software. Curiosamente, ese primer bug, tenía más que ver con el hardware. La cuestión es que hay múltiples cosas que pueden fallar, desde elementos de infraestructura hasta la lógica expresada en el código. Si nos ceñimos al código, un bug es algo un tanto más complicado de definir porque habría que distinguir entre lo que podríamos considerar un comportamiento incorrecto, cuando el software no hace lo que se espera, y un fallo manifestado en forma de un error que impide que el sistema funcione.
Como era de esperar, los bugs tienen un coste económico: si no se puede usar el software, se detienen los ingresos que genera, o se incrementan los costes que evitaba. O, en otros casos, aumenta la posibilidad de que un cliente deje de trabajar con nosotras. En resumidas cuentas: un bug es dinero que se pierde.
La política de Zero bugs consiste en dejar de registrar, clasificar y seguir bugs y dedicarse a resolverlos de forma inmediata, en cuanto nos informan de ellos.
Zero bugs la forma ágil de gestionarlos
Esto hay que verlo en un contexto ágil. En él, asumimos que las entregas de valor son pequeñas y bien definidas. Si aparece un bug una vez desplegada una entrega, es muy probable que haya sido introducido o habilitado por dicho cambio. Por tanto, la localización y subsanación debería ser rápida. También asumimos una cobertura razonable de tests, al menos en las partes críticas del sistema, y buenos sistemas de integración de cambios y despliegue. Todo esto contribuye a garantizar que podemos desplegar software sin defectos evidentes, pero también a localizarlos de forma relativamente fácil cuando ocurren.
Una vez que un bug ha sido reportado, lo primero sería centrarnos en él y establecer una o más hipótesis y expresarlas en forma de test. Un bug normalmente es el resultado de un ejemplo que no ha sido testeado. Esto puede pasar porque carecíamos de información en el momento de desarrollo, bien porque no identificábamos ese ejemplo como un caso particular. También puede ocurrir que un cierto cambio habilite un bug que antes no se había manifestado.
En cualquier caso, una vez que tenemos un test, modificamos el código para hacerlo pasar, junto con todos los demás tests existentes. De este modo, subsanamos el bug y podemos desplegar este nuevo cambio para arreglarlo en producción. Entonces volvemos al desarrollo habitual.
Esta forma de abordar los bugs suele despertar recelos. Por ejemplo, es cierto que no se puede aplicar en organizaciones que arrastran errores desde hace largo tiempo. Pero también existe una especie de creencia de que los bugs son algo así como consustanciales al desarrollo de software. Sin embargo, Zero bugs no va tanto de impedir que aparezcan errores, como de evitar que se queden.
Defectos de software
Para empezar, en lugar de bugs voy a empezar a hablar de defectos. Un defecto del software es un concepto que podríamos considerar más amplio que el de bug. Un defecto ocurre cuando el software no se comporta como las usuarias esperan.
Defectos de comportamiento
Un defecto del software puede ser algo así como un aspecto no especificado al definir una prestación. ¿Cómo puede ser un bug algo que no sabías que era necesario?
Otro ejemplo de defecto puede ser el haber hecho asunciones incorrectas sobre una característica. Como que un cierto parámetro admita o no números negativos. De nuevo, estaríamos ante un caso de definición incompleta, de un escenario no contemplado.
Estos defectos suelen detectarlos las usuarias del software, de ahí que muchas veces se habilitan sistemas para que puedan informar de los problemas. Básicamente, se trata de bug-trackers y presentan el riesgo de convertirse en backlogs de bugs, que tienen que esperar a ser priorizados para ser atendidos. Exceptuando, tal vez, el caso de que el problema sea tan grande que se prioriza inmediatamente.
Por este motivo, entre otros, frameworks como extreme programming proponen poner al cliente en el propio equipo. Si algo no funciona bien, la pregunta ¿qué deberíamos estar haciendo? Se contesta sola.
Defectos técnicos
Otra categoría de defectos nos lleva a lo que podríamos considerar errores técnicos. Por ejemplo, que se pueda dar una división por cero, desbordar la memoria, o no manejar la situación en que accedemos a un servicio externo y no funciona. Es decir, errores que no tienen que ver haber interpretado mal la lógica de nuestro negocio, sino con detalles de implementación. Obviamente, lo peor que puede pasar es que el sistema no pueda utilizarse de ninguna manera.
La mayor parte de defectos técnicos debería ser detectada con herramientas de monitorización, que nos permitan saber cuando se producen este tipo de problemas y que nos alerten cuanto antes.
Triaje
En muchas organizaciones se hace triaje de bugs. El triaje sirve para decidir qué equipo debe encargarse de atender un bug. Esto implica, tanto entender si se trata de un defecto de comportamiento o es un defecto técnico. Y, en todo caso, averiguar quién tiene los conocimientos o acceso necesario para darle solución.
A la vez que escribo esto, debo reconocer que se me encienden varias alarmas. En todo caso, es cierto que a poco que una organización sea grande, es difícil saber a quién dirigir el reporte de un defecto, por lo que un proceso de triaje tiene sentido. Sin embargo, corre el riesgo de convertirse en un freno. En muchos casos, la solución del bug puede ser evidente para el equipo y todo el proceso de seguimiento y triaje puede hacer que tarde mucho en hacerse la corrección.
Así, es necesario garantizar que no pasa más tiempo del necesario entre que se informa de un defecto y se le pone remedio, para lo cual debe llegar cuanto antes al equipo de desarrollo. El mejor escenario, en estos casos, es que el equipo tenga ownership de su producto o, en su caso, de su micro-servicio. Si existen muchas dependencias entre equipos y proyectos, puede ser muy difícil determinar el punto de fallo, o decidir quién tiene la responsabilidad de remediar la causa.
Si tienes bugs de larga duración, que llevan meses, o incluso años en tu backlog o en tu sistema de seguimiento, la mejor estrategia, de largo, es eliminarlos de ese registro y empezar de cero. Si alguno de esos bugs era importante, puedes tener por seguro que volverá enseguida.
Buenas prácticas técnicas y zero-bugs
Aplicar buenas prácticas técnicas en el desarrollo es la mejor forma de prevenir la aparición de defectos, pero, ante todo, es la mejor forma para conseguir que sea fácil identificar sus causas e introducir una solución.
El refactor continuado no evita por sí mismo los defectos, sin embargo, es más fácil prevenirlos en un software bien estructurado que refleja de forma clara el conocimiento de negocio. Cuando seguimos principios de diseño y construimos software basado en pequeñas unidades, con responsabilidades bien acotadas, bloques de código reducidos, etc., determinar la causa que ha originado un error suele ser un proceso bastante sencillo y preciso.
El testing nos ayuda a reducir las oportunidades de introducir bugs. En general, podríamos decir que los bugs aparecen en aquellas partes del código en las que no hemos podido definir el comportamiento esperado mediante al menos un test. Son zonas oscuras del comportamiento del software.