wandres.dev
NIVEL DIOS · Síntesis y el método de depuración

El método completo de depuración

Las seis fases del procedimiento que convierte la depuración en un proceso repetible, con el criterio de avance de cada una y los errores que hacen perder más tiempo.

⏱ 20 min

Todo lo anterior de este track son herramientas. Esta lección es el procedimiento que decide cuál usar y cuándo, y es lo único que no caduca: los paneles cambian de sitio, las APIs se renuevan, los atajos se mueven, y el método de reducir un problema hasta que solo queda una explicación posible es el mismo que era hace veinte años y el que será dentro de otros veinte. Si de todo el track hubiera que conservar una lección, es esta.

🎯 Al terminar esta lección sabrás
  • Ejecutar las seis fases del método en orden y reconocer el criterio de salida de cada una.
  • Convertir un síntoma reportado en una observación utilizable.
  • Formular hipótesis falsables y diseñar el experimento que las mata.
  • Reconocer los cinco errores de método que más tiempo consumen.

Las seis fases

Fase 1: observar. Convertir lo que te cuentan en lo que ves. Criterio de salida: puedes describir el síntoma sin usar ninguna palabra causal. No “no guarda”, sino “sale una petición que devuelve estado de éxito y la tabla sigue mostrando el valor anterior”.

Fase 2: reproducir. Conseguir provocarlo tú, a voluntad. Criterio de salida: una secuencia concreta que lo produce, escrita. Si no puedes reproducirlo, todo lo demás es adivinación, y la fase pasa a ser conseguir la reproducción, no arreglar el bug.

Fase 3: reducir. Quitar todo lo que no sea necesario para que ocurra. Criterio de salida: cada elemento que queda es imprescindible; si quitas cualquiera, deja de ocurrir.

Fase 4: aislar. Bisecar el espacio de causas hasta señalar el punto exacto. Criterio de salida: sabes qué línea, qué recurso o qué configuración lo produce.

Fase 5: explicar. Entender por qué ese punto produce ese síntoma. Criterio de salida: puedes predecir el comportamiento en un caso que todavía no has probado, y aciertas.

Fase 6: corregir y verificar. Arreglar, y comprobar que el arreglo funciona por la razón que crees. Criterio de salida: el síntoma desaparece y vuelve si revocas el arreglo.

⚠️
Cuidado

Saltarse la fase cinco es el atajo más tentador y el más caro. Cuando el síntoma desaparece tras un cambio que no entiendes del todo, es muy probable que hayas movido el problema en lugar de arreglarlo: lo has escondido tras un cambio de tiempos, o has tapado uno de sus tres caminos. Vuelve semanas después con otra forma y sin relación aparente con nada.

Las fases en detalle

Fase 1: observar sin interpretar

Lo que llega en un ticket nunca es un síntoma: es la interpretación que alguien hizo de un síntoma. “El botón está roto” puede ser cuatro bugs de tres familias distintas.

El trabajo de esta fase es sustituir cada palabra causal por una observación. Las preguntas que lo consiguen son cinco.

¿Qué esperabas ver y qué viste? Separar la expectativa del hecho.

¿Qué pasos exactos diste? Con detalle incómodo.

¿Pasa siempre o a veces? La intermitencia cambia todo el diagnóstico.

¿Desde cuándo? Si funcionaba antes, hay un cambio que lo rompió, y encontrarlo es más rápido que entenderlo.

¿A quién le pasa? Uno, algunos o todos. Si es a algunos, la diferencia entre ellos y el resto es el diagnóstico.

Fase 2: reproducir, y qué hacer si no puedes

Sin reproducción no hay depuración, así que cuando falla, la fase se convierte en conseguirla. Cuatro palancas, en orden.

Igualar el entorno. Navegador, versión, tamaño de ventana, sistema, extensiones. La ventana de incógnito descarta extensiones y estado persistente en cinco segundos.

Igualar el estado. El almacenamiento de esa persona, sus datos, sus permisos, su configuración. Una cuenta con sus datos reproduce muchos bugs que una cuenta limpia no.

Igualar las condiciones. Red lenta, CPU lenta. Una parte enorme de los bugs no reproducibles son carreras que solo se ven con las asimetrías exageradas.

Conseguir la evidencia. Si nada funciona, un fichero de sesión de red, una grabación de pantalla, o instrumentación desplegada que registre lo que pasa cuando vuelva a ocurrir.

Fase 3 y 4: reducir y aislar

La reducción es el paso que más gente se salta y el que más tiempo ahorra. Consiste en quitar cosas mientras el fallo siga ocurriendo: componentes, datos, dependencias, CSS, código. Cada cosa que quitas y el fallo persiste es una parte del espacio de búsqueda eliminada.

Cuando termina, tienes un caso mínimo, que tiene tres propiedades muy valiosas: es rápido de ejecutar, es fácil de razonar, y es compartible. Un caso mínimo es lo que convierte “nuestra aplicación tiene un problema” en un informe que un tercero puede atender.

El aislamiento es bisección, y tiene lección propia en este mismo nivel.

Fase 5: explicar

Una explicación válida cumple tres condiciones, y conviene comprobarlas antes de dar el bug por entendido.

Explica el síntoma completo, no solo una parte. Si tu teoría explica por qué falla pero no por qué falla solo a veces, está incompleta.

Explica por qué funcionaba antes, si funcionaba.

Predice algo que todavía no has comprobado. Es la condición decisiva. Si tu explicación es correcta, debe implicar que en tal otra situación pasará tal otra cosa. Comprobarlo cuesta un minuto y separa una explicación de una coincidencia.

// Un cuaderno de sesion: registrar hipotesis, experimentos y resultados
(() => {
  const CLAVE = '__cuaderno_depuracion';
  const leer = () => JSON.parse(localStorage.getItem(CLAVE) || '[]');
  const escribir = (d) => localStorage.setItem(CLAVE, JSON.stringify(d));

  window.sesion = {
    sintoma(texto) {
      escribir([{ tipo: 'sintoma', texto, cuando: Date.now() }]);
      console.log('Sesion iniciada. Sintoma:', texto);
    },
    hipotesis(texto, prediccion) {
      const d = leer();
      d.push({ tipo: 'hipotesis', texto, prediccion, estado: 'abierta', cuando: Date.now() });
      escribir(d);
      console.log('H' + d.filter(x => x.tipo === 'hipotesis').length + ':', texto);
      console.log('  predice:', prediccion);
    },
    resultado(indice, confirmada, nota = '') {
      const d = leer();
      const hs = d.filter(x => x.tipo === 'hipotesis');
      if (!hs[indice - 1]) return console.warn('No existe la hipotesis', indice);
      hs[indice - 1].estado = confirmada ? 'confirmada' : 'descartada';
      hs[indice - 1].nota = nota;
      escribir(d);
      console.log('H' + indice, confirmada ? 'CONFIRMADA' : 'descartada', nota);
    },
    ver() {
      const d = leer();
      console.log('Sintoma:', d.find(x => x.tipo === 'sintoma')?.texto);
      console.table(d.filter(x => x.tipo === 'hipotesis').map((h, i) => ({
        n: i + 1, hipotesis: h.texto.slice(0, 60), predice: h.prediccion.slice(0, 40),
        estado: h.estado, nota: h.nota || ''
      })));
    },
    limpiar() { localStorage.removeItem(CLAVE); console.log('Cuaderno vaciado.'); }
  };

  console.log('Cuaderno listo: sesion.sintoma(), sesion.hipotesis(texto, prediccion),');
  console.log('sesion.resultado(n, true/false, nota), sesion.ver()');
})();

Ese cuaderno parece burocracia y resuelve el problema más real de una sesión larga: a las dos horas no recuerdas qué has descartado, y acabas repitiendo comprobaciones. El campo de predicción es el que obliga a formular hipótesis falsables, que es donde está el valor.

Los cinco errores que más tiempo consumen

Empezar a arreglar antes de entender. Cambiar cosas a ver si el síntoma desaparece. Cada cambio añade una variable y a los diez cambios ya no sabes en qué estado está el sistema.

Cambiar dos cosas a la vez. Si el síntoma desaparece, no sabes cuál lo arregló, y probablemente una de las dos era innecesaria y ha introducido algo nuevo.

Confiar en la memoria. Sobre qué has probado, qué has descartado y qué estado tenía la aplicación. A la segunda hora, la memoria miente.

No volver al estado limpio. Después de veinte modificaciones en el panel, la página que tienes delante no es la de nadie, y las observaciones sobre ella no valen.

Buscar donde es cómodo en lugar de donde es probable. Todo el mundo mira primero el código que conoce. El bug está estadísticamente donde nadie ha mirado.

La velocidad al depurar no viene de saber más sino de descartar más rápido, y descartar es una decisión de coste

Si observas a alguien que depura muy rápido, lo que llama la atención no es que sepa dónde está el bug: es que hace muchas comprobaciones muy baratas en muy poco tiempo. Abre incógnito, mira si el nodo existe, filtra la red, comprueba la respuesta, activa el throttling, mira si hay errores en la consola. Ninguna de esas comprobaciones encuentra el bug; todas eliminan familias enteras de causas, y cada una cuesta segundos. En cinco minutos ha reducido el espacio de veinte hipótesis a dos, y ahí es donde invierte tiempo de verdad. Alguien más lento no es menos inteligente: elige mal el orden. Empieza por la hipótesis que le parece más probable, que suele ser la más cara de comprobar, invierte cuarenta minutos en ella, y si se equivoca ha gastado cuarenta minutos sin reducir nada. La formulación explícita del principio es sencilla y merece interiorizarse: el valor de una comprobación es la cantidad de espacio que elimina dividida por lo que cuesta hacerla, y la intuición sobre probabilidad no entra en esa fórmula. Una comprobación que elimina la mitad del espacio y cuesta diez segundos es mejor que una que elimina el ochenta por ciento y cuesta media hora, aunque tu instinto diga que el problema está en el segundo sitio. De ahí salen dos hábitos concretos que se pueden adoptar hoy. El primero: antes de invertir más de cinco minutos en una hipótesis, pregúntate si hay alguna comprobación de treinta segundos que no hayas hecho. Casi siempre la hay, y casi siempre alguna de ellas cambia la dirección de la investigación. El segundo: mantén una lista mental de tus comprobaciones baratas y ejecútalas siempre al principio, en el mismo orden, como un piloto que recorre su lista antes de despegar. Incógnito, consola, red, estado, condiciones. Cinco comprobaciones, dos minutos, y una fracción muy grande de los bugs queda acotada a una familia antes de que hayas leído una sola línea de código.