Juanrobilara.

Vibe Coding - ¿Realmente es tan malo?

Vibe Coding: cuando el código "funciona"... pero no sabemos por qué

En los últimos años apareció un fenómeno bastante común: el vibe coder. Ese desarrollador que programa por intuición, copia snippets, prueba cosas hasta que más o menos anda… y luego pasa a lo siguiente.

El problema no es que el código funcione hoy. El problema es cuando alguien tiene que mantenerlo mañana (a veces ese alguien sos vos mismo).

En este artículo vamos a ver errores clásicos del vibe coding, por qué son peligrosos y cómo corregirlos.

Ante todo, no estoy en contra del vibe coding, pero si considero que al realizar este tipo de prácticas se debería ser más responsables y detallados.

1. Credenciales expuestas en el código

Error típico

javascript
const db = connectDB({ host: "localhost", user: "admin", password: "123456", database: "app_prod" });

Esto aparece muchísimo en repositorios de GitHub.

Problemas:

  • credenciales filtradas
  • ataques automatizados
  • bases de datos comprometidas
  • imposible rotar credenciales fácilmente

Corrección

Usar variables de entorno.

javascript
const db = connectDB({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME });

Y un .env

DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=strongpassword
DB_NAME=app_prod

Regla simple:

Si hay un secreto en tu código, ya lo filtraste.


2. SQL Injection por concatenación de strings

Error típico

javascript
app.get("/user", (req, res) => { const query = "SELECT * FROM users WHERE id = " + req.query.id; db.query(query, (err, result) => { res.send(result); }); });

Un atacante puede mandar:

?id=1 OR 1=1

Y listo: acceso a toda la base.

Corrección

Usar queries parametrizadas.

javascript
app.get("/user", (req, res) => { const query = "SELECT * FROM users WHERE id = ?"; db.query(query, [req.query.id], (err, result) => { res.send(result); }); });

Esto evita que el input se ejecute como SQL.


3. El archivo monstruo de 2000 líneas

Error típico

app.js

Contiene:

  • rutas
  • lógica de negocio
  • conexión a base
  • validaciones
  • middlewares
  • helpers
  • utilidades

Todo en el mismo archivo.

Resultado: infierno de mantenimiento.

Corrección

Separar responsabilidades.

Ejemplo de estructura simple:

src/
 ├ controllers/
 │   └ userController.js
 ├ services/
 │   └ userService.js
 ├ routes/
 │   └ userRoutes.js
 ├ models/
 │   └ userModel.js
 └ app.js

Regla básica:

Si tu archivo requiere mucho scroll, ya es una red flag.


4. Código duplicado por todos lados

Error típico

javascript
function calculatePrice(price){ return price * 1.21; } function calculateCart(price){ return price * 1.21; } function calculateTotal(price){ return price * 1.21; }

Tres funciones iguales.

Cuando cambie el impuesto, hay que modificar todo el código.

Corrección

Centralizar lógica.

javascript
function applyTax(price){ const TAX = 1.21; return price * TAX; }

Luego reutilizar.

javascript
const total = applyTax(product.price);

Principio clave:

DRY — Don't Repeat Yourself


5. Manejo de errores inexistente

Error típico

javascript
app.get("/users", async (req,res)=>{ const users = await db.getUsers(); res.json(users); });

Si la base falla → la app crashea.

Corrección

Manejo de errores explícito.

javascript
app.get("/users", async (req,res)=>{ try{ const users = await db.getUsers(); res.json(users); }catch(error){ console.error(error); res.status(500).json({error:"Internal server error"}); } });

Esto evita:

  • crashes
  • fugas de información
  • errores silenciosos

6. Código espagueti (dependencias cruzadas)

Error típico

userController → orderService → paymentService → userController

Dependencias circulares.

Después nadie entiende qué se ejecuta primero.

Corrección

Arquitectura clara.

Patrón simple:

Routes
 ↓
Controllers
 ↓
Services
 ↓
Repositories / Models

Cada capa tiene una responsabilidad clara.


7. No hay validación de inputs

Error típico

javascript
app.post("/register",(req,res)=>{ createUser(req.body); });

Si alguien manda:

json
{ "email": "<script>alert(1)</script>" }

Puede terminar en:

  • XSS
  • datos corruptos
  • errores inesperados

Corrección

Validar datos.

Ejemplo simple:

javascript
if(!req.body.email){ return res.status(400).send("Email requerido"); }

O usar librerías de validación.


8. Sin tests

El vibe coder prueba así:

funciona en mi máquina

Pero cuando el código crece:

  • aparecen regresiones
  • bugs inesperados
  • deploys peligrosos

Corrección

Agregar tests mínimos.

javascript
test("applyTax adds 21%", ()=>{ expect(applyTax(100)).toBe(121); });

No hace falta obsesionarse con cobertura.

Pero algo de testing cambia todo.


Conclusión

El vibe coding no es el enemigo.

De hecho es muy útil para prototipar rápido.

El problema aparece cuando el prototipo se convierte en producción sin disciplina técnica.

La diferencia entre un proyecto amateur y uno profesional suele ser:

  • estructura
  • seguridad
  • mantenibilidad
  • escalabilidad

Y la regla de oro:

Si dentro de seis meses no entendés tu propio código, el problema no es la memoria. Es la arquitectura.