IA no refactor: refactor assistido, validar tipos, evitar alucinação
5 min de leitura
Você tem uma função de 200 linhas que funciona mas é macarronada. Pede pra IA "refatora isso". Ela entrega código "bonito" que não compila porque alucinou uma API. Esse nó cobre IA no refactor: como refatorar com IA sem quebrar comportamento, validar tipos automaticamente, e identificar alucinação de API antes de aceitar.
Refactor é a operação mais arriscada de AI coding: muda estrutura sem mudar comportamento. Sem testes, IA introduz bugs sutis. Com testes, IA valida a si mesma. TypeScript + testes = rede de segurança.
Você sai de "IA quebra meu código em refactor" pra "IA refatora com segurança".
O essencial 🟢
O fluxo seguro de refactor com IA.
- Testes primeiro. Antes de pedir refactor, garanta testes cobrindo o comportamento atual. Se não tem, escreva primeiro (use IA pra ajudar).
- Refactor pequeno por vez. "Extrai essa função", "renomeia X pra Y", "move pra módulo Z". Não "refatora tudo".
- Tests passam a cada step. Rode testes após cada mudança. Se falha, volta.
- Commit por step. 1 refactor = 1 commit. Facilita rollback.
- Type check.
tsc --noEmit(zero errors) sempre.
Exemplo de fluxo seguro.
# Estado inicial
src/legacy.ts (200 linhas, 5 funções, sem testes)
# Step 1: adicionar testes
src/legacy.test.ts (cobre as 5 funções)
git commit -m "test: add tests for legacy module"
# Step 2: extrair função 1
src/legacy.ts (190 linhas) + src/extract1.ts (10 linhas)
git commit -m "refactor: extract function foo to extract1"
# Step 3: extrair função 2
src/legacy.ts (180 linhas) + src/extract2.ts (10 linhas)
git commit -m "refactor: extract function bar to extract2"
# ... continua
# Final
src/legacy.ts (50 linhas) + 5 arquivos extraídos
Cada step: testes verdes, type check OK, commit atômico.
Os 4 alucinações mais comuns em refactor.
-
API inventada. IA chama método que não existe na versão da lib.
// IA gera array.uniqueify(); // método inventado // Real [...new Set(array)]; // ou Array.from(new Set(array)) -
Tipo errado. IA passa tipo errado, TypeScript pega.
// IA gera fetchUser(id: string) { ... } // TypeScript pega fetchUser(123); // Error: number is not string -
Comportamento mudou. IA "refatora" mudando lógica sutilmente.
// Antes if (user.role === "admin" || user.role === "mod") { ... } // IA "refatora" pra if (user.isStaff) { ... } // equivalente? não // isStaff pode incluir outros roles não previstos -
Edge case perdido. IA "limpa" código removendo check que era necessário.
// Antes if (!user) return null; if (user.deleted) return null; // ... lógica // IA "refatora" pra // ... lógica // ❌ esqueceu de verificar deleted
Como evitar alucinação de API.
- Use TypeScript.
tsc --noEmitpega API inventada em 99% dos casos. - Verifique versão da lib. IA pode usar API de versão antiga. Diga explicitamente: "Use a versão 4.5 do Express".
- Use
npm viewoupnpm viewpra verificar API antes de aceitar. - Olhe changelog da lib se refactor grande.
Como evitar mudança de comportamento.
- Tests (cobre o comportamento antes do refactor).
- Visual diff (se UI, compare screenshots).
- Code review (outro dev compara antes/depois).
Como evitar edge case perdido.
- Testes de edge case (null, 0, "", negative, max).
- Property-based testing (IA gera inputs aleatórios).
- Code review (procurar "removi essa check" no diff).
O pattern: "behavior-preserving refactor". Um bom refactor não muda comportamento. Como garantir:
- Tests antes. Capture comportamento atual.
- Refactor. Mude estrutura, não lógica.
- Tests depois. Mesmo output, mesmo comportamento.
- Compare. Se teste passou antes e passa depois, mesmo comportamento (com mesmas condições).
Red flags no refactor com IA.
- "Simplifiquei a lógica" (sem diff de teste)
- "Removi código duplicado" (sem garantir mesmo comportamento)
- "Melhorei a performance" (sem benchmark)
- "Adicionei tipagem" (mas tipos diferentes do original)
- "Refatorei pra ESM" (mas quebrou imports)
Refactor seguro: 5 patterns.
- Rename (variável, função, file). Baixo risco. TypeScript pega quebra.
- Extract function (lógica longa em função nomeada). Baixo risco.
- Move file (de uma pasta pra outra). Risco médio (imports).
- Change type (de
anypra tipo específico). Risco médio. - Refactor architecture (mover lógica entre módulos). Alto risco. Decomponha.
A "rule of three". Não refatore preemptivamente. Espere ter 3 casos similares antes de extrair pattern. Refactor cedo demais = abstração errada. Refactor tarde demais = código duplicado.
IA ajuda com refactor "difíceis". Code smells que IA detecta automaticamente:
- God class (500+ linhas, 20+ métodos).
- Long function (50+ linhas).
- Duplicate code (3+ blocos similares).
- Feature envy (método usa mais dados de outra classe).
- Primitive obsession (string "user_role" em vez de enum).
Peca pra IA: "lista code smells desse arquivo", "extrai o pattern X em função".
Aprofundamento 🟡
Refactor com type check e testes - o "safety net" duplo.
1. Antes: rodar testes + tsc → tudo OK
2. Refactor: IA gera código novo
3. tsc --noEmit → ZERO errors (TypeScript
pega tipos errados)
4. npm test → 100% passing (tests pegam
comportamento)
5. Se ambos passam → refactor OK
6. Se algum falha → rollback ou fix
Rede de segurança:
- TypeScript: tipos errados, API inexistente, null safety.
- Tests: comportamento mudou.
- Lint: patterns ruins.
- Code review: decisão de design.
Refactor com diff visual. Em refactor UI, compare screenshots:
// Playwright
const before = await page.screenshot();
await refactor();
const after = await page.screenshot();
expect(after).toMatchSnapshot(before);
Visual diff pega mudanças subtis de layout, cor, spacing que tests não pegam.
Refactor de código gerado por IA em loop. Pattern iterativo:
1. Tests cobrem comportamento atual
2. IA refatora (1 refactor por vez)
3. Tests passam
4. Commit
5. Próximo refactor
Loop até IA não conseguir mais refatorar (código "limpo"). Cada loop = 1 commit. 10-50 commits por refactor grande = git history limpo.
Refactor com IA + Behavior-Driven Development (BDD). BDD = spec em linguagem natural (Gherkin) + tests:
Feature: User login
Scenario: Valid credentials
Given user exists with email "user@example.com"
When user submits login form
Then user is redirected to dashboard
And user sees "Welcome"
IA gera implementação que passa esses tests. Refactor mantendo tests verdes. BDD = "behavior spec" que IA segue.
Quando Não usar IA pra refactor.
- Refactor de performance crítica. IA pode introduzir overhead sutil. Benchmark antes/depois.
- Refactor com mudança de paradigma. Migrar de OOP pra functional, ou vice-versa - IA mistura patterns.
- Refactor de código altamente otimizado. IA vai "limpar" o que era deliberadamente otimizado.
- Refactor sem testes. Risco alto demais.
"AI refactor debt" - o novo pattern. Code gerado por IA sem refactor vira "AI refactor debt": código "funcional" mas com patterns inconsistentes, naming confuso, duplicação sutil. Auditar mensal e refatorar.
Leitura recomendada:
- TypeScript Handbook - tipos, generics, type narrowing.
- Martin Fowler - Refactoring - catálogo de code smells, refactorings, behavior-preserving.
Dica: o erro mais comum em IA refactor é pedir refactor sem testes. "Refatora essa função de 200 linhas" = IA muda comportamento sem você perceber. Sem testes, bug silencioso em prod. Testes antes = rede de segurança. 5 min de testes = evita 5h de debug em prod. TDD-first em refactor: capture comportamento atual, depois refatore. Tests verdes antes e depois = mesmo comportamento (com TypeScript pra pegar tipos).
No próximo nó, vamos quando não usar IA: lockfile, secrets, código com implicação legal/segurança, e os limites de IA em código crítico.
// Quiz
Qual o fluxo mais seguro pra fazer refactor assistido por IA em código existente?