
Este artículo fue publicado originalmente en Octubre de 2023 en mi blog y fue el primero de la serie las trampas de los sistemas complejos. De vez en cuando rescataré en esta newsletter los artículos que he escrito a lo largo de los años y que han generado mayor interés.
Trampas y oportunidades de los sistemas
Los teóricos de sistemas llaman “arquetipos” a estructuras comunes que dan lugar a comportamientos característicos. Donella H. Meadows los define como “trampas y oportunidades de los sistemas”, ya que son responsables de algunos de los problemas más difíciles de abordar, pero también nos proveen de información oportuna de que algo no funciona como se esperaba. Son oportunidades para profundizar en la causalidad del sistema y encontrar soluciones a sus problemas.
Hoy comenzaré con dos de los más triviales y comunes en cualquier organización: “elusión de las reglas” y “persiguiendo el objetivo equivocado”.
Elusión de las reglas
Ocurre cuando escribimos una regla para evitar un problema o para cumplir un objetivo, y las partes implicadas terminan eludiéndola. Esto sucede consciente o inconscientemente; tomamos atajos o explotamos debilidades de la regla para aparentemente “cumplirla”, pero sin seguir el espíritu con el que fue creada.
Perseguir el objetivo equivocado
Se da cuando definimos de manera inexacta los objetivos de los bucles de retroalimentación de nuestro sistema. Ocurre cuando la regla se confunde con el objetivo final. Normalmente, cuando utilizamos métricas proxy para un objetivo, nos quedamos en el proxy aunque nos alejemos del objetivo.
Ejemplo en el contexto del desarrollo de software.
Nos enteramos de que hacer testing es bueno, así que nos marcamos como objetivo tener una buena cobertura de tests. Para ello, configuramos las herramientas necesarias y bloqueamos automáticamente cualquier pull request que no supere el 80% de cobertura de tests.
Siendo un profesional que quiere llevar código a producción y cumplir la regla de la mejor forma posible, intentas alcanzar ese porcentaje de cobertura como puedas. Ya sea testeando cada método “getter” o “setter” o, incluso, añadiendo un par de métodos más que son fáciles de implementar y testear, que ahora no se necesitan pero en el futuro pueden ser útiles (sigh).
Como resultado, terminamos añadiendo más tests inútiles que mantener y hasta incrementamos la entropía tanto de los tests como del código, violando el mantra Yagni de XP, todo motivado por la nueva regla. Esta regla también desincentiva la vía negativa, ¿quién va a eliminar cualquier código que ya esté testeado si eso hace bajar el porcentaje de cobertura?
¿Qué ha pasado aquí?
En primer lugar, hemos confundido esfuerzo con resultado al definir lo que queremos medir. Por desconocimiento, creemos que hacer testing es el fin y que mágicamente hará nuestro software más mantenible o libre de fallos. Hemos caído en la trampa de “perseguir el objetivo equivocado”.
Por otro lado, al establecer una métrica proxy (porcentaje de cobertura de tests) sin educar sobre por qué tener buena cobertura es beneficioso, qué es un buen test y qué es una buena cobertura de tests, etc., estamos creando una barrera para el equipo para hacer su trabajo, y ellos intentarán cumplir (eludir) la regla para seguir adelante. Hemos caído en la trampa de “elusión de reglas”.
Modelando la trampa
Como ya es costumbre, hagamos un análisis mediante la dinámica de sistemas y modelemos la calidad de nuestra base de tests (Tests Quality).
¿De qué depende la calidad de un test?
Entender el objetivo de hacer tests: ¿Qué problema resuelve hacer tests? ¿Cuál es su fin último?
Saber qué es y cómo hacer un buen test: ¿Debemos hacerlos antes o después?.¿Cómo diseñar código testeable?
Tener tiempo suficiente: Tiempo para dedicar el esfuerzo requerido para hacer buenos tests, preparar las herramientas adecuadas, frameworks de testing, integración continua. Tener una cultura donde hacer un test no se vea como un trabajo extra, y donde la presión o incentivos no te lleven a escribir código sin testear.
Motivación: Para dedicar el esfuerzo requerido tanto en aprender todo lo anterior como en entender que los tests son también código que debemos mantener.
En resumen, sabiendo por qué y cómo hacer buenos tests, el resto depende de una relación entre el esfuerzo necesario para hacer un buen test (Time Needed to Write a Good Test) y el que realmente dedicamos (Time Spent per Test Development).
Si dedicamos el esfuerzo necesario para escribir buenos tests, estaremos mejorando la calidad de nuestra base de tests (Tests Quality). Hasta aquí todo obvio así que sigamos añadiendo complejidad.
Como vimos antes, el tiempo que realmente dedicamos a escribir un buen test (Time Spent per Test Development) depende, además de saber cómo hacerlo, de los incentivos y reglas del sistema. ¿Qué pasa si la empresa decide que debemos escribir un número objetivo de tests por semana?
El número de buenos tests por semana que podemos escribir (Good Tests per Week Capacity) es el resultado del tiempo que decidimos dedicar a escribir tests (Time for Writing Tests) y cuánto nos cuesta escribirlos (Time Required to Write Good Tests).
Si existe una regla (Tests per Week Goal) que nos incentiva a hacer más tests que nuestra capacidad real, terminaremos dedicando menos esfuerzo a cuidar la calidad de estos tests.
Nota en la simulación anterior como calidad media por test (línea amarilla) y la calidad de la base de tests (línea roja) van en picada cuando la presión nos lleva a eludir las reglas.
Por el contrario la calidad media por test (línea amarilla) y la calidad de la base de tests (línea roja) aumentan cuando somos capaces de cumplir el objetivo sin necesidad de buscar atajos.
Por supuesto, hay muchos factores que he dejado fuera de este modelo:
El esfuerzo que necesitas para escribir buenos tests (Time Needed to Write a Good Test) depende de cuánto invierta la organización en formar a sus miembros y en permitirles practicar estas técnicas deliberadamente.
El esfuerzo que terminamos dedicando a diseñar los tests (Time Allocated for Writing Tests per Week) depende en gran medida de la cultura de la organización.
Puedes jugar tú mismo con el diagrama y sus simulaciones en InsightsMaker e incluso clonarlo para adaptarlo a tu antojo.
Concluyendo
El objetivo de este artículo no es demostrar que la cobertura de tests es una herramienta inútil. Es una métrica valiosa si se usa correctamente pero debemos tener en cuenta que un código bien testeado tendrá una alta cobertura de tests, pero un código con una alta cobertura de tests no siempre está bien testeado.

Marcarnos un objetivo extremo sobre una métrica que no es el fin último sino solo un proxy hacia este puede llevarnos a buscar atajos cuyos efectos generan otros problemas.
“Me pagan por escribir código que funciona, no por test, así que mi filosofía es probar lo mínimo posible para alcanzar un nivel dado de confianza.”
Kent Beck
Fuente: Stackoverflow answer
“Si regularmente mides la cobertura de tests de todo tu código, te animaría a mirar más las tendencias que los números absolutos. He visto cómo los objetivos arbitrarios de cobertura llevan a las personas a preferir testear solo lo que es fácil de probar. Las personas pueden evitar hacer un refactor porque introducirá nuevas líneas de código y reducirá su cobertura total. He visto tests escritos con sin o muy débiles aserciones solo para mejorar los números de cobertura.”
Emily Bache
Fuente: Using Coverage to Improve Your Unit Tests
Se me ocurren muchos otros ejemplos de nuestra industria. Te invito a que juegues por tu cuenta e imagines los efectos no deseados que provocarían si no se tienen en cuenta el por qué de las siguientes potenciales reglas:
Número de bugs solucionados por semana
Número de postmortems por mes
Número de puntos por sprint
Toda historia de usuario en el formato: Como (rol) quiero (algo) para poder (beneficio).
Número de funcionalidades por sprint.
Número de deploys por semana.
Hay que desplegar los viernes 😎
Presupuesto para formación; si no se consume, se reduce.
El mundo está lleno de buenas intenciones, pero no abunda el pensamiento de segundo orden, por lo que terminamos cayendo en estas trampas que nos pone la complejidad.
Lecturas recomendadas
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. (este artículo)
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.
Exclusión competitiva: La trampa del «rockstar developer».
Resistencia a las políticas: La trampa de los atajos y el falso dilema entre calidad y velocidad.
Tragedia de los recursos comunes: La tragedia del código compartido.
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.