Saltar al contenido
Lección 8 de 22

Iterar y Depurar con IA

19 min read

El Bucle del Vibe Coding

Cada sesión productiva de vibe coding sigue el mismo ritmo: Prompt, Revisar, Probar, Refinar. Este bucle es el latido del desarrollo asistido por IA. Cuanto más rápido y con más precisión puedas moverte a través de él, más podrás construir.

Prompt: Describes lo que quieres. Puede ser una nueva funcionalidad, una corrección de bug, un cambio de diseño o una tarea de refactorización. La calidad de tu prompt determina la calidad del primer resultado, como cubrimos en la lección de prompting.

Revisar: Miras lo que la IA generó. No necesariamente cada línea de código, sino la estructura general, el enfoque que tomó y si entendió tu intención. ¿Creó los archivos correctos? ¿El componente se ve aproximadamente correcto? ¿Hay problemas obvios?

Probar: Ejecutas el código e interactúas con él. ¿La página carga? ¿El botón hace lo que debería? ¿El formulario se envía exitosamente? ¿Los estados de error funcionan? Las pruebas son donde la teoría se encuentra con la realidad.

Refinar: Basándote en lo que viste en la revisión y las pruebas, le das feedback a la IA. Quizás la funcionalidad funciona pero el estilo está mal. Quizás la lógica es correcta pero lanza un error en casos límite. Quizás es perfecto y pasas a la siguiente tarea.

Este bucle se repite hasta que el resultado cumple tus expectativas. La mayoría de las funcionalidades pasan por 2-5 iteraciones. Los cambios simples pueden acertar al primer intento. Las funcionalidades complejas pueden tomar 10 o más rondas. Ambos son normales.

La clave: cada iteración debe hacer progreso medible. Si estás dando vueltas en círculos — el mismo error sigue volviendo, o cada corrección introduce un nuevo problema — esa es una señal para cambiar tu enfoque, no para seguir iterando.

Feedback Efectivo vs. Feedback Vago

La calidad de tu feedback determina directamente qué tan rápido la IA puede corregir un problema. El feedback vago desperdicia tu tiempo y el poder de procesamiento de la IA. El feedback específico lleva a correcciones precisas.

Veamos seis comparaciones lado a lado:

Par 1: Algo está roto

Vago: This doesn't work.

Efectivo: The submit button on the contact form at /contact returns a 404 error when clicked. Here's the console output: "POST /api/contact 404 (Not Found)". The form fields are filled in correctly and validation passes.

Par 2: Problemas de estilo

Vago: It looks weird on mobile.

Efectivo: On iPhone (375px width), the pricing cards overlap each other. The three-column grid isn't switching to a single column. The cards need to be full width and stacked vertically on screens below 768px.

Par 3: Comportamiento incorrecto

Vago: The login isn't working.

Efectivo: After entering valid credentials and clicking "Sign In," the page redirects to /dashboard for a split second, then immediately redirects back to /login. This happens in a loop. I can see the session cookie is being set in DevTools, so the authentication seems to work but the middleware might be redirecting authenticated users incorrectly.

Par 4: Rendimiento

Vago: The page is slow.

Efectivo: The /dashboard page takes 8 seconds to load. The Network tab shows that the /api/analytics endpoint takes 6.5 seconds to respond. It's probably fetching too much data — we're loading all analytics for all time instead of just the current month.

Par 5: Éxito parcial

Vago: Almost, but not quite.

Efectivo: The dark mode toggle works — clicking the sun/moon icon switches the color scheme. But two things are wrong: (1) the preference doesn't persist — refreshing the page always starts in light mode, and (2) the chart component in the dashboard doesn't respect the dark mode variables, so it stays white even when everything else is dark.

Par 6: Nuevo requisito

Vago: Can you also add validation?

Efectivo: Add client-side validation to the registration form: the email field should validate the format on blur (show "Please enter a valid email" below the field in red), the password field should require at least 8 characters with one number (show strength indicator: weak/medium/strong), and the "confirm password" field should show an error if it doesn't match. Don't submit the form if any validation fails.

El patrón es claro: el feedback efectivo incluye lo que esperabas, lo que pasó en su lugar, y cualquier mensaje de error, URL o detalle específico que ayude a la IA a localizar y entender el problema.

El Arte del Feedback Específico

Hay una estructura simple que puedes seguir cada vez que le das feedback a la IA:

1. Lo que esperaba que pasara
2. Lo que realmente pasó
3. Evidencia relevante (mensaje de error, descripción visual, URL, comportamiento)

Aquí tienes algunos ejemplos de esta estructura en acción:

Expected: Clicking "Add to Cart" should show a toast notification
and update the cart count in the header.
Actual: The toast appears, but the cart count doesn't update until
I refresh the page.
Evidence: The addToCart server action returns successfully (I can see
the item in the database), so the issue is probably that the header
component isn't re-rendering after the action completes.
Expected: The search should filter blog posts as I type.
Actual: Nothing happens when I type. The post list stays the same.
Evidence: No console errors. I checked the React DevTools and the
search state is updating correctly, so the filtering logic might
not be connected to the post list rendering.
Expected: The image upload should accept JPEG and PNG files up to 5MB.
Actual: It accepts the file but the preview shows a broken image icon.
Evidence: The file uploads successfully to the /api/upload endpoint
(returns 200 with the URL), but the returned URL gives a 403 when
accessed directly. This might be a Supabase storage permission issue.

Nota cómo cada uno de estos le da a la IA un punto de partida claro para investigar. No solo estás diciendo "está roto" — estás proporcionando un rastro de diagnóstico que lleva a la solución.

Siempre Incluye el Mensaje de Error

Esto no se puede enfatizar lo suficiente: siempre pega el mensaje de error real. No lo resumas, no lo parafrasees, no lo describas de memoria. Copia y pega el texto exacto.

Los mensajes de error contienen información precisa — rutas de archivos, números de línea, nombres de funciones y códigos de error — que la IA usa para localizar el problema. Un resumen como "hay un error de tipo en algún lugar" pierde toda esta información valiosa.

# Mal: resumir el error
There's a type error in the user component.

# Bien: pegar el error real
Error in app/dashboard/page.tsx:
TypeError: Cannot read properties of undefined (reading 'name')
  at UserGreeting (app/components/UserGreeting.tsx:14:22)
  at Dashboard (app/dashboard/page.tsx:31:8)

El error completo le dice a la IA exactamente qué archivo, qué línea, qué propiedad y qué cadena de componentes está involucrada. Esa es la diferencia entre una corrección precisa y un juego de adivinanzas.

Patrones de Depuración Colaborativa

Con el tiempo, desarrollarás un repertorio de conversaciones de depuración con la IA. Aquí hay cuatro patrones que cubren la mayoría de las situaciones.

El Volcado de Error

El patrón más simple y más común. Encuentras un error, lo pegas y le pides a la IA que lo diagnostique.

I'm getting this error when I try to build the project:

./app/dashboard/page.tsx
Type error: Property 'user' does not exist on type 'Session | null'.

  29 |   const session = await getServerSession(authOptions);
  30 |   const userName = session.user.name;
                                 ^

What's wrong and how do I fix it?

La IA reconocerá inmediatamente esto como un problema de seguridad nula — session podría ser null, y necesitas verificar eso antes de acceder a .user.name. Pega el error completo y la corrección generalmente es directa.

La Descripción de Comportamiento

Cuando no hay error pero el comportamiento es incorrecto, describe lo que ves versus lo que esperas.

The navigation bar is supposed to be fixed at the top of the page so
it stays visible when scrolling. But it scrolls away with the rest of
the content. I added "fixed top-0" to the nav element. The nav is
inside the layout.tsx file, wrapped in a div with "flex flex-col min-h-screen".

No hay mensaje de error aquí, pero la descripción es lo suficientemente específica para que la IA diagnostique. El problema probablemente es que el contenedor flex padre necesita ajuste, o el contenido principal necesita un margen superior para compensar la navegación fija.

La Comparación

Este patrón funciona muy bien cuando algo que funcionaba ahora no funciona.

The user avatar was displaying correctly in the header until I added
the notification bell feature in the last commit. Now the avatar
shows a broken image icon. I didn't change any avatar-related code,
so the notification bell changes must have broken something.

The last commit was: feat: add notification bell to header

Can you check what changed in that commit and figure out why the
avatar broke?

Esto le da a la IA una línea de tiempo clara: funcionaba antes del commit X, está roto después del commit X, así que el problema fue introducido por el commit X. La IA puede revisar el diff del commit y encontrar el problema.

La Investigación Guiada

A veces tienes una corazonada sobre dónde está el problema. Compártela.

The checkout flow is failing on the payment step. I think the issue
is in app/api/checkout/route.ts — specifically in how we're creating
the Stripe Checkout Session. The error from Stripe says
"Invalid price ID" but the price ID in our database looks correct
(price_1234abc). Can you check if we're passing the price ID
correctly to the Stripe API?

Tu hipótesis podría ser incorrecta, y eso está bien. Pero darle a la IA un punto de partida para investigar es más rápido que pedirle que busque a ciegas.

Leer Stack Traces

Los stack traces se ven intimidantes si nunca has visto uno, pero siguen un formato consistente que en realidad es bastante legible una vez que sabes qué buscar.

Aquí hay un stack trace típico:

TypeError: Cannot read properties of undefined (reading 'email')
    at getUserProfile (C:\project\lib\users.ts:45:24)
    at async Dashboard (C:\project\app\dashboard\page.tsx:18:20)
    at async renderServerComponent (node_modules\next\...):

Desglosémoslo:

Línea 1 — El tipo de error y mensaje: TypeError: Cannot read properties of undefined (reading 'email'). Esto te dice la categoría de error (TypeError) y qué salió mal específicamente (intentó leer .email en algo que es undefined).

Líneas 2+ — La pila de llamadas: Muestran la cadena de llamadas a funciones que llevaron al error, comenzando desde la más reciente. La primera línea después del mensaje de error usualmente es donde está el problema:

  • getUserProfile en lib/users.ts en la línea 45, columna 24

El resto de la pila muestra qué llamó a getUserProfile:

  • Dashboard en app/dashboard/page.tsx en la línea 18

Las líneas que referencian node_modules son internos del framework — generalmente no necesitas preocuparte por esas.

Tipos de Error Comunes

TypeError — Intentaste usar un valor de una forma que no coincide con su tipo. Lo más común: acceder a una propiedad en undefined o null. Solución: agregar verificaciones de null.

ReferenceError — Usaste una variable que no existe. Usualmente un typo en el nombre de una variable o un import faltante. Solución: verificar ortografía e imports.

SyntaxError — El código tiene sintaxis inválida. Un paréntesis faltante, una coma extra, un punto y coma mal colocado. Solución: mira la línea mencionada en el error.

404 (Not Found) — Una petición HTTP fue a una URL que no existe. Causa común: ruta de API incorrecta, archivo de página faltante o typo en la URL.

500 (Internal Server Error) — El servidor falló al procesar una petición. Revisa los logs del servidor para el error real. El 500 solo significa "algo salió mal del lado del servidor."

401 (Unauthorized) — La petición no tiene autenticación válida. Token faltante o expirado, API key incorrecta, o el usuario no está logueado.

403 (Forbidden) — El usuario está autenticado pero no tiene permisos. Verifica el control de acceso basado en roles o la propiedad de recursos.

Error CORS — El navegador bloqueó una petición a un dominio diferente. Este es un problema de configuración del servidor, no un bug del lado del cliente. La API necesita enviar los headers CORS correctos.

El Patrón de "Deshacer y Reintentar"

A veces la iteración no converge. Has ido y vuelto con la IA durante 15 minutos, y el código no se acerca más a funcionar — se vuelve más complejo con cada iteración. Este es el momento de dejar de iterar y empezar de nuevo.

Aquí está el patrón:

# 1. Guarda tu estado actual (por si quieres referenciarlo después)
git add .
git commit -m "wip: save broken auth attempt for reference"

# 2. Vuelve a la última versión funcional
git reset HEAD~1
git checkout -- .

# 3. Prueba un enfoque completamente diferente

Ahora inicia una nueva conversación o un nuevo prompt que tome un enfoque fundamentalmente diferente. En lugar de ajustar la misma solución rota, describe el problema de nuevo y deja que la IA proponga una nueva solución.

Cuándo Es Necesario

Aquí hay señales concretas de que la iteración se estancó:

  • El mismo error sigue volviendo. Lo corriges, algo más se rompe, corriges eso, y el error original regresa. La IA está en un bucle.
  • El código se vuelve más complejo con cada iteración. Cada "corrección" agrega más workarounds, lógica condicional y casos especiales. La solución está creciendo cuando debería estar simplificándose.
  • Has estado en el mismo problema más de 15 minutos. Establece un temporizador mental. Si un solo problema toma más de 15 minutos de ida y vuelta, el enfoque probablemente está mal.
  • La IA empieza a sugerir "workarounds." Cuando la IA dice cosas como "as a workaround, you could..." significa que el enfoque actual tiene una limitación fundamental. Un workaround sobre una sugerencia de IA es un castillo de naipes.
  • Estás frustrado. Esta es una señal real. La frustración usualmente significa que el enfoque está mal, no que solo necesitas una iteración más.

El reinicio limpio frecuentemente resuelve el problema en un solo prompt porque la IA elige una estrategia de implementación diferente (y mejor) cuando empieza desde cero.

Escenarios de Depuración por Tipo

Diferentes tipos de bugs requieren diferentes estrategias de depuración. Aquí hay una guía para las categorías más comunes.

Errores de Build y Compilación

Estos impiden que tu código se ejecute del todo. Son usualmente los más fáciles de corregir porque el mensaje de error te dice exactamente qué está mal.

Module not found: Can't resolve '@/components/UserCard'

Diagnóstico: El archivo no existe en esa ruta, o la ruta de importación es incorrecta. Verifica typos en la ruta y asegúrate de que el archivo exista.

Type 'string' is not assignable to type 'number'.

Diagnóstico: Estás pasando un string donde se espera un número. Verifica la firma de la función y los datos que estás pasando.

Estrategia: Pega el error completo en tu prompt de IA. Los errores de build casi siempre tienen mensajes claros y accionables.

Problemas de Estilo

Los bugs de CSS son visuales — puedes verlos pero no producen mensajes de error. Esto los hace más difíciles de describir a la IA.

Estrategia: Sé extremadamente específico sobre lo que ves versus lo que esperas. Menciona tamaños de pantalla, elementos específicos y comportamientos exactos.

The pricing cards are overlapping on iPad (768px width). The three
cards should be in a 2-column grid on tablet and 1-column on mobile.
Currently they're all in one row and the third card extends beyond
the right edge of the screen. The container has max-w-6xl and the
cards use w-1/3 without responsive variants.

Culpables comunes de estilo:

  • Variantes responsivas faltantes (sin prefijos md: o lg:)
  • Conflictos de z-index (elementos superpuestos)
  • Overflow hidden cortando contenido
  • Flexbox o grid no haciendo wrap como se esperaba
  • Contenedores padre con alturas fijas restringiendo a los hijos

Bugs de Lógica

El código se ejecuta sin errores, pero produce el resultado incorrecto.

The discount calculation is showing 15% off instead of 20% off.
The subtotal is $100, the discount should be $20, but it shows $15.
The calculation is in lib/pricing.ts in the calculateDiscount function.

Estrategia: Describe el resultado esperado, el resultado real y los valores de entrada específicos. Si puedes identificar la función donde ocurre el cálculo, menciónala.

Errores de API

Peticiones de red fallando entre tu frontend y backend (o servicios externos).

Estrategia: Incluye el código de estado HTTP, la URL, el método de la petición y cualquier cuerpo de error. Revisa la pestaña Network en DevTools del navegador para esta información.

POST request to /api/users returns 500.
Request body: { "name": "John", "email": "john@example.com" }
Response body: { "error": "relation \"users\" does not exist" }
This means the database table hasn't been created. Need to run migrations.

Causas comunes de errores de API:

  • 400: Al cuerpo de la petición le faltan campos requeridos o tiene datos inválidos
  • 401: Token de auth faltante o expirado
  • 403: El usuario no tiene permisos para esta acción
  • 404: Ruta URL incorrecta o el recurso no existe
  • 500: Crash del lado del servidor — revisa los logs del servidor para el error real
  • CORS: La API no permite peticiones desde el dominio de tu frontend

Problemas de Rendimiento

La app funciona pero es lenta.

Estrategia: Usa las DevTools del navegador para medir qué es lento. La pestaña Performance, la pestaña Network y la auditoría de Lighthouse te dan números específicos para compartir con la IA.

The /dashboard page takes 6 seconds to load. The Network tab shows
that the /api/analytics endpoint takes 5.2 seconds. It returns
45,000 rows of data. We should paginate this to return only the
current month's data (about 1,500 rows) and add server-side filtering.

Errores de TypeScript

Los errores de tipo son advertencias en tiempo de compilación que previenen bugs pero pueden ser confusos si eres nuevo en TypeScript.

Type '{ name: string; }' is not assignable to type 'User'.
  Property 'email' is missing in type '{ name: string; }'
  but required in type 'User'.

Estrategia: Pega el error completo de TypeScript. Estos son altamente estructurados y la IA casi siempre puede corregirlos instantáneamente. El error te está diciendo exactamente qué propiedad falta y qué tipo la espera.

Cuándo Empezar de Nuevo vs. Seguir Iterando

Esta decisión determina si pasas 5 minutos o 50 minutos en un problema. Aquí hay un marco de referencia:

Sigue Iterando Cuando:

  • Cada iteración hace progreso visible hacia la solución
  • El enfoque central es sólido pero los detalles necesitan ajuste
  • Estás corrigiendo ajustes de estilo o layout
  • La IA entiende lo que quieres pero necesita afinación
  • Estás en la iteración 2-4 y la trayectoria es positiva

Empieza de Nuevo Cuando:

  • El mismo error vuelve después de ser "corregido" dos o más veces
  • Cada iteración hace el código más complejo en lugar de más simple
  • Has pasado más de 15 minutos en un solo problema
  • La IA sigue sugiriendo workarounds en lugar de soluciones
  • Te das cuenta de que el enfoque inicial era fundamentalmente incorrecto
  • El código ha acumulado tantos parches que es difícil de seguir

Cómo Empezar de Nuevo Efectivamente

Empezar de nuevo no significa perder todo. Este es el proceso:

  1. Commitea el estado actual roto con un prefijo wip: para que puedas referenciarlo
  2. Revierte a la última versión funcional usando git reset
  3. Identifica qué estaba mal en el enfoque anterior (este es el paso clave)
  4. Escribe un nuevo prompt que explícitamente evite el problema. Por ejemplo: "Last time, using client-side state for the cart caused sync issues. This time, use a server action approach with revalidation instead."

La mención explícita de qué evitar previene que la IA tome la misma decisión arquitectónica de nuevo.

Mantener el Momentum

Una sesión de depuración puede drenar tu energía y descarrilar todo tu flujo de trabajo si lo permites. Aquí hay estrategias para mantenerte productivo.

Establece un límite de tiempo. Si un bug no se resuelve en 15 minutos, apárcalo y sigue adelante. Trabaja en otra cosa — una funcionalidad diferente, una página diferente, una parte diferente de la aplicación. Frecuentemente, la solución se vuelve obvia cuando regresas con ojos frescos.

No dejes que un bug bloquee todo. A menos que el bug sea verdaderamente bloqueante (la app no compila del todo), generalmente hay otro trabajo que puedes hacer. Agrega un comentario TODO, anota el problema y continúa construyendo otras partes del proyecto.

Celebra las pequeñas victorias. Cada iteración exitosa es progreso. Cada bug que resuelves es una habilidad que has ganado. El vibe coding tiene un ciclo de retroalimentación rápido — disfruta la velocidad de ir de prompt a funcionalidad funcionando.

Toma descansos. Esto suena simple pero es genuinamente efectivo. Si has estado mirando el mismo problema durante 20 minutos, aléjate por 5 minutos. Tu subconsciente sigue trabajando en el problema incluso cuando tu mente consciente se detiene.

Mantén un registro continuo. Cuando resuelvas un bug complicado, anota qué era y cómo lo arreglaste. Con el tiempo, esto se convierte en tu manual de depuración personal. Empezarás a reconocer patrones: "Oh, esto se parece a ese problema de CORS que arreglé el mes pasado."

Lo Que Sigue

Ahora puedes iterar efectivamente, dar feedback preciso, diagnosticar errores por categoría y saber cuándo cortar tus pérdidas y empezar de nuevo. Estas habilidades te servirán en cada sesión de vibe coding de aquí en adelante.

Pero hay una habilidad más esencial antes de empezar a construir aplicaciones completas: leer y revisar código generado por IA. No necesitas ser programador para revisar código — solo necesitas saber qué buscar. En la próxima lección, cubriremos patrones de revisión de código que te ayudan a detectar problemas, entender la estructura y saber cuándo pedir una reescritura.