La señal de alarma
Empezó con quejas de usuarios: "la app se cuelga en la tarde", "los reportes tardan 5 minutos en cargar". Después vino el CTO a una reunión con los inversores diciendo que necesitaban 8 meses y un equipo nuevo para "hacerlo bien esta vez". La startup no tenía 8 meses. Con 10k usuarios activos y creciendo, el colapso operacional era cuestión de semanas.
El síntoma clásico: Cuando una startup dice "hay que reescribir todo", lo que realmente está diciendo es "perdimos la comprensión de nuestro propio sistema". El rewrite es la solución emocional. El diagnóstico es la solución racional.
El diagnóstico (2 semanas)
Aplicamos un protocolo de diagnóstico arquitectónico que desarrollamos en proyectos anteriores. No miramos código al azar — buscamos patrones específicos:
Día 1-3: Mapeo de síntomas vs causas
El equipo reportaba "problemas de rendimiento general". Pero cuando pusimos APM (AppDynamics trial) y correlacionamos con logs, encontramos que el 92% de los incidentes ocurrían en ventanas de 30 minutos después de las 14:00. No era "rendimiento general" — era un cuello de botella puntual.
Resultado: un cron job de sincronización contable que corría a las 14:00, escrito por un practicante 2 años atrás. Hacía un SELECT * sobre una tabla con 2 millones de registros y luego procesaba en memoria. Bloqueaba la base de datos durante 15 minutos.
Día 4-6: Análisis de base de datos
Revisamos el esquema, los queries lentos y los patrones de acceso:
- Índices faltantes: 7 tablas sin índices en columnas que se consultaban a diario
- N+1 queries en serie: el endpoint de "dashboard del cliente" hacía 47 queries individuales cuando podía resolverse con 3
- Conexión única a base de datos — sin pool de conexiones. Cada query nuevo abría una conexión TCP separada
- Modelo de datos anémico: tablas genéricas con columnas JSON donde debería haber relaciones explícitas
Nada de esto requería cambiar de lenguaje o reescribir la aplicación.
Día 7-10: Revisión de frontend y assets
El frontend cargaba 4.2 MB de JavaScript sin minificar, incluyendo 3 librerías de gráficos que no se usaban ("las dejamos por si acaso"). El tiempo de carga inicial en 3G era de 14 segundos. Implementar tree-shaking + lazy loading redujo a 1.8 MB y 4 segundos sin tocar una línea de lógica de negocio.
Las intervenciones (4 semanas)
No reescribimos nada desde cero. Aplicamos cambios quirúrgicos priorizados por impacto:
- Semana 1 — Matar el cron y optimizar el query (1 día de trabajo)
Reemplazamos el cron sincrónico por un job asíncrono con paginación. El query que bloqueaba 15 minutos pasó a ejecutarse en 200ms. Impacto inmediato: el 92% de los incidentes de la tarde desaparecieron. - Semana 2 — Pool de conexiones + índices (2 días)
Agregamos HikariCP como pool de conexiones. En 2 horas de trabajo. Agregamos 12 índices compuestos basados en los queries lentos identificados. Reducción de latency promedio en API: 65%. - Semana 3 — Refactor del dashboard endpoint (3 días)
Reescribimos el endpoint del dashboard para hacer 3 queries en vez de 47. UsamosJOINcon índices existentes. Tiempo de carga del dashboard: de 5 minutos a 800ms. - Semana 4 — Tree-shaking + lazy loading (1 día)
Limpiamos dependencias muertas y aplicamos lazy loading en rutas del frontend. Tamaño de JS bajó de 4.2 MB a 1.8 MB. Carga inicial en 3G: de 14 a 4 segundos.
Dato concreto: 7 días hábiles de trabajo efectivo resolvieron los síntomas que el equipo atribuía a "arquitectura incorrecta". El rewrite que iba a costar 8 meses era una solución equivocada para un problema mal diagnosticado.
Resultados
- Latencia API promedio: reducción del 65%
- Carga de dashboard: de 5 min a 800ms
- Incidentes diarios: de 12+ a 0 (después de la semana 1)
- Tamaño JS frontend: reducción del 57%
- Costo de infraestructura: sin cambios — no se necesitó escalar
- Roadmap recuperado: los 8 meses que iban a gastar en rewrite se usaron para construir features que los usuarios pedían
Lo que aprendimos
- El rewrite casi nunca es la respuesta. Especialmente en startups, donde la deuda técnica duele menos que el costo de oportunidad de 8 meses sin features nuevas.
- Mide antes de tocar. Sin APM y análisis de logs, el equipo jamás habría identificado el cron job de las 14:00. Estaban convencidos de que el problema era "la arquitectura".
- Los problemas de rendimiento casi siempre son puntuales. Una consulta, un índice faltante, un asset pesado. Rara vez son "el stack entero".
- El mejor diagnóstico lo hace alguien externo. El equipo estaba tan metido en el día a día que normalizó el rendimiento degradado. Nosotros vimos en una semana lo que ellos llevaban meses sintiendo sin poder articular.