# Refactorizar código legacy con IA sin romper producción

URL: https://agentvera.dev/es/blog/refactor-legacy-code-with-ai/ · Publicado: 2026-10-25

Cómo refactorizar código legacy con agentes de IA sin riesgos: tests de caracterización primero, pasos pequeños, migraciones a TypeScript, revisión y rollback.

**En resumen:**

- Antes de que un agente toque código legacy, haz que fije el comportamiento actual con tests de caracterización; sin esa red no sabrás distinguir un refactor de una reescritura.
- Trabaja en pasos pequeños, cada uno en su propio commit y con los tests en verde, y deja los cambios de comportamiento fuera de los commits de refactor para poder revertir cualquier paso por separado.
- Migraciones como pasar de JavaScript a TypeScript o actualizar un framework salen mejor módulo a módulo, dejando que el compilador, los tests y un codemod hagan todo el trabajo posible.
- En AgentVera cada paso puede ir en su propio worktree, revisarse y verificarse al terminar el turno del agente y llegar a main por la cola de fusión sobre la última versión.

Refactorizar código legacy con IA es poner a un trabajador muy rápido y muy seguro de sí mismo delante de la parte del código que nadie entiende del todo. Puede salir bien. Los agentes tienen paciencia con archivos de 3.000 líneas, no les importa renombrar una función en doscientos sitios y leen código viejo sin resoplar. También puede salir mal: una «limpieza» que cambia una regla de redondeo, se lleva por delante un efecto secundario que nadie documentó o acaba convertida en una reescritura imposible de revisar.

Esta guía va del primer escenario. Explica cómo montar una red de seguridad antes del primer cambio, cómo mantener cada paso pequeño y reversible, cómo abordar migraciones como pasar de JavaScript a TypeScript o actualizar un framework, y cómo revisar y deshacer lo que ha hecho el agente.

## Por qué el código legacy también es difícil para los agentes

El código legacy es el código que te da miedo tocar, normalmente porque tiene pocos tests y muchas reglas no escritas. Lo que lo complica para las personas también lo complica para un agente:

- **El comportamiento vive en sitios raros.** Un formato de fecha en un helper, un reintento en un decorador, una variable global que lee otra parte.
- **Algunos bugs son funcionalidades.** Puede que un sistema externo dependa de un valor incorrecto. «Arreglarlo» rompe una integración que nunca has visto.
- **El código muerto parece vivo y el vivo parece muerto.** Reflexión, despacho por cadenas, cron jobs y plantillas llaman a funciones que ninguna búsqueda encuentra.
- **La ventana de contexto es finita.** Un agente ve los archivos que lee. No sabrá nada del proceso por lotes de otro repo que importa este módulo.

Además, un agente tiene una costumbre peligrosa aquí: mejora cosas. Pídele que extraiga una función y puede que de paso arregle el caso límite que vio, renombre variables y modernice la sintaxis. Cada cambio puede estar bien. Juntos dan un diff en el que no sabes qué se quería cambiar.

## Paso 1: primero, la red de seguridad

No dejes que el agente cambie una sola línea de código de producción hasta que el comportamiento que te importa esté fijado con tests. En código legacy eso significa tests de caracterización: tests que registran lo que el código hace ahora, no lo que debería hacer.

Un prompt que funciona:

> No cambies nada de código en `src/`. Escribe tests de caracterización para `src/orders/pricing.js` que registren su comportamiento actual, incluido todo lo que parezca incorrecto. Cubre cada rama que encuentres, también las de error. Donde el comportamiento parezca un bug, deja el test afirmando la salida actual y añade un comentario que empiece por `SUSPICIOUS:`. Ejecuta los tests y enséñame que pasan.

Algunos consejos:

- **Prueba a través de la interfaz pública.** Los tests que llaman al módulo como lo hace el resto de la aplicación sobreviven al refactor. Los que se meten en helpers privados se rompen cuando los mueves.
- **Usa entradas reales.** Payloads de ejemplo sacados de los logs (limpios de datos personales), archivos de fixtures o una copia de la base de datos de staging cubren los casos raros mucho mejor que entradas inventadas.
- **Aquí los archivos golden valen.** Para un generador de informes o una exportación, grabar la salida completa y compararla es un test de caracterización rápido y honesto, siempre que la salida sea determinista.
- **Comprueba que los tests pueden fallar.** Rompe el código a mano en un par de sitios o pasa una herramienta de mutation testing por el módulo. Si los tests siguen en verde, la red tiene agujeros.

La guía para [escribir tests unitarios con IA](/es/blog/write-unit-tests-with-ai/) trata con más detalle los tests de caracterización, la cobertura y el mutation testing.

Las notas `SUSPICIOUS:` valen oro. Son los bugs que arreglarás más adelante, a propósito, en sus propios commits, con alguien decidiendo que el nuevo comportamiento es el correcto.

## Paso 2: refactoriza en pasos pequeños y reversibles

Con la red puesta, mantén cada paso lo bastante pequeño como para revisarlo en unos minutos y deshacerlo sin tocar nada más.

### Separa estructura y comportamiento

La regla más útil: un commit de refactor solo cambia la estructura, y un cambio de comportamiento va en su propio commit. Díselo al agente sin rodeos:

> Esto es un refactor puro. No cambies el comportamiento, no arregles bugs, no cambies firmas públicas. Si ves algo que debería cambiar, apúntalo al final en lugar de hacerlo.

Si los tests de caracterización cambian en un commit de refactor, algo va mal. Eso te da una comprobación sencilla: `git diff --stat main -- tests/` no debería mostrar ediciones en los tests existentes.

### Un tipo de cambio por paso

Buenos tamaños de paso:

- Extraer una función o una clase.
- Mover un módulo y actualizar sus imports.
- Sustituir una API obsoleta en todo el código.
- Introducir una interfaz en una frontera para que el código viejo y el nuevo convivan.

Pide al agente que ejecute los tests después de cada paso y haga un commit con un mensaje claro antes de seguir. Un plan ayuda: «Propón el refactor como una lista numerada de pasos, cada uno dejando los tests en verde. Espera mi OK antes de empezar.» La mayoría de los agentes de código tienen un modo de planificación para esto; el plan mode de Claude Code, por ejemplo, explora y propone sin editar.

### Estrangula, no reescribas

Para una parte que de verdad hay que sustituir, pon la nueva implementación junto a la vieja detrás de una interfaz o un flag, pasa a los llamadores uno a uno y borra el código viejo cuando ya nadie lo use. Es el patrón strangler fig. Convierte un cambio arriesgado en muchos cambios pequeños y aburridos, y a los agentes se les da bien lo aburrido.

## Paso 3: migraciones con agentes

En las migraciones es donde los agentes más tiempo ahorran, porque el trabajo es amplio y repetitivo. También es donde los diffs se vuelven enormes. El truco es dejar la parte mecánica a las herramientas y las decisiones al agente.

### De JavaScript a TypeScript

Un camino que mantiene la aplicación funcionando todo el tiempo:

1. **Añade TypeScript junto a JavaScript.** En `tsconfig.json`, pon `allowJs: true` para que convivan archivos `.js` y `.ts`, y ejecuta `npx tsc --noEmit` en CI como comprobación de tipos.
2. **Empieza en modo permisivo.** Arranca con `strict: false`. Si quieres, activa `checkJs` o añade `// @ts-check` a archivos JS sueltos para encontrar problemas antes de renombrarlos.
3. **Convierte primero los módulos hoja.** Los archivos sin imports internos, como utilidades y constantes, son los más fáciles. Luego sube hacia los puntos de entrada.
4. **Una carpeta por paso.** Pide al agente que convierta `src/utils/` a `.ts`, añada tipos, mantenga los tests en verde y haga pasar `tsc --noEmit`. Luego la siguiente carpeta.
5. **Endurece poco a poco.** Cuando todo sea `.ts`, activa `noImplicitAny`, luego `strictNullChecks` y después `strict` completo, arreglando errores entre medias.

Dos reglas para darle al agente: nada de `any` sin un comentario que explique por qué, y nada de `@ts-ignore` para hacer desaparecer errores. Si no, el camino más rápido hacia un compilador en verde es ir apagándolo línea a línea.

### Actualizaciones de frameworks y librerías

En un salto de versión mayor, el orden importa:

1. **Lee primero la guía de migración.** Haz que el agente resuma la guía oficial de actualización y liste los cambios incompatibles que afectan a tu código, con rutas de archivo. Es un paso de solo lectura.
2. **Ejecuta el codemod oficial si existe.** Muchos proyectos publican codemods, por ejemplo `npx @next/codemod` para Next.js; en Java, las recetas de OpenRewrite cubren muchas actualizaciones. Un codemod es determinista; un agente no. Deja que el codemod haga todo lo que pueda.
3. **Deja al agente lo que sobra.** Los casos que el codemod no supo resolver, los wrappers propios, los tests que dependían del comportamiento antiguo.
4. **Sube una versión mayor cada vez.** Pasar de la 3 a la 6 de golpe apila todos los cambios incompatibles en un solo diff.

Fija el resultado esperado en tu prompt: «el build pasa, la suite de tests pasa, no hay advertencias nuevas en la consola». Un vago «actualiza a la última versión» invita al agente a subir de paso otros cinco paquetes.

## Paso 4: aísla el trabajo con worktrees

Un refactor largo no debería vivir en tu carpeta de trabajo principal, y los pasos en paralelo no deberían compartir una. Un [git worktree](/es/glossary/git-worktree/) da a cada paso su propia rama y su propia carpeta:

```bash
git worktree add ../app-ts-utils -b refactor/ts-utils
git worktree add ../app-ts-api -b refactor/ts-api
```

Ahora un agente convierte `utils`, otro convierte `api` y tú sigues trabajando en la carpeta principal. Cuando un paso está terminado y revisado, lo fusionas; cuando no lleva a ninguna parte, borras el worktree y la rama. Más en [git worktrees para agentes en paralelo](/es/blog/git-worktree-parallel-agents/).

Cuidado con los pasos en paralelo que tocan los mismos archivos. Dos agentes renombrando cosas en el mismo módulo producirán conflictos, y resolver conflictos en un refactor es justo por donde se cuela el comportamiento. Reparte el trabajo por carpeta o por módulo, no por tipo de cambio.

## Paso 5: revisa cada paso

Un diff de refactor es fácil de aprobar porque parece que no hace nada. Precisamente por eso hay que leerlo. Qué mirar:

- **¿Han cambiado los tests?** En un refactor puro, los tests existentes no deberían cambiar.
- **¿Han cambiado las firmas públicas?** Funciones exportadas, respuestas de la API, columnas de la base de datos, nombres de eventos.
- **¿Se ha borrado algo?** Pregunta al agente por qué cada función eliminada no se usaba. «No se encontraron referencias» no es una prueba cuando hay reflexión o despacho por cadenas.
- **¿Ha cambiado el manejo de errores?** Una excepción que antes se tragaba y ahora se propaga, o al revés, es un cambio de comportamiento.
- **¿El diff ha crecido más allá del paso?** Un paso de «mover este módulo» no debería reformatear de paso otros veinte archivos. Pide el formateo en su propio commit, o que no lo haga.

Un segundo modelo revisando cada turno detecta bastante de esto. Consulta [revisión de código con IA](/es/blog/ai-code-review/) para ver cómo funciona.

## Paso 6: planifica el rollback antes de necesitarlo

Deshacer sale barato si lo preparas:

- **Commits pequeños.** `git revert <sha>` quita un paso limpiamente. Un commit de 4.000 líneas solo se puede revertir entero.
- **Revierte, no reescribas.** Cuando algo ya está en main, revierte el commit o el merge en lugar de hacer force push sobre un historial compartido.
- **Bisect cuando algo se cuela.** Con commits pequeños y en verde, `git bisect` encuentra en unas pocas ejecuciones el paso que rompió el comportamiento.
- **Flags para los cambios arriesgados.** Cuando el código viejo y el nuevo conviven, un flag apaga el camino nuevo sin desplegar.
- **Deshacer dentro de la sesión.** Antes de hacer commit, puedes deshacer el último turno de un agente; consulta [cómo deshacer los cambios de Claude Code](/es/blog/undo-claude-code-changes/).

## Errores habituales

- **«Refactoriza este módulo» sin tests.** Obtienes una reescritura y ninguna forma de comprobarla.
- **Mezclar refactor y arreglos de bugs.** Cuando el comportamiento cambia, no sabes si era intencionado.
- **Una rama de migración gigante.** Se aleja de main, se acumulan los conflictos y nadie puede revisarla.
- **Fiarse de «no se usa».** La búsqueda no ve llamadas dinámicas, otros repos ni tareas programadas.
- **Dejar que el agente silencie al compilador.** `any`, `@ts-ignore` y reglas de lint desactivadas esconden el trabajo en lugar de hacerlo.
- **Fusionar pasos paralelos sin probarlos juntos.** Dos ramas en verde pueden ponerse en rojo al fusionarse, y para eso está una [cola de fusión](/es/blog/merge-queue-for-ai-agents/).

## Cómo hacerlo en AgentVera

AgentVera ejecuta CLIs de agentes de código lado a lado por proyecto, con git integrado, lo que encaja con el estilo paso a paso de un refactor de código legacy.

- **Un worktree por paso.** Desde el panel de worktrees, abre una rama y una carpeta para cada paso e inicia un agente directamente en ella: Claude Code en uno, Codex o Gemini CLI en otro. Tu carpeta principal se queda como está.
- **Checkpoints en cada turno.** Al empezar cada turno, la carpeta de trabajo se guarda en una referencia de git oculta, y se conservan los últimos 60 turnos por agente. Mira qué archivos cambió un turno y deshaz solo ese turno si el agente se pasó de la raya.
- **Revisión al final de cada turno.** La revisión de código automática lee el código que escribió el agente con el modelo de Claude que elijas y lista los hallazgos con su gravedad y su file:line; si quieres, los hallazgos vuelven al agente, hasta dos rondas seguidas.
- **Verify contra tus criterios.** Escribe en tu mensaje «refactor puro, todos los tests pasan, no ha cambiado ningún archivo de tests existente». Verify lo convierte en criterios y, al terminar el turno, un verificador independiente que no puede editar archivos ejecuta los tests y marca cada criterio con una evidencia.
- **Cola de fusión para los pasos en paralelo.** Las ramas se fusionan de una en una sobre la última versión del destino y el comando de comprobación se ejecuta sobre el resultado fusionado. Por defecto, una rama en verde espera tu aprobación.
- **Equipo en paralelo para migraciones grandes.** Para una migración que se divide en partes independientes, un equipo en paralelo ejecuta cada parte en su propio worktree, fusiona las partes terminadas en una rama de integración y lanza la comprobación final, así que revisas un único pull request.
- **Git sin salir de la app.** El gestor de commits, los diffs y el historial en grafo están en el panel derecho, así que revisar cada paso y revertir uno es rápido.

## Para terminar

La IA no hace que el código legacy sea seguro de tocar; eso lo hacen los tests y los pasos pequeños. Lo que cambia la IA es el coste de esos pasos. Escribir tests de caracterización, convertir una carpeta a TypeScript o lanzar un codemod y limpiar después era el trabajo para el que nunca había tiempo. Con agentes sale barato, así que puedes permitirte hacerlo bien: primero la red, un cambio cada vez, cada paso revisado y cada paso reversible.

Sigue leyendo:

- [Git y GitHub](/es/features/git-and-github/)
- [Checkpoints y repetición de sesiones](/es/features/checkpoints-and-replay/)
- [Revisión de código](/es/features/code-review/)
- [Verify](/es/features/verify/)
- [Cola de fusión](/es/features/merge-queue/)
- [Equipo en paralelo](/es/features/parallel-team/)

Para probar AgentVera, empieza en la [página de inicio](/es/).

## Preguntas frecuentes

**¿Puede la IA refactorizar código legacy de forma segura?** Puede, si le das una red de seguridad y pasos pequeños. Haz que el agente escriba primero tests de caracterización, luego que haga un cambio estructural cada vez, ejecute los tests después de cada paso y lo confirme con un commit. Las peticiones grandes del tipo «limpia este módulo» son donde los agentes cambian el comportamiento sin avisar.

**¿Qué son los tests de caracterización?** Tests que registran lo que el código hace hoy, incluido el comportamiento raro o con bugs, en lugar de lo que debería hacer. Te permiten cambiar la estructura y darte cuenta al momento si el comportamiento se ha movido.

**¿Dejo que un agente migre todo el código a TypeScript de una vez?** No. Activa allowJs, convierte un módulo o una carpeta cada vez, mantén el build y los tests en verde entre pasos y endurece las opciones del compilador poco a poco. Un único cambio gigante es muy difícil de revisar.

**¿Cómo deshago un refactor hecho con IA que ha roto algo?** Si cada paso es su propio commit, git revert quita solo ese paso. Antes de fusionar, los checkpoints de AgentVera también pueden deshacer un único turno del agente. Después de fusionar, revierte el commit o el merge en main en lugar de reescribir el historial.

**¿Qué agente es mejor para refactorizar?** Claude Code, Codex y Gemini CLI pueden hacerlo. Importa más el proceso que el modelo: tests primero, pasos pequeños y revisar cada diff. En AgentVera puedes ejecutarlos lado a lado en pasos distintos.

---

**Sobre AgentVera.** AgentVera es una app de escritorio para macOS, Windows y Linux, desarrollada por Solviera Teknoloji. Ejecuta 18 agentes de programación con IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) en paralelo, por proyecto, en terminales reales con las instalaciones y sesiones de CLI del propio usuario. El plan gratuito tiene agentes ilimitados. Descargar: https://agentvera.dev/es/download/ · Precios: https://agentvera.dev/es/pricing/
