Construir sobre legacy: decisiones, no magia
🧱 Legacy: el verdadero desafío no es el código, es el contexto
Hay algo que tarde o temprano le pasa a cualquier desarrollador: dejás de escribir features “greenfield” y empezás a convivir con sistemas que ya existen.
Y ahí aparece el famoso legacy.
No ese legacy romántico que se usa en conferencias, sino el real: el que factura, el que nadie quiere tocar, el que “funciona… más o menos”.
Después de varios proyectos, hay patrones que se repiten. No importa la empresa, el stack o el país.
Este es un resumen bastante honesto de los problemas más comunes.
🔗 1. Todo es HTTP… y nada más
Uno de los primeros olores:
“Para todo hacemos un request HTTP”
Comunicación sincrónica para absolutamente todo
Dependencias en cascada entre servicios
Timeouts que generan errores fantasma
Retries sin control → duplicación de operaciones
Problema real
Cuando todo depende de HTTP:
No hay desacople real
No hay resiliencia
No hay control de flujo
Un servicio lento empieza a arrastrar a todos.
Qué suele faltar
Eventos (Kafka, SQS, etc.)
Colas para procesos async
Idempotencia bien pensada
📉 2. Observabilidad: “console.log y rezar”
Otro clásico:
“Sí, logueamos… creo”
Logs inconsistentes
Sin correlación entre requests
Sin métricas reales
Sin tracing
Resultado
Cuando algo falla:
No sabés dónde
No sabés por qué
No sabés cuándo empezó
Debuggear se vuelve arqueología.
Señales claras de problema
“No se puede reproducir”
“En local funciona”
“Debe ser algo del cliente”
🧪 3. Ambientes: cada uno juega un juego distinto
Este es de los más destructivos:
main ≠ develop
develop ≠ staging
staging ≠ producción
Y encima:
Configs hardcodeadas
Feature flags inexistentes
Seeds inconsistentes
Resultado
Bugs que aparecen “solo en prod”
Releases con miedo
Hotfixes constantes
🗄️ 4. Base de datos: creció… pero no evolucionó
La base de datos suele ser el cuello de botella silencioso.
Tablas gigantes sin partición
Queries sin índices
Relaciones mal diseñadas
Migraciones inexistentes o peligrosas
Frase típica
“No toques eso que rompe todo”
Problemas comunes
Performance degradándose con el tiempo
Locks
Queries de segundos/minutos
🧩 5. Acoplamiento invisible
Este es el más traicionero.
No está documentado, pero existe:
Cambiás algo en un servicio → rompe otro
Campos que “nadie usa”… pero alguien sí
Lógicas duplicadas en múltiples lugares
Resultado
El sistema deja de ser predecible.
🔁 6. Falta de idempotencia
Especialmente en sistemas financieros o integraciones:
Retries generan duplicados
Webhooks procesados múltiples veces
Estados inconsistentes
Esto no es un bug menor. Es deuda técnica crítica.
⚙️ 7. CI/CD débil o inexistente
Tests que no corren siempre
Pipelines lentos o poco confiables
Deploys manuales
Resultado
Se rompe producción
Nadie confía en el pipeline
Se deploya “con miedo”
🧠 Entonces… ¿el problema es el legacy?
No exactamente.
El problema no es que el sistema sea viejo.
El problema es:
La falta de decisiones técnicas sostenidas en el tiempo.
🧭 Cómo empezar a salir (sin romper todo)
No existe “rebuild mágico”.
Pero sí hay estrategias:
1. Introducir observabilidad primero
Antes de tocar lógica:
logs estructurados
tracing básico
métricas
2. Cortar el acoplamiento progresivamente
anti-corruption layers
wrappers
mappers
3. Meter asincronía donde duele
colas
eventos
outbox pattern
4. Atacar puntos críticos, no todo
endpoints más usados
queries más lentas
flujos más sensibles
5. Idempotencia como regla, no excepción
🧩 Reflexión final
El legacy no es un enemigo.
Es una foto de decisiones pasadas, bajo otras presiones, otros tiempos y otros contextos.
El verdadero desafío como desarrolladores (y más como TL) es este:
Mejorar el sistema sin frenar el negocio.
Y eso no se logra con reescrituras épicas.
Se logra con criterio, paciencia… y muchas pequeñas decisiones bien hechas.