El 87% de los bugs que encontré en código generado por IA aparecieron en edge cases que el prompt no mencionaba. No en la funcionalidad principal. En los bordes.
Cuando vi ese número en mi propio historial de PRs, tuve que releer dos veces. Porque llevaba semanas hablando de cuánto me ayudaba Cursor y Claude, y resulta que el 87% de mis correcciones eran exactamente en los lugares donde el contexto del negocio importa más que la sintaxis.
Eso me hizo pensar diferente sobre el vibe-coding. Y hoy lo quiero decir directo.
Vibe coding productividad real con IA — la diferencia que nadie te explica
Existe una corriente (legítima, interesante) que dice que el futuro del desarrollo es el vibe-coding: describís lo que querés, la IA lo genera, vos lo guiás con prompts, y el código aparece casi solo. Vi el artículo que circuló en Dev.to hace poco sobre "stress-coding" — la contracara ansiosa — y aunque el post en sí era bastante básico, el concepto me cerró algo que venía dando vueltas.
El vibe-coding no es malo. Es contextual.
Yo vibe-codeo. Todos los días. Pero no en todos los proyectos de la misma manera. La distinción que me tomó tiempo articular es esta:
- Cuando experimento: la IA es copiloto con las riendas sueltas
- Cuando hay usuarios reales: la IA es una herramienta poderosa que yo audito con criterio propio
Parece obvio. No lo es cuando estás en el flow y todo parece funcionar.
Cómo uso IA en modo experimento (y por qué está bien)
Cuando construí juanchi.dev, el proceso fue casi puro vibe-coding en las primeras semanas. Next.js 16, React 19, Tailwind v4 — todo bleeding edge, todo con poca documentación, todo con IA como primera línea de consulta.
En ese contexto, el flujo era:
// Prompt típico en modo experimento:
// "Necesito un componente que anime la entrada de cards
// usando Framer Motion con el nuevo hook useAnimate"
// La IA genera esto, yo lo acepto y pruebo:
import { useAnimate, stagger } from 'framer-motion'
export function AnimatedGrid({ items }: { items: PostCard[] }) {
const [scope, animate] = useAnimate()
// IA sugirió este approach — lo probé, funcionó, seguí
useEffect(() => {
animate(
'.card',
{ opacity: [0, 1], y: [20, 0] },
{ delay: stagger(0.1) }
)
}, [])
return (
<div ref={scope} className="grid gap-6">
{items.map(item => (
<div key={item.slug} className="card">
<PostCard {...item} />
</div>
))}
</div>
)
}
En modo experimento, si esto falla en un edge case, el costo es: yo me doy cuenta, lo corrijo, sigo. No hay usuario esperando. No hay SLA. El vibe-coding acá multiplica mi velocidad de exploración de manera real.
El problema empieza cuando ese modo mental no cambia al pasar a producción.
Cómo uso IA cuando hay producción de por medio (stress-coding, pero el bueno)
Tengo un proyecto cliente — e-commerce, tráfico real, órdenes reales. Cuando trabajé la optimización de performance de esa app, el flujo con IA fue completamente diferente.
Lo que cambió:
1. El prompt incluye el contexto de negocio, siempre
// Prompt en modo producción:
// "Tengo una query que trae órdenes de los últimos 30 días
// con JOIN a usuarios y productos. Se ejecuta cada vez que
// alguien entra al dashboard admin. Promedio 2.3 segundos.
// La tabla órdenes tiene 180k filas. ¿Cómo la optimizo?
// NO quiero soluciones que rompan la paginación existente."
// Lo que la IA genera, yo NO acepto sin revisar:
const getRecentOrders = async (page: number, limit: number) => {
// IA sugirió este índice compuesto — lo evalué en staging primero
// CREATE INDEX idx_orders_created_user
// ON orders(created_at DESC, user_id)
// WHERE created_at > NOW() - INTERVAL '30 days';
return await db
.select({
id: orders.id,
total: orders.total,
// Solo los campos que realmente necesito — la IA quería traer todo
userName: users.name,
// Removí el JOIN a products porque no se mostraba en este view
})
.from(orders)
.innerJoin(users, eq(orders.userId, users.id))
.where(
and(
gte(orders.createdAt, sql`NOW() - INTERVAL '30 days'`),
eq(orders.status, 'completed') // IA no sabía que solo quería completed
)
)
.orderBy(desc(orders.createdAt))
.limit(limit)
.offset((page - 1) * limit)
}
La IA no sabía que solo quería órdenes completed. Ese filtro cambió la query de 2.3 segundos a 400ms sin índice nuevo. El contexto de negocio que yo aporté valió más que el código que ella generó.
2. Nada va a producción sin que yo entienda cada línea
Esto suena básico y lo es. Pero en modo vibe-coding es fácil hacer Accept All y seguir. En producción, si no podés explicar qué hace una función en 30 segundos, no la deployás.
3. Los edge cases los pienso yo, no los delego
Volviendo al 87% del principio: los edge cases son exactamente el lugar donde el contexto de negocio importa. ¿Qué pasa si el usuario cancela la orden justo cuando se está procesando el pago? ¿Qué pasa si el stock llega a cero entre el addToCart y el checkout? Eso no está en el prompt. Nunca va a estar en el prompt a menos que vos lo pongas.
Los errores que cometí mezclando los dos modos
El problema real no es el vibe-coding ni el stress-coding. El problema es no saber en cuál modo estás.
En mi viaje de 30 años con tecnología, tiré un servidor de producción con rm -rf en mi primera semana de sysadmin. Eso fue stress-coding sin criterio: urgencia, presión, ejecutar sin pensar. El equivalente moderno es vibe-coding en producción: velocidad, flow, Accept All sin auditar.
Dos errores concretos que cometí:
Error 1: Confiar en los tipos de TypeScript generados por IA sin validar en runtime
// IA generó esto, yo lo acepté:
type OrderResponse = {
id: string
total: number
items: OrderItem[]
}
// Problema: la API real a veces devuelve total como string
// TypeScript no lo detecta en runtime, Zod sí:
import { z } from 'zod'
// Lo que debería haber hecho desde el principio:
const OrderResponseSchema = z.object({
id: z.string(),
total: z.coerce.number(), // coerce maneja string -> number
items: z.array(OrderItemSchema)
})
// Ahora si la API rompe el contrato, yo me entero en runtime
// y no cuando el usuario ve "NaN" en su total
Este error me costó 2 horas de debugging en producción. El stack tecnológico que elijo hoy incluye Zod obligatorio por esta razón.
Error 2: Dejar que la IA decida la arquitectura de features nuevas
La IA es excelente implementando. Es mediocre diseñando. Cuando le preguntás "¿cómo estructuro el módulo de notificaciones?", te va a dar una respuesta técnicamente correcta y genéricamente inútil para tu contexto.
Los patrones de TypeScript que realmente uso surgieron de decisiones de diseño que tomé yo, no la IA. Ella implementa los patrones. Yo decido cuándo y por qué aplicarlos.
Lo que cambió en mi flujo de trabajo concreto
Hoy tengo una regla interna simple:
Si el bug en producción me va a despertar a las 2am, no vibe-codeo esa parte.
Más específico:
- Autenticación y autorización: cada línea auditada
- Manejo de pagos: zero vibe-coding
- Queries a base de datos en producción: genero con IA, reviso el plan de ejecución
- Manejo de errores y edge cases: los pienso yo, la IA los implementa
- UI components sin estado crítico: vibe-coding libre
- Animaciones, estilos, layout: vibe-coding con los ojos cerrados
- Scripts de migración de datos: auditados línea por línea, siempre
El resultado es que uso IA el 80% de mi tiempo de coding, pero de manera diferenciada. No es menos IA — es IA con criterio.
FAQ: Vibe-coding y productividad real con IA
¿El vibe-coding es solo para proyectos personales o sirve en trabajo cliente?
Sirve en trabajo cliente, pero en capas específicas. Para exploración inicial, prototipos, componentes de UI sin lógica crítica — perfecto. Para la lógica de negocio core, las integraciones de pago, el manejo de datos sensibles — necesitás un modo más riguroso. La clave es saber cuál es cuál antes de empezar a tipear.
¿Cómo evitás aceptar código de IA que parece funcionar pero tiene bugs escondidos?
Dos prácticas concretas: primero, siempre correr los tests antes del commit (tenés tests, ¿no?). Segundo, si es código que interactúa con external APIs o base de datos, lo probás con datos edge case reales: strings vacíos, IDs que no existen, respuestas con campos faltantes. La IA genera el camino feliz de maravilla. Los bordes los tenés que probar vos.
¿Qué herramientas de IA usás actualmente?
Cursor como editor principal con Claude Sonnet para el día a día. Claude Opus cuando necesito pensar arquitectura o debuggear algo complejo que no entiendo. ChatGPT casi no lo uso para código. GitHub Copilot lo dejé — Cursor lo supera en contexto de proyecto completo. El contexto es todo en esta ecuación.
¿El vibe-coding no te hace perder profundidad técnica con el tiempo?
Es la pregunta que más me hago. Mi respuesta honesta: sí, si no tenés cuidado. La manera de contrarrestarlo es elegir deliberadamente entender el código difícil, no solo aceptarlo. Cuando la IA genera algo que no entiendo completamente, le pido que me explique. No por paranoia — para mantener el músculo activo. Los 30 años de background técnico que describí no los quiero atrofiar.
¿Hay un tipo de proyecto donde NO usarías IA en el loop?
Honestamente, no. Pero hay partes de proyectos donde la IA está en el loop de manera diferente. En código crítico de seguridad, la uso para revisar lo que yo escribo, no para generar. "Acá está mi implementación de rate limiting, ¿qué ataques no estoy cubriendo?" Eso es IA como auditor, no como generador. Es un modo más, no ausencia de IA.
¿Cómo sabés cuándo el código generado por IA está bien y cuándo hay que reescribirlo?
Señales de reescritura: no podés explicar qué hace en 30 segundos, tiene más de 3 niveles de anidamiento sin razón obvia, los nombres de variables son genéricos (data, result, temp), o no tiene manejo de errores. Señales de que está bien: lo leerías orgulloso en un code review, los edge cases están contemplados, y si algo falla, el error va a ser claro sobre qué falló y por qué.
Lo que haría diferente si empezara hoy
El vibe-coding es real, es productivo, y vino para quedarse. Pero la narrativa de "describís y la IA hace" tiene un problema: omite que el valor del desarrollador senior no está en escribir código. Está en saber qué código escribir, cuándo, y con qué trade-offs.
Empecé a usar IA en serio durante la pandemia, cuando hice el pivot a desarrollo de software. Los primeros meses fueron devastadores — todo lo que sabía de infra no valía en React. Tuve que aprender a pensar diferente. Y hoy, con IA, pasa algo parecido: el que no aprende cuándo confiar y cuándo auditar va a tener el mismo problema que el dev que copiaba Stack Overflow sin entender. Los bugs van a aparecer en el peor momento, en los bordes, exactamente donde el negocio duele más.
La IA multiplicó mi productividad real. Pero la productividad real incluye no despertar a las 2am por algo que "parecía funcionar".
¿Vos cómo dividís el uso de IA entre proyectos que importan y experimentación? Me interesa saber si tu criterio es diferente al mío.
Comentarios (0)
Deja un comentario
Artículos Relacionados
Google Maps para codebases: pegué la URL de mi propio repo y me asusté un poco
Existe una herramienta que te permite pegar una URL de GitHub y preguntarle cualquier cosa sobre el código. La usé con mi propio proyecto. Lo que me mostró sobre mí mismo no fue cómodo.
Metí Gemma corriendo en el browser, sin API keys, y me cambió cómo pienso el edge
Hay una creencia instalada sobre AI en producción que está bastante equivocada: que necesitás una API, un server y una tarjeta de crédito para meter inteligencia en tu app. Lo corrí en el browser. Sin nube. Sin billing. Y ahora no puedo dejar de pensar en lo que esto significa.
Sandboxes para agentes de código: qué es Freestyle y por qué me importa
Cuando empecé a usar agentes de código en proyectos reales, el mayor miedo no era que escribieran mal — era que ejecutaran cosas en mi máquina sin que yo entendiera qué. Freestyle llegó al HN con 188 puntos tocando exactamente ese nervio.