Cuando el vibe coding conoce a un desarrollador

17 min de lectura

La IA lo construyó. ¿Y ahora qué?

28.07.2026, Por Stephan Schwab

Tres clientes llegaron a mí en pocos meses, cada uno con una aplicación funcional creada con una herramienta de programación de IA. Ninguno era desarrollador. Herramientas distintas, sectores distintos, el mismo momento de la verdad: estaban tan cerca de lanzar que el negocio suponía que lo difícil había terminado. No era así. Los tres tenían un enredo de dependencias que nadie podía explicar, defectos que seguían multiplicándose sin una forma fiable de encontrarlos, despliegues por SSH y esperanza, y o bien ninguna prueba o pruebas desactivadas discretamente porque eran incómodas. La IA había hecho lo que le pidieron. Nadie había formulado las preguntas que hacen que el software se pueda cambiar con seguridad. Antes de que una aplicación creada con IA salga a producción, alguien debe rastrear dependencias, hacer repetible el despliegue, decidir qué comportamiento hay que comprobar y asumir los fallos que aparecerán fuera del camino feliz. No es la mirada de un desarrollador a última hora. Es la diferencia entre un prototipo útil y un sistema en el que la empresa puede confiar. Si mañana alguien trajera a su equipo un producto creado con IA y casi terminado, ¿podrían decirle qué debe ser cierto antes de que llegue a los usuarios?

Viñeta de un robot de IA entusiasta que presenta una pila precaria de componentes de software mientras un desarrollador la inspecciona.

Quiero ser honesto sobre lo primero que me impresionó: las aplicaciones funcionaban de verdad. Datos reales, flujos de trabajo reales, no demostraciones de juguete. Las tres eran funcionales y estaban casi listas para abrirse a usuarios. Las características funcionaban. Las integraciones conectaban. Los flujos básicos se sostenían.

Eso es realmente notable. Hace cinco años ninguna de estas personas habría llegado tan lejos sin contratar a un desarrollador desde el primer día. Las herramientas de IA habían bajado drásticamente el suelo.

Sin embargo, el techo no se había movido.

Lo que las tres tenían en común

"La IA les dio un prototipo funcional. Estaban a punto de enviarlo como sistema de producción."

Las aplicaciones diferían en dominio y alcance. Los problemas de fondo eran casi idénticos.

Dependencias sin responsable. Cada proyecto había acumulado decenas de bibliotecas. Algunas estaban fijadas a versiones concretas porque algo se había roto al actualizarlas. Otras no estaban fijadas en absoluto y derivaban silenciosamente. Nadie sabía qué dependencias se usaban realmente y cuáles habían llegado por algo que la IA sugirió tres refactorizaciones atrás y nunca limpió. Los archivos requirements.txt parecían excavaciones arqueológicas: capas de decisiones, ninguna documentada, varias contradictorias.

Defectos sin ciclo de retroalimentación. El proceso de depuración era: abrir la aplicación, hacer clic como un usuario, advertir que algo parecía mal, describírselo a la IA y pedir una corrección. Sin monitorización de errores. Sin agregación de registros. Sin conciencia de lo que la aplicación hacía internamente. La IA sugería un cambio, se aplicaba el cambio y el ciclo se repetía. En más de un caso, una corrección había introducido una regresión que pasó inadvertida durante días, porque la única señal era lo que podía verse desde fuera y nadie miraba dentro.

Pruebas más decorativas que funcionales. Un cliente no tenía pruebas en absoluto. El tema nunca había surgido; ¿por qué iba a surgir? Las pruebas no son una característica visible para el usuario. La aplicación hacía lo esperado al recorrerla con clics, o no lo hacía. Ese era el único ciclo de retroalimentación que conocían. El segundo tenía una pequeña suite de pytest que pasaba localmente y llevaba tanto tiempo fallando en otro entorno que la comprobación de CI se había desactivado para desbloquear una versión. El tercero tenía pruebas para las partes de la aplicación que eran más fáciles de probar, que resultaban ser las partes que nunca se habían roto.

El despliegue como ocurrencia tardía. En el mundo de Python y PHP existe una larga cultura en la que desplegar significa copiar un archivo a un servidor y el cambio queda vivo. Sin paso de compilación, sin artefacto, sin pipeline. Las herramientas de IA —Claude Code, GitHub Copilot— habían absorbido esa cultura y la reprodujeron sin comentario. Entrar por SSH, hacer pull desde el repositorio, reiniciar el servicio. En ecosistemas donde un compilador produce un artefacto, los equipos tienden a desarrollar un flujo de despliegue más deliberado por necesidad. Aquí esa presión nunca existió, y la IA nunca la introdujo.

Nada de esto es una crítica a los clientes. Habían hecho lo que tenía sentido según lo que sabían. Las herramientas de IA nunca les dijeron que estas cosas importaban. Las herramientas respondieron las preguntas que les hicieron. No ofrecieron las preguntas que no se formularon.

Pero lo mismo vale para la mayoría de los desarrolladores humanos. El patrón de esperar instrucciones —responder la pregunta formulada, no la que debería haberse formulado— no es un fallo de la IA. Es un comportamiento social profundamente arraigado que la mayoría de las organizaciones seleccionan activamente. Los desarrolladores que plantean preocupaciones, sugieren mejoras estructurales o se oponen a malas decisiones suelen ser percibidos como difíciles. Los desarrolladores que entregan lo solicitado, a tiempo y sin fricción, reciben el nombre de buenos jugadores de equipo. La estructura de incentivos es explícita.

Esto se remonta más allá del software. Frederick Winslow Taylor, cuyos Principles of Scientific Management (1911) moldearon el trabajo industrial durante la mayor parte de un siglo, formalizó la separación entre quienes piensan y quienes ejecutan. Los directivos planifican. Los trabajadores ejecutan. El trabajador que cuestiona el plan es un problema que gestionar. Gran parte de la escolarización en sociedades industriales se diseñó con la misma lógica: producir personas que sigan instrucciones de forma fiable, no personas que interroguen si las instrucciones tienen sentido.

La IA es un ejecutor muy rápido y muy capaz. No interroga. No se opone. En ese sentido es un producto perfecto del sistema que Taylor imaginó, y un espejo de lo que la mayoría de las organizaciones siempre han recompensado realmente en las personas que contratan.

Por qué Python y React

Los tres habían llegado de forma independiente a elecciones tecnológicas parecidas. Python porque aparecía constantemente en contenido relacionado con IA y las herramientas parecían hablarlo con fluidez. React porque era el framework de frontend más visible en tutoriales, vídeos de YouTube y cualquier cosa que la IA sugería al preguntar «¿qué debería usar para el frontend?».

No son malas decisiones. Python es realmente bueno para backends de esta escala. React es un framework de frontend razonable. El problema no era la tecnología. El problema era que se había elegido por sensaciones: lo que parecía popular, lo que la IA ofrecía por defecto, lo que mostraban los tutoriales, en lugar de analizar lo que la aplicación realmente necesitaba.

Nadie había tomado esas decisiones deliberadamente. La IA las había tomado de forma implícita, prompt a prompt, y las decisiones se habían acumulado en una arquitectura que nadie había diseñado y nadie entendía por completo.

La IA que nunca dice no

Un caso destacó. El cliente había construido la aplicación mediante largas conversaciones con un asistente de IA, y la IA había sido —no hay mejor palabra— entusiasta. Elogiaba el trabajo. Proponía mejoras. Ofrecía soluciones a problemas que todavía no existían.

El resultado era una base de código que parecía prepararse para un futuro que la aplicación no se había ganado. OpenTofu para una infraestructura que un solo servidor no necesitaba. Redis medio conectado, conectado a nada. Feature toggles a medio terminar dispersos por el código, ninguno controlando nada real. Una suite completa de Playwright, confirmada en el repositorio y nunca ejecutada. Junto a ella, una suite de pytest con la mayoría de las pruebas marcadas como skip, y no uno sino varios workflows de GitHub Actions, cada uno desplegando una imagen de contenedor distinta, ninguno esperando a que pasaran las pruebas.

Ese último detalle merece un momento. Once contenedores en total, con una separación rígida entre servicios de frontend y backend. Para una aplicación que una persona había construido y estaba a punto de lanzar sola. La IA había absorbido de sus datos de entrenamiento los patrones de la arquitectura de software empresarial: microservicios, separación de responsabilidades a nivel de infraestructura, pipelines de despliegue independientes, y los había aplicado fielmente. También había absorbido las disfunciones organizativas que acompañan esos patrones en grandes empresas: propiedad aislada, pipelines que optimizan que todo siga moviéndose sin importar las señales de calidad, complejidad de infraestructura que existe porque siempre ha existido. Nada de eso era apropiado aquí. La IA no lo sabía. No tenía forma de saberlo. Estaba comparando patrones con ejemplos de un contexto muy diferente.

Este es un modo de fallo específico de algunas herramientas de IA: optimizan la apariencia de progreso. Añadir infraestructura señala seriedad. Añadir pruebas señala calidad. Sugerir Redis señala que el sistema está listo para escalar. Nada de eso necesita funcionar. Nada de eso necesita ser apropiado. La IA puede mantener la conversación y el usuario puede sentir que las cosas avanzan. Nadie está ahí para decir: todavía no necesitas esto, y añadirlo ahora te va a costar.

Un desarrollador senior habría puesto freno en esa conversación. No porque las ideas fueran incorrectas en abstracto —OpenTofu es una herramienta legítima, Redis es una herramienta legítima, los feature toggles son un patrón legítimo— sino porque eran la respuesta equivocada a la pregunta equivocada en el momento equivocado. Saber cuándo no añadir algo es gran parte de lo que separa la experiencia del entusiasmo.

"La IA optimizó la apariencia de progreso. Nadie estaba allí para decir: todavía no necesitas esto."

El problema de las dependencias es más profundo de lo que parece

"Un archivo de requisitos que nadie posee es un pasivo, no un activo."

Cuando empecé a examinar las dependencias de cada proyecto, el problema superficial era obvio: bibliotecas desactualizadas, avisos de seguridad ignorados, conflictos de versiones tapados con fijaciones. Eso se puede arreglar. El problema más profundo era que ninguno de los clientes podía responder una pregunta básica: ¿de qué depende realmente esta aplicación y por qué?

La IA había añadido bibliotecas cuando se le pedía implementar características. A veces había añadido bibliotecas como pasos intermedios y no las había eliminado al cambiar el enfoque. En ocasiones había sugerido bibliotecas populares en algún momento de sus datos de entrenamiento que desde entonces habían sido sustituidas o abandonadas. Y como los clientes no eran desarrolladores, no tenían un marco de referencia para evaluar nada de eso. Cuando la IA decía «añade requests a tus requisitos», lo añadían. Cuando decía «necesitaremos celery para esta tarea en segundo plano», lo añadían. Si esas elecciones seguían teniendo sentido seis meses después no era una pregunta para la que tuvieran herramientas.

La consecuencia práctica era un sistema Frankenstein. Capa tras capa de bibliotecas elegidas por IA, cada una añadida para resolver un problema en el momento, ninguna revisada después. Cuando repasé correctamente las listas de dependencias, se podía eliminar alrededor del sesenta por ciento sin perder una sola pieza de funcionalidad útil. Simplemente estaban ahí: restos de enfoques abandonados, duplicados que hacían el mismo trabajo que algo ya presente, bibliotecas añadidas para una característica que se había reescrito tres sesiones después de una forma completamente distinta.

No es exclusivo de los sistemas creados con IA. He visto exactamente el mismo patrón en bases de código construidas por humanos en grandes clientes, de manera constante, durante años. La dirección cambia de rumbo. Los desarrolladores empiezan obedientemente el nuevo enfoque. El anterior nunca se limpia, no por pereza, sino porque nadie autorizó la limpieza y los desarrolladores no iban a levantar la mano para proponer trabajo extra sin ticket. El código muerto se queda. Las bibliotecas sin usar se quedan. Las abstracciones a medio terminar se quedan. La base de código se convierte en un registro arqueológico de cada giro estratégico que vino de arriba, sin retirar ninguna prueba. La IA sólo produce el mismo resultado más rápido y sin necesitar una capa de gestión para desencadenar el giro: basta un nuevo prompt.

El problema de las pruebas es un problema de confianza

La ausencia de pruebas se suele describir como un problema de calidad. También es un problema de confianza.

Sin pruebas, no puede comprobar que un cambio hizo lo que pretendía. No puede comprobar que no rompió otra cosa. No puede entregar la base de código a otro desarrollador y decir «las pruebas te dirán si rompiste algo». No puede desplegar con confianza. No puede refactorizar con seguridad. Se queda permanentemente esperando que lo que recuerda sobre el código siga siendo cierto.

Los no desarrolladores no saben que existen las pruebas ejecutables como práctica. Saben qué significa probar en el sentido cotidiano: recorrer la aplicación con clics y ver si funciona, pero las pruebas automatizadas, las suites de pruebas y el desarrollo guiado por pruebas no forman parte de su modelo mental. Si han oído hablar de pruebas, es como concepto técnico vago, algo que hacen los desarrolladores, posiblemente algo que se le pide añadir a la IA cuando uno se acuerda. Lo que no saben es que su presencia o ausencia da forma a toda la trayectoria de la base de código: que las pruebas dan terreno estable a los agentes de programación de IA, y una base creada sin ellas acumula problemas estructurales que hacen cada vez más difícil añadirlas después.

Esta es la parte más cruel de la trayectoria: el momento en que las pruebas se vuelven más valiosas es el momento en que son más difíciles de añadir. Una base de código sin disciplina de pruebas incorpora la imposibilidad de probar a su estructura. Funciones que hacen demasiadas cosas. Dependencias codificadas de forma rígida en lugar de inyectadas. Efectos secundarios incrustados en la lógica de negocio. Cuando quiere pruebas, primero necesita una refactorización, y no puede refactorizar con seguridad sin pruebas.

En un caso había una función central de cálculo de más de 300 líneas que leía de una base de datos, llamaba a una API externa, aplicaba reglas de negocio, formateaba salida y escribía un registro en un archivo, todo en secuencia, sin separación de responsabilidades. Escribir una prueba para ella habría requerido una base de datos real, una clave de API real y un sistema de archivos real, o una reescritura considerable. Nunca se había probado. Durante la revisión aparecieron casos límite que producían resultados incorrectos, el tipo de cosa que habría llegado a los usuarios el primer día.

Cuando las especificaciones reemplazan a las pruebas

Un cliente tenía formación de programación, no reciente, pero real. Décadas atrás, antes de frameworks, nube e IA, había escrito código. Trajo ese instinto de estructurar el trabajo, lo cual era bueno. La dirección que le dio, menos.

Había adoptado lo que llamaba desarrollo guiado por especificaciones: archivos Markdown detallados que describían cómo debía comportarse la aplicación. Docenas de ellos, acumulados durante meses. Documentaban características, casos límite, decisiones tomadas y revisadas, requisitos que habían evolucionado a medida que crecía la aplicación. Los usaba como contexto para cada conversación con Claude, esperando que el modelo los aplicara fiel y consistentemente.

El problema era que las especificaciones se habían convertido en un registro de la historia de la aplicación en vez de una descripción de su estado actual. Contenían contradicciones: decisiones anteriores reemplazadas por otras posteriores, sin que se eliminaran las primeras. Describían comportamientos parcialmente implementados, implementados de otro modo o abandonados. Claude, con ese contexto, hizo lo que hace un modelo con instrucciones en conflicto: produjo resultados localmente plausibles, pero globalmente inconsistentes. Las características retrocedían. El comportamiento cambiaba entre sesiones sin motivo aparente. El cliente no tenía forma de detectarlo porque no había comprobaciones ejecutables, sólo más Markdown.

La corrección fue incómoda, pero directa: borrar los archivos de especificación. No archivarlos; borrarlos. Luego escribir pruebas que describieran lo que la aplicación hacía de verdad, ahora mismo y de forma verificable. Una vez que la suite capturó el comportamiento real, Claude tenía algo estable contra lo que trabajar. Las regresiones se hicieron visibles inmediatamente. El desarrollo se estabilizó.

La lección no es que la documentación sea inútil. Es que la documentación no puede hacer el trabajo de las pruebas. Un archivo Markdown puede describir el comportamiento previsto. Sólo una prueba puede verificarlo. El modelo no sabe cuáles de sus especificaciones son actuales, cuáles son aspiracionales y cuáles simplemente son erróneas, a menos que le dé algo que se ejecute.

"Borra las especificaciones. Escribe pruebas que describan lo que la aplicación hace realmente. Entonces el desarrollo puede avanzar."

El bug que en realidad era una brecha de arquitectura

Un propietario llegó con lo que entendía como unos pocos bugs de permisos: determinadas acciones que debían restringirse a roles concretos estaban disponibles para todos. Operaciones sensibles, del tipo que sólo debería realizar un administrador o un aprobador designado, quedaban abiertas a cualquier usuario que hubiera iniciado sesión.

Leídos como bugs, parecen pequeños: unas cuantas comprobaciones en el sitio incorrecto. Leídos correctamente, son síntomas de un modelo de autorización ausente. La aplicación tenía roles sólo de nombre. No existía un concepto coherente de quién puede hacer qué, aplicado en un lugar y en todas partes. Los permisos se habían añadido ad hoc, característica por característica, donde la IA conectaba alguno cuando se le pedía, y se habían omitido donde no se pedían explícitamente. Para una aplicación que trata acciones organizativas sensibles, eso no es un defecto cosmético. Es el tipo de brecha que, en producción, se convierte en un incidente con consecuencias legales.

Un no desarrollador lo comunica como «algunos usuarios pueden hacer cosas que no deberían». Es una descripción precisa del síntoma. Lo que no puede ver es que el síntoma señala la ausencia de toda una capa arquitectónica: autenticación y autorización como decisión de diseño deliberada y centralizada, no como una dispersión de condicionales. La IA nunca construyó esa capa porque nunca se le pidió pensar en el sistema como sistema. Se le pidió añadir características. Cada característica funcionaba de forma aislada. La preocupación transversal que debía gobernarlas a todas simplemente no existía.

La elección tecnológica hizo que esto fuera casi inevitable. Construya la misma aplicación con Spring Boot y obtiene Spring Security prácticamente gratis: un framework de seguridad con raíces de dos décadas, probado en miles de sistemas empresariales, que le da autenticación, autorización basada en roles y expresiones, control de acceso a nivel de método, protección CSRF, gestión de sesión y codificación de contraseñas como una capa coherente que se espera que conecte. Todo el ecosistema asume que la seguridad es una preocupación transversal porque el framework fue construido por gente que ha visto lo que sucede cuando no lo es. En la pila típica de Python elegida por IA —FastAPI, Flask— nada de eso existe. Como mucho obtiene primitivas OAuth2 y puntos de inyección de dependencias, y ensambla el resto por su cuenta, biblioteca a biblioteca, decisión a decisión. No hay un equivalente que llegue completo y le obligue a hacer la pregunta. (Django es la excepción que confirma la regla: incluye un sistema real de autenticación y permisos, pero Django no es lo que la IA elige cuando un no desarrollador pide un backend.) Así que el modelo eligió la pila con menos protección incorporada y luego construyó fielmente una aplicación sin ella. Nadie eligió ese resultado. Salió de dos valores por defecto apilados.

Aquí es donde se hacen concretos los límites de externalizar el juicio a un modelo. La IA puede implementar una comprobación de permisos sin defectos. Lo que no hace, sin que se le pida, es dar un paso atrás y preguntar: ¿cuál es el modelo de acceso para toda esta aplicación?, ¿quiénes son los actores?, ¿dónde están los límites de confianza?, ¿y dónde deben imponerse? Son preguntas de diseño y comprensión del dominio. Requieren a alguien que haya visto qué sucede cuando no se formulan, normalmente porque ha limpiado las consecuencias. Esa experiencia todavía no viene en un modelo. Viene de haber sido responsable de las consecuencias.

Donde sigue viviendo el juicio humano

Nada de esto es un argumento contra las herramientas de programación con IA. Son realmente potentes, y los clientes de estas historias llegaron más lejos con ellas de lo que habrían llegado solos. El punto es más estrecho y duradero: construir software no es lo mismo que producir código, y la brecha entre ambos es exactamente donde sigue viviendo el juicio humano experimentado.

La IA responde la pregunta que se le formula. No sabe qué preguntas importan. No se opone, no sopesa compensaciones frente a un contexto que no puede ver, ni reconoce la ausencia de algo que debería estar. Construirá gustosamente bien la cosa equivocada. Saber qué construir, qué dejar fuera, cuándo dejar de añadir y dónde se esconden los riesgos reales: ese es el trabajo que no se externaliza. Todavía no, y no porque los modelos sean débiles. Porque ese juicio se forma con consecuencias, y un modelo nunca ha respondido por una.

Así que si ha construido algo impresionante con una herramienta de IA y está a punto de abrirlo a usuarios reales, lo más valioso que puede hacer es pedir a alguien con experiencia real que lo revise antes, no para quitárselo, sino para formular las preguntas en las que nadie pensó.

"La IA construirá gustosamente bien la cosa equivocada. Saber qué construir es la parte que no se externaliza."

Divulgación completa: este texto fue escrito con ayuda de un LLM, pero no por el LLM. Las historias, el juicio, el argumento y cada afirmación son míos. El modelo me ayudó a dar forma a las palabras. No aportó la experiencia. Esa distinción es, en cierto sentido, todo el punto.

Hablemos de la situación

Cuénteme qué está pasando. Yo escucho, hago algunas preguntas prácticas y le devuelvo lo que veo: dónde puede estar el riesgo, qué puede estar bloqueando la entrega y qué parece valer la pena revisar después. Sin discurso comercial, sin compromiso. Confidencial y directo.

Iniciar una conversación

Newsletter: Sin teatro metodológico. Sin relleno.
Ideas reales sobre entrega de software y liderazgo.

×