metis-desk/.agents/skills/rdx-solid/referencias/arquitectura-legacy.md

7.6 KiB

Arquitectura y evolución de sistemas heredados (Legacy)

Referencia especializada del skill rdx-solid. Consulta arquitectura.md y el documento del ámbito afectado: arquitectura-backend.md, arquitectura-frontend.md o arquitectura-shared.md.

1. Propósito

Modernizar y mantener sistemas existentes con seguridad, preservando comportamientos y contratos requeridos. «Legacy» no significa necesariamente código de baja calidad: puede ser software estable, valioso y escasamente documentado.

Prioridad: comprender antes de cambiar; verificar antes de declarar el cambio correcto. No imponer patrones o nomenclaturas nuevas de forma masiva.

2. Reconocimiento inicial

  1. Identifica límites del sistema, ejecutables, servicios y consumidores.
  2. Revisa dependencias, versiones, compilación y despliegue.
  3. Localiza contratos públicos, formatos de intercambio y persistencia.
  4. Identifica comportamientos implícitos, trabajos programados y efectos secundarios.
  5. Comprueba las pruebas existentes y los mecanismos de recuperación.
  6. Delimita la tarea, sus riesgos y los componentes afectados.

No presupongas que un comportamiento aparentemente extraño es un error: puede ser un requisito histórico o un contrato con consumidores externos.

3. Caracterización del comportamiento

Cuando falten especificaciones o pruebas, utiliza ejemplos de entrada y salida, datos anonimizados, consultas, trazas o pruebas de caracterización para describir el comportamiento actual.

Distingue:

  • Comportamiento a conservar: contratos y resultados vigentes necesarios.
  • Defecto a corregir: fallo confirmado respecto al comportamiento esperado.
  • Cambio funcional: nuevo requisito que modifica la semántica.

No conviertas automáticamente un fallo conocido en una obligación permanente mediante una prueba de caracterización.

4. Refactorización incremental

  • Realiza cambios pequeños y reversibles cuando sea posible.
  • Separa las correcciones funcionales de las refactorizaciones generales.
  • Introduce pruebas de regresión en torno a comportamientos críticos cuando sea viable.
  • No renombres, reformatees o muevas grandes áreas ajenas a la tarea.
  • Conserva convenciones y límites de módulos existentes salvo necesidad justificada.
  • Utiliza adaptadores temporales si permiten migrar consumidores gradualmente.
  • Evita reescrituras completas sin evaluación de costes, riesgos y continuidad del servicio.

La ausencia de pruebas no prohíbe todo cambio: exige mecanismos de verificación proporcionales, mayor cautela y documentación de incertidumbres.

5. Estrategias de modernización

Estrategia Cuándo considerarla Riesgo a controlar
Refactorización localizada Corregir estructura sin cambiar contratos Regresiones involuntarias
Adaptador / fachada Aislar un contrato antiguo Traducción semántica incorrecta
Capa anticorrupción Separar modelos de dominio antiguo y nuevo Complejidad de mapeo
Strangler Fig Sustituir capacidades progresivamente Enrutamiento y coexistencia
Migración por etapas Cambiar persistencia o infraestructura Consistencia y reversión
Sustitución completa Sistema realmente inviable de mantener Alcance, datos y paridad funcional

Escoge la opción con menor riesgo y coste total razonable; no asumas que reescribir equivale a mejorar.

6. Capas de adaptación y anticorrupción

Una capa anticorrupción evita que el nuevo dominio adopte conceptos o errores del modelo antiguo.

interface CustomerDirectory {
  findCustomer(id: CustomerId): Promise<Customer | null>;
}

class LegacyCustomerAdapter implements CustomerDirectory {
  constructor(private readonly legacyApi: LegacyCustomerApi) {}

  async findCustomer(id: CustomerId): Promise<Customer | null> {
    const legacyRecord = await this.legacyApi.readCustomer(id.value);
    return legacyRecord ? mapLegacyCustomer(legacyRecord) : null;
  }
}

Los tipos y colaboradores son ilustrativos. Verifica diferencias de identificación, nulos, fechas, moneda, errores y codificación: un mapeo estructural no garantiza equivalencia semántica.

No crees una capa anticorrupción cuando un adaptador sencillo sea suficiente.

7. Migración de datos y persistencia

  • Determina esquemas, claves, restricciones, volumen y dependencias.
  • Diseña migraciones reproducibles con validaciones de integridad.
  • Evalúa ventanas de mantenimiento, backups y recuperación.
  • Considera expansión-contracción para cambios de esquema compatibles.
  • Si existe doble escritura, define fallos, reconciliación y fuente de verdad; no la adoptes sin necesidad.
  • Verifica volumen, rendimiento y compatibilidad con versiones desplegadas.
  • Evita transformaciones destructivas sin un procedimiento probado o adecuado de recuperación.

8. Contratos, compatibilidad y despliegue

Identifica qué consumidores pueden quedar afectados: clientes externos, informes, procesos por lotes, integraciones, archivos de intercambio, aplicaciones móviles o servicios anteriores.

  • Mantén formatos y significado de campos cuando sea requerido.
  • Utiliza versionado o adaptadores si los consumidores no pueden migrar a la vez.
  • Controla coexistencia de versiones y despliegues escalonados.
  • Define condiciones de reversión cuando el riesgo lo exija.
  • No elimines endpoints o campos aparentemente no usados sin verificar consumidores externos.

9. Dependencias y tecnologías obsoletas

  • Determina compatibilidad y riesgos de seguridad de runtimes, librerías y drivers.
  • No actualices todas las dependencias durante una corrección puntual sin necesidad.
  • Prioriza vulnerabilidades o incompatibilidades relevantes según su impacto.
  • Realiza actualizaciones por etapas y verifica sus contratos.
  • Documenta dependencias no sustituibles y mecanismos de mitigación.

10. Pruebas y seguimiento

  • Pruebas de caracterización para comportamiento existente.
  • Regresión para defectos corregidos.
  • Integración para adaptadores y persistencia.
  • Contrato para consumidores externos y coexistencia.
  • E2E para flujos de negocio críticos.
  • Comparación controlada de resultados antiguo/nuevo cuando sea viable.

Evita utilizar exclusivamente métricas de cobertura como garantía de migración. Observa errores, tiempos de respuesta, integridad de datos y resultados funcionales tras un cambio cuando el entorno lo permita.

11. Señales de alerta

  • Reescribir todo antes de conocer el comportamiento existente.
  • Confundir limpieza estética con mejora arquitectónica necesaria.
  • Modificar contratos sin inventariar consumidores.
  • Migrar datos sin validar integridad ni recuperación.
  • Repartir reglas inconsistentes entre implementación antigua y nueva.
  • Eliminar lógica aparentemente redundante con efectos históricos desconocidos.
  • Introducir frameworks nuevos para una corrección localizada.
  • Declarar paridad funcional sin pruebas o evidencias suficientes.

12. Lista de comprobación

  • ¿Conozco comportamiento, contratos y consumidores afectados?
  • ¿He distinguido defectos de comportamientos históricos a conservar?
  • ¿La estrategia de migración es proporcional al riesgo?
  • ¿Existe verificación antes y después del cambio?
  • ¿La integridad de los datos y la compatibilidad están protegidas?
  • ¿Se han previsto reversión o recuperación cuando corresponda?
  • ¿He evitado reestructuraciones ajenas a la tarea?
  • ¿He comunicado incertidumbres y verificaciones pendientes?

Principio final: modernizar significa reducir el riesgo y mejorar la capacidad de evolución, no reescribir por preferencia tecnológica.