La trampa de los atajos y el falso dilema entre calidad y velocidad
Cuando dos equipos tienen objetivos diferentes e incompatibles, se genera una resistencia que obliga a todos a realizar un esfuerzo extra para alcanzar sus metas.
Imagina un escenario donde un equipo de desarrollo de software lleva un ritmo de entrega que no le permite pagar la deuda técnica que va generando. Tras cada funcionalidad o bug solucionado, viene la siguiente, y entre los parches provocados por la urgencia y la entropía del código, mantener la misma velocidad de entrega se vuelve cada vez más difícil. Además, los fallos en producción se vuelven más frecuentes.
Tras analizar la situación, el equipo acuerda cambiar su flujo y prácticas de desarrollo. Adoptan prácticas de eXtreme Programming como TDD y Pair Programming, tomándose tiempo para diseñar el software adecuadamente y refactorizar zonas del código que no les permitían evolucionarlo con seguridad. En resumen, comienzan a intentar conseguir un ritmo sostenible gracias a mantener a raya la deuda técnica.
Lo que ha hecho el equipo es crear un bucle de compensación donde, al detectar una brecha entre la calidad interna deseada y el estado actual, proponen acciones para pagar esa deuda técnica y así mantener la calidad del código en un nivel óptimo que permita seguir evolucionando la base de código a un ritmo sostenible.
Sin embargo, este nuevo ritmo, aunque sostenible, es más lento que el anterior. Así que para hacer frente a algunas oportunidades a la velocidad acostumbrada, la directiva busca atajos:
Que el CTO o algún tech lead haga el desarrollo para no «molestar» al resto del equipo, que ya está con algo también importante y urgente, pero lo están haciendo a la «manera lenta».
Usar un becario aislado del equipo y de sus acuerdos cómo trabajar para sacar a producción la solución a esa oportunidad. Cuando el becario termine sus prácticas, el código que ha hecho hay que seguir manteniéndolo.
Hacer outsourcing de manera descoordinada del equipo, para no «distraerlos». Así, un equipo externo hace el desarrollo y luego el equipo interno tiene que mantenerlo.
Pedir al equipo que no realicen tests o hacer micromanagement sobre cómo gestionan la deuda técnica para asegurar que dan más prioridad a la entrega de nuevas funcionalidades o la corrección de bugs sin resolver la causa raíz de los mismos (el mal estado de la base de código).
Ofrecer bonos por trabajar horas extras, una práctica poco sostenible que puede llevar al agotamiento del equipo y generar incentivos no deseados.
La directiva está añadiendo otro bucle de refuerzo negativo que hace que el sistema vuelva a su ritmo de entrega anterior y, como consecuencia, la calidad interna vuelve a verse comprometida. Aunque esto no impacta al equipo de forma inmediata, en algún momento tendrán que hacerse cargo de la deuda técnica si esas nuevas funcionalidades necesitan evolucionar o aparecen fallos.
Trampa de la Resistencia a las Políticas
Estamos en presencia de la trampa de las «soluciones fallidas» o de la «resistencia a las políticas» que describe Donella Meadows en Pensar en Sistemas:
El origen de la resistencia a las políticas se encuentra en la racionalidad limitada de los actores de un sistema, hombres, mujeres (o «cosas», en el caso de una institución) que poseen sus propios objetivos. Cada actor controla el estado del sistema en relación con alguna variable importante —los ingresos o los precios o la vivienda o las drogas o la inversión— y compara ese estado con su propio objetivo. Si existe una discrepancia, cada actor hace algo para corregir la situación. Por lo general, cuanto mayor sea la discrepancia entre el objetivo y la situación actual, más enfática será la acción.
La causa raíz de la resistencia al cambio surge porque los objetivos de los subsistemas son diferentes e incompatibles entre sí, como aparentemente lo son la calidad interna y velocidad de entrega.
Cuando esta trampa está en marcha, cada parte tira en una dirección diferente, y todos tienen que realizar un esfuerzo extra para conseguir sus objetivos. El equipo de desarrollo encuentra cada vez más complejidad y deuda técnica que ralentiza su ritmo, ya sea porque tiene que pagarla, porque es más difícil evolucionar ese código o porque se introducen más fallos. Por su parte, la directiva percibe esa ralentización del ritmo de entrega y sigue buscando atajos que, a corto plazo, solucionan las oportunidades puntuales pero no hacen más que engordar el problema de fondo.
La falsa dicotomía entre la calidad interna y el coste
El escenario que he usado de ejemplo representa lo que Martin Fowler llama la Hipótesis de la Resistencia del Diseño (Design Stamina Hypothesis):
Las actividades de diseño ciertamente consumen tiempo y esfuerzo, pero valen la pena porque facilitan la evolución del software en el futuro. Puedes ahorrar tiempo a corto plazo al descuidar el diseño, pero esto acumula deuda técnica que ralentizará tu productividad más adelante. Invertir esfuerzo en el diseño de tu software mejora la resistencia de tu proyecto, permitiéndote avanzar más rápido durante más tiempo.
Estamos acostumbrados a pensar de manera lineal; es nuestro modo por defecto. Si para conseguir mayor calidad interna necesito gastar más tiempo, entonces no compensa. ¿Quién va a querer ir lento cuando puede ir más rápido a costa de algo tan invisible para el usuario final como la calidad interna? Sin embargo, la mayoría de los sistemas complejos requieren un pensamiento no lineal, que normalmente es contraintuitivo. Como vimos en Ralentizar, simplificar y amplificar para ganar, a veces es necesario ir más lento para poder ir más rápido luego.
Como bien explica Fowler su artículo Is High Quality Software Worth the Cost?, este compromiso entre calidad interna y coste solo existe durante las primeras semanas. Es cierto que durante ese tiempo podrías ir más lento si inviertes en el cuidado del diseño del software. Pero, a partir de entonces, la velocidad de entrega con un flujo que cuida la calidad se mantiene estable, mientras que con un flujo que no cuida la deuda técnica, será cada vez más difícil responder a las necesidades del mercado.
El contexto del equipo y la organización es importante. Un modelo mental muy útil para este dilema es el Modelo 3X de Kent Beck:
Explorar: la búsqueda arriesgada de un retorno viable sobre una inversión viable. La exploración exitosa es impredecible, por lo que la estrategia de mayor valor esperado es reducir el costo de la experimentación e invertir un poco en muchos experimentos no correlacionados. Si tienes suerte, uno de estos experimentos resulta ser inesperadamente exitoso, lo que lleva a:
Expandir: ahora las cosas se vuelven locas (piensa en Pokémon Go o Facebook Live Video). Aparecen cuellos de botella imprevistos. Todo lo que tienes tiempo de hacer es eliminar el próximo cuello de botella justo antes de que te descarrile. Una vez que el crecimiento se vuelve rutinario, es hora de:
Extraer: ahora la forma de los espacios de problemas y soluciones es clara. Un euro invertido equivale a tres euros de retorno. Emergen manuales de operaciones: así es como se lanza el servicio en una nueva ciudad. Las economías de escala importan: entregar el servicio a menor costo es más rentable.
En función de la etapa en la que se encuentre el producto se puede ser más o menos cortoplacista y asumir más riesgos y deuda técnica.
Parte del contexto del equipo a tener en cuenta es su madurez. Cito el resumen que hizo Edu Ferro sobre la sesión «La “mal” entendida calidad en el desarrollo de software» que tuvo lugar en el SOSZ24:
Si algo me quedó claro en esta discusión es que todo en el desarrollo del software es contextual, incluida la calidad. Por supuesto, se habló de ser consciente de las decisiones que tomamos y de que la velocidad implica una dirección. Yo introduje el tema de la inercia y la madurez de los equipos, puesto que es fácil hablar de tener distintos niveles de calidad dependiendo del contexto, pero eso implica que el equipo es capaz de trabajar bien y seguro con distintas prácticas y que tendremos que absorber el coste basal del software desarrollado durante los distintos periodos y contextos (inercia).
Si asumimos deuda técnica es importante saber lo que hacemos, muy útil este cuadrante de Fowler sobre los tipos de deuda técnica:
Debemos ser conscientes de la deuda que estamos tomando y evaluar deliberadamente los beneficios a corto plazo frente a los costos a largo plazo. Es crucial evitar la deuda imprudente, procurando no sacrificar la calidad del código por soluciones rápidas y sucias que no se pueden mantener. Además, debemos aceptar la deuda inadvertida como parte del proceso de desarrollo, reconociendo que siempre habrá algo de deuda técnica debido al aprendizaje continuo y estar preparados para manejarla.
¿Cómo salir de esta trampa?
Aquí vuelvo a enfatizar la empatía como una habilidad imprescindible para salir de trampas como esta. La directiva no tiene por qué ser vista como explotadores que sólo buscan complacer a los clientes a toda costa a cambio de dinero, ni los desarrolladores como personas que sólo se preocupan por su código y se toman la aplicación de buenas prácticas como un argumento moral. Cada uno tiene sus propios incentivos y son víctimas de un sistema que es importante entender para descubrir qué palancas activar y así aunar esfuerzos.
Para salir de esta trampa no hay otra alternativa que relajarse, ponerse todos de acuerdo y alinearse en los objetivos. Intentar aprovechar la energía y creatividad que se está invirtiendo en resistirse a las políticas buscando atajos, para unir esfuerzos y definir objetivos que tengan en cuenta las metas fundamentales de ambas partes que idealmente estarán alineadas con las de la organización. Esto es justo lo que proponía en la entrega anterior con el enfoque de resolución de conflictos desde la compasión.
Recursos
Design Stamina Hypothesis | Martin Fowler
Is High Quality Software Worth the Cost? | Martin Fowler
Technical Debt Quadrant | Martin Fowler
The Product Development Triathlon | Kent Beck
Guía para la gestión de Deuda Técnica | Dani Latorre
Pensar en Sistemas | Donella Meadows
Serie: las trampas de los sistemas complejos
Esta entrega forma parte de una serie sobre las trampas de los sistemas complejos aplicadas al desarrollo de productos:
Elusión de las reglas y persecución del objetivo equivocado: La trampa del testing coverage.
Desplazamiento de la carga hacia la intervención: La trampa de la adicción al parche.
Deriva hacia el bajo rendimiento: La Trampa de la Erosión de Metas y el Síndrome de la Rana Hervida.
Tragedia de los recursos comunes: La tragedia del código compartido.
Exclusión competitiva: La trampa del «rockstar developer».
Si te interesa el tema del pensamiento sistémico aplicado al desarrollo de producto, de vez en cuando organizo talleres sobre cómo usar y sacarle partido a estas herramientas. Si estás interesado en que lo imparta para tu equipo o en algún evento, escríbeme.