Reproducir las condiciones del usuario que reporta el bug
Combinar throttling, bloqueo, overrides y emulación para recrear el entorno donde algo falla, con el método de reducción de variables que lo hace repetible.
La frase más frecuente y menos útil de cualquier equipo es “a mí me funciona”. Casi siempre es cierta y casi nunca aporta nada, porque el entorno del que desarrolla es el menos representativo que existe. Reproducir el entorno del usuario que reporta el problema es una habilidad concreta con herramientas concretas, y es lo que convierte un informe de bug irreproducible en uno que se arregla en una tarde.
- Enumerar las variables de entorno que pueden diferir y en qué orden probarlas.
- Combinar las herramientas de simulación para recrear un escenario concreto.
- Aplicar la reducción de variables para aislar cuál de ellas provoca el fallo.
- Redactar la información que hay que pedir para que un informe sea reproducible.
Las variables que pueden diferir
Cuando algo funciona en tu máquina y no en la de otro, hay una lista finita de diferencias posibles. Merece la pena tenerla escrita porque bajo presión se olvida la mitad.
El navegador y su versión. Una versión anterior puede no tener la propiedad de CSS o la API que estás usando.
Las extensiones. Bloqueadores de contenido, gestores de contraseñas, herramientas de privacidad. Cortan dominios, inyectan código y modifican el DOM.
La red. Latencia, ancho de banda, filtros corporativos, proxies con inspección.
El dispositivo. CPU más lenta, menos memoria, pantalla de otra densidad, otro sistema de entrada.
El tamaño de ventana. Rama distinta de tus media queries.
Las preferencias del sistema. Modo oscuro, movimiento reducido, colores forzados, tamaño de fuente aumentado, idioma y zona horaria.
El estado persistente. Cookies antiguas, almacenamiento local con formato de una versión anterior, service worker de un despliegue viejo.
Los datos. Una cuenta con diez mil registros, con caracteres no latinos, con campos vacíos que en tu entorno de pruebas nunca están vacíos.
El orden de comprobación
Ordenado por coste de comprobación y por probabilidad, que en este caso casi coinciden.
Uno: incógnito. Descarta extensiones y estado persistente de golpe, y cuesta dos segundos. Si en incógnito falla igual, has eliminado dos categorías enteras.
Dos: el tamaño de ventana. Emula el dispositivo que el usuario dice tener, con dimensiones explícitas. Muchas diferencias visuales se explican aquí.
Tres: las preferencias. Activa el modo oscuro, el movimiento reducido, los colores forzados. Es rápido y descarta una categoría que nadie prueba.
Cuatro: la red y la CPU. Aplica un perfil lento en ambas. Convierte carreras intermitentes en deterministas.
Cinco: los datos. Si tienes acceso, reproduce con los datos del usuario, o con datos del mismo tamaño y forma.
Seis: la versión del navegador. La más cara de comprobar y la que menos veces es la causa, aunque cuando lo es, no hay ninguna otra forma de descubrirlo.
Recrear un escenario completo
Un ejemplo de combinación, para el caso más frecuente: un usuario de móvil con conexión mediocre reporta que una pantalla se queda cargando.
Abre una ventana de incógnito.
Activa la emulación de dispositivo con las dimensiones y la densidad del suyo.
Aplica un perfil de red con la latencia de una conexión celular y un throttling de CPU de cuatro veces.
Vacía el almacenamiento del sitio y desregistra cualquier service worker, para partir del estado de un usuario nuevo.
Reproduce el flujo, con el panel de red grabando y con la conservación del registro activada.
Si con eso el fallo aparece, ya tienes reproducción y el resto es depuración normal. Si no aparece, sigue quedando la lista: el usuario puede tener un bloqueador cortando un dominio, o unos datos distintos, o una versión anterior.
Para el caso del bloqueador, la simulación es directa: bloquea los dominios que un bloqueador típico cortaría —analítica, publicidad, seguimiento— y vuelve a probar. Ese experimento sorprende con frecuencia, porque muchas aplicaciones tienen dependencias funcionales de scripts que creían decorativos.
La reducción de variables
Cuando el fallo se reproduce con cinco condiciones aplicadas a la vez, no sabes cuál es la responsable. La segunda mitad del método es quitarlas una por una.
Quita la condición que crees menos probable y vuelve a probar. Si sigue fallando, esa no era; déjala fuera. Si deja de fallar, esa era necesaria; devuélvela.
Al terminar tienes el conjunto mínimo de condiciones que reproducen el fallo, y ese conjunto es el diagnóstico. “Falla solo con CPU ralentizada” apunta a una carrera. “Falla solo con el almacenamiento vacío” apunta a un valor que se asume presente. “Falla solo por debajo de cierto ancho” apunta a una rama de layout. “Falla solo con el bloqueador” apunta a una dependencia no declarada.
Cada una de esas frases es un bug distinto con un arreglo distinto, y ninguna se puede formular sin haber reducido.
Reproducir con cinco condiciones y arreglar sin reducir es un error común y caro: arreglas algo que hace desaparecer el síntoma en esa combinación concreta, sin saber cuál era la causa, y el bug vuelve con otra combinación. La reducción no es un lujo metodológico; es lo que distingue arreglar de tapar.
Qué pedir en un informe
La consecuencia práctica de todo lo anterior es que se puede pedir por adelantado la información que hace un informe reproducible. Una plantilla corta que cubre la mayoría de los casos.
Qué navegador y qué versión exacta. Qué sistema operativo. Qué dispositivo si es móvil.
Si ocurre también en una ventana de incógnito.
Si ocurre siempre o a veces, y en el segundo caso, con qué frecuencia aproximada.
Qué pasos exactos, desde una pantalla conocida, y no una descripción del objetivo.
Qué esperaba ver y qué vio, sin usar palabras causales.
Una captura de la pantalla y, si es posible, de la consola con los errores.
Ese último punto tiene un truco que merece conocerse: en una consola con la conservación del registro activada, el menú contextual ofrece guardar todo el contenido en un fichero, y lo mismo el panel de red con su exportación. Pedir esos dos ficheros en lugar de una captura convierte un informe vago en un conjunto de datos.
Hay una experiencia que se repite lo suficiente como para haberse convertido en una regla informal en muchos equipos: el tiempo que se tarda en conseguir una reproducción fiable es normalmente varias veces mayor que el tiempo que se tarda en arreglar el bug una vez reproducido. Eso significa que el trabajo real de depurar no está en la parte que parece técnica, sino en la parte administrativa y tediosa de averiguar en qué condiciones ocurre. Y tiene tres consecuencias que conviene interiorizar porque van contra el instinto. La primera: cuando alguien te pasa un bug irreproducible, la pregunta correcta no es “cómo lo arreglo” sino “qué variable no estoy replicando”, y esa pregunta se responde con la lista de esta lección, no leyendo código. Pasar dos horas leyendo el módulo sospechoso sin haber reproducido es casi siempre tiempo perdido, porque sin reproducción no puedes ni confirmar tu hipótesis ni verificar tu arreglo. La segunda: el conjunto mínimo de condiciones que reproducen el fallo suele contener el diagnóstico entero. Cuando reduces y descubres que solo falla con la CPU ralentizada, ya sabes que es una carrera aunque no sepas todavía entre qué y qué; cuando descubres que solo falla con el almacenamiento vacío, ya sabes que hay una lectura que asume un valor que puede no estar. El trabajo de reducir es el trabajo de diagnosticar, no un preámbulo. Y la tercera, que es la más rentable a largo plazo: cada reproducción que consigues es un test que puedes escribir. Un bug que has reducido a “falla con estos datos y esta configuración” se convierte en un caso de prueba automatizado casi mecánicamente, y ese test impide que vuelva. Los equipos que hacen esto acumulan una suite que refleja los fallos reales de su producto, que es infinitamente más valiosa que una suite escrita a partir de lo que alguien imaginó que podía fallar.