# Refatorar código legado com IA sem quebrar a produção

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

Como refatorar código legado com agentes de IA com segurança: testes de caracterização, passos pequenos, JS para TypeScript, upgrades, revisão e rollback.

**Resumo:**

- Antes de um agente mexer em código legado, peça que ele fixe o comportamento atual com testes de caracterização; sem essa rede de segurança você não distingue uma refatoração de uma reescrita.
- Trabalhe em passos pequenos, cada um com seu commit e com os testes verdes, e deixe mudanças de comportamento fora dos commits de refatoração para que qualquer passo possa ser revertido sozinho.
- Migrações como JavaScript para TypeScript ou o upgrade de um framework funcionam melhor módulo a módulo, com o compilador, os testes e um codemod fazendo o máximo possível do trabalho.
- No AgentVera cada passo pode rodar na sua própria worktree, ser revisado e verificado quando o turno do agente termina e entrar pela fila de merge na main mais recente.

Refatorar código legado com IA é entregar a um trabalhador muito rápido e muito confiante a parte da sua base de código que ninguém entende por completo. Isso pode dar certo. Agentes têm paciência com arquivos de 3.000 linhas, não se importam de renomear uma função em duzentos lugares e leem código antigo sem suspirar. Também pode dar errado: uma “limpeza” que muda uma regra de arredondamento, remove um efeito colateral que ninguém documentou ou vira uma reescrita impossível de revisar.

Este guia é sobre o primeiro resultado. Ele mostra como montar uma rede de segurança antes da primeira mudança, como manter cada passo pequeno e reversível, como conduzir migrações como JavaScript para TypeScript ou o upgrade de um framework, e como revisar e desfazer o que o agente fez.

## Por que código legado também é difícil para agentes

Código legado é código que você tem medo de mudar, normalmente porque tem poucos testes e muitas regras não escritas. As mesmas coisas que o tornam difícil para pessoas o tornam difícil para um agente:

- **O comportamento mora em lugares estranhos.** Um formato de data em um helper, um retry em um decorator, uma variável global que outra coisa lê.
- **Alguns bugs são features.** Um sistema mais adiante pode depender de um valor errado. “Corrigi-lo” quebra uma integração que você nunca viu.
- **Código morto parece vivo e código vivo parece morto.** Reflection, dispatch por string, cron jobs e templates chamam funções que nenhuma busca encontra.
- **A janela de contexto é finita.** Um agente vê os arquivos que lê. Ele não vai saber do job em lote em outro repositório que importa este módulo.

Um agente também tem um hábito perigoso aqui: ele melhora as coisas. Peça para extrair uma função e ele talvez também corrija o caso de borda que notou, renomeie variáveis e modernize a sintaxe. Cada mudança pode estar certa. Juntas, elas formam um diff em que você não sabe o que era para mudar.

## Passo 1: monte a rede de segurança primeiro

Não deixe o agente mudar uma linha de código de produção até que o comportamento que importa esteja fixado por testes. Em código legado isso significa testes de caracterização: testes que registram o que o código faz agora, não o que deveria fazer.

Um prompt que funciona:

> Don’t change any code under `src/`. Write characterization tests for `src/orders/pricing.js` that record its current behaviour, including anything that looks wrong. Cover each branch you can find, including error paths. Where behaviour looks like a bug, keep the test asserting the current output and add a comment starting with `SUSPICIOUS:`. Run the tests and show me they pass.

Algumas dicas:

- **Teste pela superfície pública.** Testes que chamam o módulo do jeito que o resto do app chama sobrevivem à refatoração. Testes que mexem em helpers privados quebram quando você os move.
- **Use entradas reais.** Payloads de exemplo tirados dos logs (limpos de dados pessoais), arquivos de fixture ou uma cópia de um banco de staging cobrem casos estranhos muito melhor que entradas inventadas.
- **Golden files valem aqui.** Para um gerador de relatórios ou uma exportação, gravar a saída inteira e comparar é um teste de caracterização rápido e honesto, desde que a saída seja determinística.
- **Confira se os testes conseguem falhar.** Quebre o código à mão em alguns pontos ou rode uma ferramenta de mutation testing no módulo. Se os testes continuam verdes, a rede tem buracos.

O guia [escrever testes unitários com IA](/pt/blog/write-unit-tests-with-ai/) aprofunda testes de caracterização, cobertura e mutation testing.

As notas `SUSPICIOUS:` são valiosas. São os bugs que você vai corrigir depois, de propósito, em commits próprios, com alguém decidindo que o novo comportamento é o certo.

## Passo 2: refatore em passos pequenos e reversíveis

Com a rede no lugar, mantenha cada passo pequeno o bastante para revisar em poucos minutos e para desfazer sem mexer em mais nada.

### Separe estrutura de comportamento

A regra mais útil: um commit de refatoração muda só a estrutura, e uma mudança de comportamento ganha seu próprio commit. Diga isso ao agente com todas as letras:

> This is a pure refactor. Don’t change behaviour, don’t fix bugs, don’t change public signatures. If you see something that should change, list it at the end instead.

Quando os testes de caracterização mudam em um commit de refatoração, algo está errado. Isso dá uma verificação fácil: `git diff --stat main -- tests/` não deve mostrar edições em testes existentes.

### Um tipo de mudança por passo

Bons tamanhos de passo:

- Extrair uma função ou classe.
- Mover um módulo e atualizar os imports.
- Substituir uma API obsoleta em toda a base de código.
- Introduzir uma interface em uma fronteira para que o código antigo e o novo convivam.

Peça ao agente que rode os testes depois de cada passo e faça o commit com uma mensagem clara antes de seguir. Um plano ajuda: “Proponha a refatoração como uma lista numerada de passos, cada um deixando os testes verdes. Espere meu OK antes de começar.” A maioria dos agentes de código tem um modo de planejamento para isso; o plan mode do Claude Code, por exemplo, explora e propõe sem editar.

### Estrangule, não reescreva

Para uma parte que realmente precisa ser substituída, coloque a nova implementação ao lado da antiga, atrás de uma interface ou de uma flag, migre os chamadores um por vez e apague o código antigo quando nada mais o usar. Esse é o padrão strangler fig. Ele transforma uma troca arriscada em muitas trocas pequenas e chatas, e agentes são bons em trabalho chato.

## Passo 3: migrações com agentes

Migrações são onde os agentes economizam mais tempo, porque o trabalho é amplo e repetitivo. Também são onde os diffs ficam enormes. O truque é deixar as ferramentas fazerem a parte mecânica e o agente fazer as decisões de julgamento.

### JavaScript para TypeScript

Um caminho que mantém o app funcionando o tempo todo:

1. **Adicione TypeScript ao lado do JavaScript.** No `tsconfig.json`, defina `allowJs: true` para que arquivos `.js` e `.ts` convivam, e rode `npx tsc --noEmit` no CI como verificação de tipos.
2. **Comece frouxo.** Comece com `strict: false`. Se quiser, ative `checkJs` ou adicione `// @ts-check` em arquivos JS específicos para achar problemas antes de renomeá-los.
3. **Converta primeiro os módulos-folha.** Arquivos sem imports internos, como utilitários e constantes, são os mais fáceis. Depois suba em direção aos pontos de entrada.
4. **Uma pasta por passo.** Peça ao agente para converter `src/utils/` para `.ts`, adicionar tipos, manter os testes verdes e fazer o `tsc --noEmit` passar. Depois a próxima pasta.
5. **Aperte aos poucos.** Quando tudo for `.ts`, ative `noImplicitAny`, depois `strictNullChecks`, depois `strict` completo, corrigindo os erros entre um e outro.

Duas regras para dar ao agente: nada de `any` sem um comentário explicando o porquê, e nada de `@ts-ignore` para sumir com erros. Senão o caminho mais rápido para um compilador verde é desligar o compilador linha por linha.

### Upgrades de frameworks e bibliotecas

Para uma mudança de versão major, a ordem importa:

1. **Leia o guia de migração primeiro.** Peça ao agente que resuma o guia oficial de upgrade e liste as breaking changes que afetam o seu código, com caminhos de arquivo. Esse é um passo só de leitura.
2. **Rode o codemod oficial, se houver.** Muitos projetos oferecem codemods, por exemplo `npx @next/codemod` para Next.js; para Java, receitas do OpenRewrite cobrem muitos upgrades. Um codemod é determinístico; um agente não é. Deixe o codemod fazer o que puder.
3. **Deixe o agente cuidar do resto.** Os casos que o codemod não resolveu, os wrappers customizados, os testes que dependiam do comportamento antigo.
4. **Suba uma versão major por vez.** Ir da 3 para a 6 de uma vez empilha todas as breaking changes em um só diff.

Fixe o resultado esperado no seu prompt: “o build passa, a suíte de testes passa, nenhum aviso novo no console”. Um vago “atualiza para a última versão” convida o agente a subir mais cinco pacotes no caminho.

## Passo 4: isole o trabalho com worktrees

Uma refatoração longa não deveria ficar na sua pasta de trabalho principal, e passos paralelos não deveriam dividir uma pasta. Uma [git worktree](/pt/glossary/git-worktree/) dá a cada passo sua própria branch e pasta:

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

Agora um agente converte `utils`, outro converte `api`, e você continua trabalhando na pasta principal. Quando um passo termina e é revisado, faça o merge; quando não leva a lugar nenhum, remova a worktree e a branch. Mais em [git worktrees para agentes em paralelo](/pt/blog/git-worktree-parallel-agents/).

Cuidado com passos paralelos que mexem nos mesmos arquivos. Dois agentes renomeando coisas no mesmo módulo vão gerar conflitos, e a resolução de conflitos em uma refatoração é por onde o comportamento entra escondido. Divida o trabalho por pasta ou por módulo, não por tipo de mudança.

## Passo 5: revise cada passo

Um diff de refatoração é fácil de aprovar porque parece não fazer nada. É exatamente por isso que você o lê. O que procurar:

- **Algum teste mudou?** Em uma refatoração pura, os testes existentes não deveriam mudar.
- **Alguma assinatura pública mudou?** Funções exportadas, respostas de API, colunas do banco, nomes de eventos.
- **Algo foi apagado?** Pergunte ao agente por que cada função removida não era usada. “Nenhuma referência encontrada” não é prova quando há reflection ou dispatch por string.
- **O tratamento de erros mudou?** Uma exceção engolida que agora se propaga, ou o contrário, é uma mudança de comportamento.
- **O diff cresceu além do passo?** Um passo de “mover este módulo” não deveria também reformatar outros vinte arquivos. Peça a formatação em um commit próprio, ou nenhuma.

Um segundo modelo revisando cada turno pega boa parte disso. Veja [code review com IA](/pt/blog/ai-code-review/) para saber como funciona.

## Passo 6: planeje o rollback antes de precisar

Desfazer é barato quando você se prepara:

- **Commits pequenos.** `git revert <sha>` remove um passo de forma limpa. Um commit de 4.000 linhas só pode ser revertido inteiro.
- **Reverta, não reescreva.** Quando algo já está na main, reverta o commit ou o merge em vez de dar force push sobre o histórico compartilhado.
- **Use bisect quando algo escapar.** Com commits pequenos e verdes, o `git bisect` encontra o passo que quebrou o comportamento em poucas execuções.
- **Flags para trocas arriscadas.** Quando código antigo e novo convivem, uma flag desliga o caminho novo sem deploy.
- **Desfaça dentro da sessão.** Antes de qualquer commit, você pode desfazer o último turno de um agente; veja [como desfazer alterações do Claude Code](/pt/blog/undo-claude-code-changes/).

## Erros comuns

- **“Refatora este módulo” sem testes.** Você recebe uma reescrita e nenhum jeito de conferi-la.
- **Misturar refatoração e correção de bugs.** Quando o comportamento muda, você não sabe se era para mudar.
- **Uma branch de migração gigante.** Ela se afasta da main, os conflitos se acumulam e ninguém consegue revisar.
- **Confiar em “não usado”.** A busca não vê chamadas dinâmicas, outros repositórios nem jobs agendados.
- **Deixar o agente calar o compilador.** `any`, `@ts-ignore` e regras de lint desativadas escondem o trabalho em vez de fazê-lo.
- **Fazer o merge de passos paralelos sem testá-los juntos.** Duas branches verdes podem ficar vermelhas depois do merge, e é para isso que serve uma [fila de merge](/pt/blog/merge-queue-for-ai-agents/).

## Fazendo isso no AgentVera

O AgentVera roda CLIs de agentes de código lado a lado por projeto, com git integrado, o que combina com o estilo passo a passo de uma refatoração de código legado.

- **Uma worktree por passo.** No painel de worktrees, abra uma branch e uma pasta para cada passo e inicie um agente direto nela, Claude Code em uma, Codex ou Gemini CLI em outra. Sua pasta principal continua como está.
- **Checkpoints a cada turno.** No início de cada turno, a pasta de trabalho é salva em uma ref git oculta, e os últimos 60 turnos ficam guardados por agente. Veja quais arquivos um turno mudou e desfaça só aquele turno se o agente foi longe demais.
- **Revisão ao fim de cada turno.** O code review automático lê o código que o agente escreveu com o modelo Claude que você escolher e lista os achados com severidade e arquivo:linha; opcionalmente os achados voltam para o agente, até duas rodadas seguidas.
- **Verify contra os seus critérios.** Escreva “refatoração pura, todos os testes passam, nenhum arquivo de teste existente mudou” na sua mensagem. O Verify transforma isso em critérios e, quando o turno termina, um verificador separado que não pode editar arquivos roda os testes e marca cada critério com evidências.
- **Fila de merge para passos paralelos.** As branches entram uma por vez sobre o alvo mais recente e o comando de verificação roda no resultado do merge. Por padrão, uma branch verde espera a sua aprovação.
- **Equipe paralela para migrações grandes.** Para uma migração que se divide em partes independentes, uma equipe paralela roda cada parte na sua própria worktree, faz o merge das partes prontas em uma branch de integração e roda a verificação final, então você revisa um único pull request.
- **Git sem sair do app.** O gerenciador de commits, os diffs e o histórico em grafo ficam no painel direito, então revisar cada passo e reverter um deles é rápido.

## Resumindo

A IA não torna seguro mudar código legado; testes e passos pequenos tornam. O que a IA muda é o custo desses passos. Escrever testes de caracterização, converter uma pasta para TypeScript ou rodar um codemod e arrumar o que sobrou era o trabalho para o qual ninguém tinha tempo. Com agentes isso fica barato, então dá para fazer direito: rede primeiro, uma mudança por vez, cada passo revisado, cada passo reversível.

Leia mais:

- [Git e GitHub](/pt/features/git-and-github/)
- [Checkpoints e replay](/pt/features/checkpoints-and-replay/)
- [Code review](/pt/features/code-review/)
- [Verify](/pt/features/verify/)
- [Fila de merge](/pt/features/merge-queue/)
- [Equipe paralela](/pt/features/parallel-team/)

Para experimentar o AgentVera, comece pela [página inicial](/pt/).

## Perguntas frequentes

**A IA consegue refatorar código legado com segurança?** Consegue, se você der a ela uma rede de segurança e passos pequenos. Peça ao agente que escreva primeiro testes de caracterização, depois faça uma mudança estrutural por vez, rode os testes após cada passo e faça o commit. Pedidos grandes do tipo “limpa este módulo” são onde os agentes mudam o comportamento sem avisar.

**O que são testes de caracterização?** Testes que registram o que o código faz hoje, inclusive comportamentos estranhos ou com bug, e não o que ele deveria fazer. Eles permitem mudar a estrutura e perceber na hora se o comportamento mudou.

**Devo deixar um agente migrar uma base de código inteira para TypeScript de uma vez?** Não. Ative o allowJs, converta um módulo ou pasta por vez, mantenha build e testes verdes entre os passos e aperte as opções do compilador aos poucos. Uma mudança gigante única é muito difícil de revisar.

**Como desfaço uma refatoração feita por IA que quebrou algo?** Se cada passo é um commit próprio, o git revert remove só aquele passo. Antes do merge, os checkpoints do AgentVera também conseguem desfazer um único turno do agente. Depois do merge, reverta o commit ou o merge na main em vez de reescrever o histórico.

**Qual agente é melhor para refatorar?** Claude Code, Codex e Gemini CLI conseguem fazer isso. O processo importa mais que o modelo: testes primeiro, passos pequenos, revisar cada diff. No AgentVera você pode rodá-los lado a lado em passos diferentes.

---

**Sobre o AgentVera.** AgentVera é um app desktop para macOS, Windows e Linux, desenvolvido pela Solviera Teknoloji. Ele roda 18 agentes de programação com IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) lado a lado, por projeto, em terminais reais com as instalações e logins de CLI do próprio usuário. O plano gratuito tem agentes ilimitados. Baixar: https://agentvera.dev/pt/download/ · Preços: https://agentvera.dev/pt/pricing/
