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.
← Volver a blog