Ir al contenido

Modernización de un frontend heredado

Sin TypeScript. Sin linter. Sin Sentry. 170 ubicaciones lo usan a diario.

Modernizar de forma incremental un frontend heredado, sin tipos ni monitorización, mientras el producto seguía disponible para sus usuarios.

5 min de lecturaPor

Las limitaciones heredadas eran reales

El frontend de CRA heredado estaba escrito en JavaScript puro, sin TypeScript, ESLint, Prettier, Sentry, un sistema de componentes reutilizables ni una estructura coherente por funciones. Contenía más de 5.000 líneas de CSS sin procesar, clases de Tailwind sobrescritas con estilos en línea, páginas copiadas y una estructura plana de directorios.

Los problemas se reforzaban entre sí. Los cambios de la API llegaban al navegador sin avisos del compilador. Las pantallas copiadas repetían los mismos errores de estilo. Los errores de producción solían llegar como informes de usuarios porque no había una vía de supervisión.

El costo de mantenimiento acabó afectando a los usuarios

La aplicación seguía atendiendo 170 ubicaciones de clientes cada día. No convertimos V1 sobre la marcha ni esperamos un sustituto completo. Mantuvimos las rutas antiguas en funcionamiento y exigimos que cada ruta nueva de V2 cumpliera los estándares nuevos.

Eso dio al equipo una regla sencilla: no ampliar las convenciones heredadas. Traslada la responsabilidad cuando se reconstruya una ruta y elimina la antigua después de que la nueva funcione en producción.

Crear un perímetro tipado

Next.js 15 y TypeScript formaron el perímetro nuevo. Las rutas nuevas usaban definiciones tipadas, clientes de API generados, comportamiento compartido para las solicitudes y componentes propiedad de cada función. El equipo no convirtió primero todos los archivos heredados; dejó de añadir superficie nueva sin tipos y trasladó la responsabilidad a V2 a medida que el trabajo alcanzaba cada ruta.

  • TypeScript y las rutas tipadas hicieron visibles durante el desarrollo los errores de navegación y de forma de la API.
  • Los clientes generados y el comportamiento compartido para las solicitudes sustituyeron convenciones dispersas.
  • Las carpetas por función asignaron responsables explícitos a rutas, hooks, esquemas y pruebas.
  • Los elementos reutilizables sustituyeron las copias a nivel de página para patrones de interacción repetidos.

Añadir ciclos de retroalimentación antes de trasladar cada pantalla

La modernización también cambió cómo se detectaban los fallos y cómo se admitían los cambios. Sentry añadió informes del cliente, servidor y entorno perimetral, además de límites de errores de la aplicación. Los flujos de pruebas unitarias y de navegador obtuvieron controles obligatorios explícitos, mientras las pruebas centradas en el comportamiento cubrieron recorridos de alto riesgo como Investor Intake.

Estos controles no reparaban V1 automáticamente. Hacían observable y comprobable cada ruta V2 antes de que heredara más responsabilidad de producción.

Construye el perímetro nuevo alrededor del producto antiguo

V2 era responsable del marco global, la autenticación y cada función recién migrada. CRA permanecía dentro de un único iframe solo para las rutas que todavía controlaba. El artículo complementario sobre la migración explica en detalle el puente de postMessage, SSO y enrutamiento.

Para este artículo, el punto importante es la responsabilidad: los estándares nuevos se aplicaban en el límite de V2 y cada migración terminada reducía la cantidad de código exento de ellos.

Haz visible la responsabilidad durante la transición

La responsabilidad se registró de forma explícita durante la transición. Navbar, Topbar, Settings, Investor Intake, Authentication y Twilio pasaron a V2. Home, Genius Mode, Deals y Buyers permanecieron en V1 hasta que sus sustitutos estuvieron listos. Las ubicaciones de clientes se trasladaron en grupos controlados en lugar de recibir todas las superficies incompletas a la vez.

Ese inventario evitó que la reescritura se convirtiera en un proyecto paralelo indefinido. Cada función seguía siendo propiedad de V1, se servía mediante el límite de compatibilidad o era nativa en V2.

La modernización es una secuencia, no un evento

La transición final eliminó el iframe, los clientes generados heredados y el código del puente, y después limpió rutas obsoletas, pruebas, protecciones de autenticación, código compartido del marcador y estructura de componentes. La modernización solo terminó cuando fue posible borrar el límite temporal.

  • No midas el progreso por el número de archivos nuevos del framework.
  • Mide qué responsabilidades de producción se han trasladado y qué rutas de compatibilidad pueden eliminarse.
  • Mantén el código nuevo dentro de los estándares nuevos en lugar de esperar una conversión perfecta de toda la base de código.
  • Elimina la infraestructura temporal de migración después de trasladar la última superficie que dependa de ella.