From n00b to ZeroCool / Origen
Debugging: el arte oscuro de hablar con tus errores (sin perder la cabeza)
Guía práctica de debugging: reproduce, aísla, mide, usa logs/breakpoints y cierra bugs con método. Incluye ejemplos y checklist final.
Lo que vale la pena leer aquí
La escena: 11:48 p.m. El deploy “rápido” ya se convirtió en evento. Te entra un WhatsApp del cliente: “Oye, ya no carga el checkout”. Tu laptop ya pidió retiro hace dos años; el ventilador suena como dron y tú quieres creer que es “el internet de Telmex”.
La escena: 11:48 p.m. El deploy “rápido” ya se convirtió en evento. Te entra un WhatsApp del cliente: “Oye, ya no carga el checkout”. Tu laptop ya pidió retiro hace dos años; el ventilador suena como dron y tú quieres creer que es “el internet de Telmex”.
Abres consola y aparece un error que juras que no existía hace una hora. Ahí empieza el oficio de verdad: debugging. No es magia. Es una conversación incómoda con el sistema hasta que te suelta la neta.
Qué te vas a llevar
- Cómo reproducir un bug sin depender de la suerte.
- Cómo aislar la causa con hipótesis (sin mover 30 cosas a la vez).
- Cuándo usar logs vs breakpoints vs tracing.
- Un flujo para cerrar bugs: del “ni idea” al fix con confianza.
- Errores típicos (de junior, de senior y de “traigo deadline”).
Contexto práctico: el bug no es tu enemigo, es tu señal
Debugear es traducir un síntoma (“no carga”) a una causa (“esa promesa nunca resolvió”, “ese query viene con null”, “este header cambió en production”).
El bug no suele ser un monstruo paranormal. Casi siempre cae en una de estas categorías:
- Estado: valores fuera de lo esperado (null, undefined, cadena vacía, cache vieja).
- Tiempo: carreras, async, timeouts, “a veces sí, a veces no”.
- Entrada: datos reales (Excel raro, acentos, fechas) vs datos bonitos de pruebas.
- Entorno: production no es tu laptop (variables, versiones, permisos, CORS, TLS).
Decisión clave: cuando veas un bug, no te lances a “arreglar”. Primero pregúntate: ¿qué evidencia necesito para saber qué está pasando? Esa pregunta te ahorra horas y rollback vergonzoso.
Guía principal: un workflow de debugging que sí aguanta la vida real
1) Congela el síntoma (y escríbelo como ticket decente)
“Truena” no sirve. Lo útil es:
- Qué estabas haciendo
- Qué esperabas
- Qué pasó
- Error exacto (mensaje + stack trace)
- Cuándo pasa (siempre / a veces / solo con X usuario)
Ejemplo real (frontend):
“En /checkout, al darle ‘Pagar’ con tarjeta se queda cargando. En consola:
TypeError: Cannot read properties of undefined (reading 'id')enpayment.ts:88. Solo pasa con usuarios nuevos (sin dirección guardada).”
Si estás en soporte o sysadmin: mete timestamp y request id si existe. Si no existe… ya te cayó una tarea chiquita que vale oro: generar uno.
2) Reproduce. Si no lo reproduces, estás adivinando
Reproducir es el superpoder. Sin eso, cada cambio es “a ver si ahora sí”.
Cosas que sí jalan:
- Pide pasos exactos al usuario. Sí, con paciencia: “¿qué navegador? ¿qué botón? ¿qué campo?”
- Revisa datos del caso: usuario, cuenta, payload, headers.
- Arma un fixture local: copia el JSON real (sanitizado) y guárdalo.
Ejemplo (backend Node/Express): guardas el body que llega a /api/pay y lo pruebas local.
# Ejemplo con curl (ajusta tu endpoint)
curl -X POST http://localhost:3000/api/pay \
-H 'content-type: application/json' \
-d @fixtures/pay-falla-usuario-nuevo.json
Escena real de LATAM: el bug “solo pasa cuando pagan desde OXXO”. Traducción: el usuario va en datos, la señal se va, el request se corta, el frontend reintenta y terminas duplicando la orden. Debugging también es pensar como usuario fuera de tu wifi.
3) Reduce el problema: del sistema entero a una línea sospechosa
Regla de oro: si cambias 5 cosas, no sabes cuál pegó.
Tácticas:
- Divide y vencerás: ¿es frontend, API, DB, tercero?
- Binary search mental: ¿dónde todavía funciona y dónde ya no?
- Caso mínimo: el input más pequeño que rompe.
Ejemplo: si falla “con usuarios nuevos”, tu caso mínimo es “usuario sin dirección”. Ya no es “checkout”, es “checkout sin dirección”. Y de pronto el bug deja de ser niebla.
4) Haz hipótesis… y mátalas con evidencia
Debugging sin hipótesis es pasearte por el repo con fe.
Plantilla express:
- Hipótesis: “
user.addressa veces es undefined” - Evidencia: “ver
userjusto antes de usaraddress.id” - Experimento: “agrego log + corro el fixture”
Ojo con el ego: que tu hipótesis suene elegante no la hace cierta. El bug no te debe nada.
5) Logs: el chismoso confiable (si los haces bien)
Logs útiles:
- Traen contexto: request id, user id (sin PII), endpoint, versión.
- Manejan niveles: info/warn/error.
- No revientan producción con 200 KB por request.
Ejemplo (Node):
// pseudo-logger
logger.info({ requestId, userId, hasAddress: !!user?.address }, 'checkout: before payment');
En SQL: loguea counts y la query sin escupir datos sensibles. Si hay tarjetas, tokens, passwords, headers de auth: eso ni se imprime, ni “tantito”.
Decisión práctica: si tu app no tiene request id, pon uno aunque sea con UUID por request. El día que traigas 10 servicios y un bug en production, te vas a dar las gracias.
6) Breakpoints: cuando necesitas ver el estado en vivo
Los breakpoints sirven cuando el bug vive en la lógica, no en la infraestructura.
Tips que evitan perder la noche:
- Usa conditional breakpoints (“solo si
user.addresses undefined”). - Usa watch para variables clave.
- No te cases con el “step over” infinito: brinca a la función sospechosa.
Ejemplo de condición (JS/TS en Chrome/VS Code):
- Breakpoint donde se usa
address.id - Condición:
user && !user.address
Te ahorra ver 50 iteraciones sanas antes de que falle la buena.

7) Git bisect: el exorcismo para “ayer funcionaba”
Cuando alguien dice “antes jalaba” (y tú no fuiste), lo más sano es aislar el commit culpable.
git bisect start
git bisect bad # tu commit actual (falla)
git bisect good <hash-o-tag> # una versión donde sí funcionaba
# Git te va moviendo entre commits; tú pruebas y marcas good/bad
Esto vale oro cuando hubo un merge gigantesco o una pull request “de viernes” que se fue a production sin suficiente review.
8) Asegura el fix: prueba + guardrail
Arreglar no es “ya no truena”. Es:
- ¿Cubre el caso mínimo que reproducía?
- ¿No rompe el flujo feliz?
- ¿Deja una prueba o una validación para que no regrese?
Ejemplo (TypeScript): en vez de hacer user.address!.id (el “cállate” del compilador), valida y maneja.
if (!user.address) {
throw new Error('User has no address: cannot proceed to payment');
}
const addressId = user.address.id;
Mejor todavía: en UI, muestra un mensaje accionable (“Agrega tu dirección para continuar”) y evita que el usuario choque contra un error opaco.
9) Cierra el círculo: mini postmortem (aunque seas tú solo)
No necesitas un doc eterno. Con que respondas:
- ¿Qué causó el bug?
- ¿Por qué no lo vimos antes?
- ¿Qué cambio lo hace menos probable?
Ejemplos reales:
- Validación de datos en backend.
- Test para “usuario sin dirección”.
- Métrica de errores por endpoint.
Screenshots sugeridos
- Consola con stack trace y la línea donde falla.
- Panel de Network (request/response) con status y payload.
- Breakpoint condicional en VS Code/DevTools.
- Vista de logs filtrada por request id.
- Resultado de
git bisectmostrando el commit culpable.
Errores comunes (y cómo salir del hoyo)
-
Cambiar cosas “a ver si”
- Salida: una hipótesis, un experimento, un cambio.
-
Debuggear con datos falsos (tu seed bonito) cuando el bug vive en datos reales
- Salida: fixtures con payload real sanitizado.
-
Creer que production es tu laptop
- Salida: imprime versiones, env vars relevantes, flags, y revisa diferencias.
-
Silenciar el error (
try/catchvacío,return nullporque sí)- Salida: maneja con mensaje y contexto; si degradas, deja evidencia.
-
No dejar rastro (sin test, sin nota, sin contexto)
- Salida: prueba o al menos un ticket/nota con el caso mínimo.
Momento muy de jale: ya casi sales, tu jefe pide “un cambiecito en corto” y alguien suelta el clásico “nomás súbelo rápido”. En ese minuto nacen los hotfix que te persiguen tres sprints.
Si vas a hotfixear, que sea con procedimiento: reproduce, fix mínimo, monitorea, y luego pagas la deuda con calma (refactor, tests, mejor observability). Si no, el siguiente deploy te cobra intereses.

Checklist final (para debugear con método)
- Puedo describir el bug con pasos, esperado vs actual.
- Tengo un caso reproducible (fixture, usuario, request).
- Acoté si es frontend, backend, DB o tercero.
- Tengo 1–3 hipótesis y una forma de probar cada una.
- Usé logs/breakpoints con intención, no por desesperación.
- El fix incluye validación/guardrail (test o check mínimo).
- Verifiqué regresiones básicas.
- Dejé nota: causa raíz + prevención.
FAQ
1) ¿Qué hago si no puedo reproducir el bug?
Junta evidencia: logs con request id, timestamps, navegador/OS, payload, y busca patrón (usuario nuevo, región, plan, tipo de cuenta). Si es intermitente, mete tracing/telemetría y vuelve el sistema observable antes de mover código.
2) ¿Logs o breakpoints: qué uso primero?
Si ocurre en production o depende del entorno, logs. Si lo puedes correr local y es lógica/estado, breakpoints. En la vida real, terminas usando ambos.
3) ¿Cómo debugeo errores de un tercero (pagos, envío, auth)?
Aísla: guarda request/response (sin secretos), valida timeouts/reintentos, y simula fallas (mock). No asumas que “el tercero está mal”; demuestra cuándo y cómo falla.
4) ¿Qué significa “hablar con tus errores” de verdad?
Tratar el error como señal: leer el mensaje, seguir el stack trace, observar estado, preguntar “¿qué condición lo activa?” y responder con evidencia. Tú preguntas con experimentos, el sistema contesta con datos.
5) ¿Cómo sé que mi fix no va a romper otra cosa?
Cubre el caso mínimo que fallaba, prueba un flujo feliz, y agrega guardrail (test, validación, métrica). Si toca varias capas, haz rollout cuidadoso y monitorea errores.
Siguiente episodio
Cuando ya sabes encontrar bugs, el siguiente paso es no fabricarlos tan fácil: hábitos, tests y diseño que te salvan en production.
La idea es armar un workflow que te quite talacha y te suba el nivel sin volverte policía del código.
Idea para cerrar bien este post: toma una sola práctica de aquí y conviértela en algo que tu equipo pueda aplicar hoy.
Cuando un artículo aterriza en decisiones reales, deja de ser contenido y se vuelve ventaja.


