El método: reproducir, reducir, aislar, confirmar
El procedimiento de cuatro fases que convierte la depuración en un proceso repetible, con la bisección como motor y la hipótesis falsable como criterio de avance.
Las herramientas no depuran; las usa alguien que ya sabe qué está buscando. Sin un método, un panel potente solo consigue que te pierdas más rápido y con mejores gráficos. Lo que sigue es el procedimiento que subyace a toda depuración eficaz, se llame como se llame en cada equipo: cuatro fases, un criterio de avance y una regla de parada. El resto de esta guía es el detalle de cómo se ejecuta cada fase con las herramientas de Chrome.
- Ejecutar las cuatro fases del método en orden y saber cuándo una fase está terminada.
- Formular una hipótesis falsable y diseñar el experimento de una sola variable que la contrasta.
- Aplicar la bisección a un espacio de búsqueda de código, de tiempo, de datos o de configuración.
- Detectar los tres antipatrones que hacen que una sesión de depuración no converja.
Las cuatro fases del método
Fase 1: reproducir de forma fiable
Un bug que no sabes provocar no lo puedes arreglar, solo puedes conjeturar sobre él. La primera fase termina cuando puedes decir esta frase con precisión: “haciendo esto, esto y esto, falla siempre”.
La palabra que importa es siempre. Un fallo que ocurre siete de cada diez veces no está reproducido; está observado. Y la diferencia práctica es enorme, porque con reproducción al setenta por ciento no puedes saber si un cambio arregló algo o si tuviste suerte tres veces seguidas.
Cuando la reproducción es intermitente, el trabajo de esta fase es convertirla en determinista amplificando la variable sospechosa. Si sospechas de una carrera con la red, aplica el throttling más agresivo: lo que era una ventana de veinte milisegundos pasa a ser una de dos segundos y el fallo se vuelve constante. Si sospechas de una carrera con el renderizado, aplica throttling de CPU. Si sospechas de un problema de tamaño de datos, multiplica los datos. Si sospechas de estado acumulado, ejecuta la interacción cincuenta veces seguidas con un bucle desde la consola.
Amplificar no es hacer trampa: es reducir el ruido para que la señal se vea. El fallo que aparece con red lenta también aparece con red rápida, solo que una vez de cada cien.
Fase 2: reducir el caso
La reproducción inicial casi siempre es enorme: “entro, hago login, voy a la lista, filtro por fecha, abro el tercero, edito y guardo”. Esa secuencia contiene cientos de líneas de código irrelevantes. La segunda fase consiste en quitar pasos y componentes hasta que el fallo esté a punto de desaparecer.
La técnica es la bisección, y su valor es logarítmico: cada corte a la mitad reduce el espacio de búsqueda a la mitad, así que veinte cortes acotan un millón de posibilidades. Se puede bisecar en cuatro ejes distintos y conviene tenerlos todos disponibles.
Bisección en el código: comentar la mitad de un módulo, desactivar la mitad de los componentes, poner un breakpoint a mitad de la función y ver si el estado ya está corrupto ahí.
Bisección en el tiempo: si el bug ocurre en algún punto de una secuencia larga, un breakpoint en la mitad divide la secuencia en dos, y la pregunta “¿el estado ya está mal aquí?” descarta una de ellas entera.
Bisección en los datos: si falla con mil registros, prueba con quinientos, con cien, con uno. El registro que rompe suele tener algo peculiar, y el peculiar suele ser un null, una cadena vacía, un carácter no latino o una fecha en el límite de un huso.
Bisección en la configuración: incógnito frente a perfil normal, con extensiones y sin ellas, con service worker y sin él, con caché y sin caché. Cada una de esas parejas parte el espacio en dos.
flowchart LR
a[Caso completo que falla] --> b{Quitar la mitad}
b -->|Sigue fallando| c[La mitad quitada era irrelevante]
b -->|Deja de fallar| d[La causa estaba en lo quitado]
c --> b
d --> e[Devolver la mitad y quitar un cuarto]
e --> b
b -->|Caso minimo| f[Hipotesis concreta]
style a fill:#f38ba8,color:#11111b
style c fill:#89b4fa,color:#11111b
style d fill:#89b4fa,color:#11111b
style f fill:#a6e3a1,color:#11111bLa fase termina cuando quitar cualquier cosa más hace que el fallo desaparezca. En ese punto tienes un caso mínimo, y un caso mínimo suele contener la respuesta a la vista.
Fase 3: aislar la causa con hipótesis falsables
Aquí es donde entra la parte que más cuesta y más rinde. Una hipótesis útil no es “creo que hay algo raro con el estado”. Una hipótesis útil tiene esta forma:
Si X es la causa, entonces al observar Y debería ver Z. Si veo otra cosa, X queda descartada.
El requisito es que la hipótesis pueda fallar. “Creo que es un problema de timing” no se puede falsar y por tanto no dirige ninguna observación. “Creo que el componente lee el estado antes de que la respuesta llegue, así que con un breakpoint en el render debería ver data como undefined en la primera pasada y con contenido en la segunda” sí se puede falsar, y además ya te dice dónde poner el breakpoint.
El experimento que contrasta una hipótesis tiene que cambiar una sola variable. La tentación de cambiar tres cosas a la vez porque “seguro que alguna funciona” es fortísima bajo presión, y garantiza que si funciona no sabrás por qué. Si tres cambios arreglan el bug, tienes tres candidatos y cero conocimiento; el bug volverá dentro de dos semanas por otra puerta.
Una hipótesis bien escrita casi siempre nombra la herramienta que la contrasta. “Debería ver la respuesta sin el campo” apunta a Network. “Debería ver la función ejecutándose dos veces” apunta a un breakpoint o a console.count. “Debería ver la regla perdiendo la cascada” apunta al panel de estilos. Si tu hipótesis no sugiere ninguna herramienta, todavía es demasiado vaga.
Fase 4: confirmar el arreglo y por qué funciona
La cuarta fase tiene dos comprobaciones, y la segunda se salta casi siempre.
La primera es obvia: aplicar el cambio y verificar que el caso mínimo ya no falla, partiendo de un estado limpio y con el caso completo, no solo con el reducido.
La segunda es revertir el cambio y comprobar que el fallo vuelve. Suena redundante y no lo es: es la única prueba de que tu arreglo es la causa del arreglo y no una coincidencia con un cambio de estado, una recarga de caché o un despliegue ajeno. Cuesta treinta segundos y es lo que separa “lo he arreglado” de “ha dejado de pasar”.
Y hay una tercera comprobación, la más importante de todas, que no es técnica sino de comprensión: si no puedes explicar por qué el arreglo funciona, no lo has arreglado. Un cambio que hace desaparecer el síntoma sin que sepas explicar el mecanismo es, casi siempre, un cambio que ha movido el problema a otro sitio o que ha alterado un tiempo lo justo para que la carrera se gane. Volverá.
Las cuatro fases están ordenadas por una razón que no es estética: cada fase reduce el coste de la siguiente en un factor, no en una cantidad. Si te saltas la reproducción fiable, la reducción se vuelve imposible porque no puedes distinguir un cambio que arregla de un intento afortunado. Si te saltas la reducción, la fase de hipótesis opera sobre un espacio cien veces mayor y necesitas cien veces más experimentos. Si te saltas la hipótesis falsable y vas directo a cambiar cosas, no estás depurando: estás haciendo una búsqueda aleatoria sobre un espacio que no has acotado, y ese es literalmente el peor algoritmo conocido. Lo perverso es que saltarse fases se siente más rápido, porque las fases uno y dos no producen ningún progreso visible: no arreglan nada, solo entienden. Bajo presión, con alguien mirando por encima del hombro, la tentación de empezar a cambiar código a los dos minutos es casi irresistible, y es exactamente lo que convierte un bug de veinte minutos en uno de una tarde. La disciplina no consiste en ser más listo; consiste en aguantar los primeros diez minutos sin tocar nada mientras acotas, sabiendo que se sienten improductivos y que son los que deciden el resultado.
Los tres antipatrones que impiden converger
Cambiar y rezar. Modificar algo, recargar, mirar si va, repetir. Sin hipótesis, cada iteración es independiente de la anterior y no acumula conocimiento. Reconocible porque llevas veinte cambios y no sabrías decir qué has aprendido con ninguno.
La búsqueda del culpable conocido. Convencerte al minuto uno de que el problema es la librería que ya te dio problemas el mes pasado, y gastar cuarenta minutos confirmando el prejuicio. La cura es preguntarse “¿qué observaría si mi sospecha fuera falsa?” y salir a buscar precisamente eso.
La instrumentación infinita. Añadir trazas, recargar, no ver lo que esperabas, añadir más trazas, recargar. Cada iteración cuesta una recarga completa y aporta un dato. Un breakpoint bien puesto da acceso a todo el estado del programa en ese instante sin recargar ni una vez, que es la diferencia entre un dato por minuto y todos los datos de golpe. Este antipatrón es el que ataca directamente el nivel de los breakpoints sin línea, y es probablemente el cambio de hábito más rentable de esta guía entera.
Coge el último bug que arreglaste y reescríbelo según el método: cuál era la reproducción exacta, cuál el caso mínimo, qué hipótesis formulaste y con qué observación la confirmaste. Casi con seguridad descubrirás que te saltaste la fase dos y que la hipótesis nunca llegó a estar escrita. Ese hueco es donde se fue el tiempo.