Como refatorar código sem destruir o que já funciona
Vou começar pelo jeito mais fácil de errar, porque eu errei desse modo algumas vezes. Peguei um módulo inteiro de 4.000 linhas, abri o refactoring book martin fowler num canto da mesa e comecei a aplicar as ideias na ordem do índice. O resultado foi um projeto que passou duas semanas sem compilar e um colega perguntando se eu tinha hackeado o repositório. O problema não era o livro. Era a minha premissa de que refatoração é sobre o código, e não sobre o sistema sendo executado.
A ideia central (contando depois da história, como sempre acontece)
Refatoração é a arte de melhorar a estrutura interna de um software sem alterar seu comportamento externo. O termo foi cunhado pelo Doug Ross nos anos 80, mas foi o Martin Fowler quem sistematizou a prática, publicando o trabalho em 1999 e atualizando-o nas edições seguintes. O livro lista mais de 220 pequenos movimentos, cada um com o nome, o "como fazer", um exemplo e os riscos conhecidos. A contribuição real dele não foi criar técnicas novas — as melhores já existiam em Heads First Design Patterns e no Smalltalk original —, foi transformar o sensato "deixa isso aí que funciona" em algo que equipes podiam ensinar e auditar. A regra de ouro que todo mundo copia e pouquíssimos respeita: refatore apenas quando tiver testes passando. Não "testes que você acha que cobrem". Testes que rodaram na última vez que o build foi verde e cujos asserts você consegue ler sem precisar consultar o histórico do git.
O fluxo que eu realmente uso
O primeiro passo é identificar o "smell", não o trecho bonito. Nomes ruins de variáveis, funções com três responsabilidades misturadas, duplicação que apareceu duas vezes em lugares diferentes e sumiu por seis meses. Anoto no quadro ou num arquivo de texto antes de abrir o IDE. Quando eu tento refatorar sem um alvo definido, acabo refatorando por ansiedade, e isso é o tipo de coisa que gera commits sem mensagem e PRs que ninguém sabe o que resolveram. O segundo passo é a divisão em micro-commits. Cada movimento do catálogo — Extract Method, Rename Variable, Replace Temp with Query, Pull Up Field — deve gerar um commit separado com mensagem padrão. Se o seu teste quebra no meio do caminho, o commit anterior mostra exatamente onde a fronteira está. Timeboxes de 25 minutos ajudam. Eu costumo usar o Pomodoro não como ritual motivacional, mas como freio contra a tentação de continuar "só mais uma melhoria".
O terceiro passo é o review focado. Não peço para ninguém revisar o estilo; peço para alguém executar os testes antes e depois do meu commit e confirmar que o resultado foi idêntico. Isso elimina 80% dos falsos positivos de regressão e sobra tempo para discutir a arquitetura.
Três insights que aprendi na mão
Primeiro: o catálogo não é uma receita. É um vocabulário. Usar "Extract Method" quando a função já tem 8 linhas e uma coisa é gastar token de reviewer sem ganho. O movimento serve para tornar explícito um intento que o leitor teria que inferir. Se a inferência já é trivial, não refatore. Segundo: a ordem dos movimentos importa tanto quanto os movimentos em si. Eu já tentei aplicar Replace Inheritance with Delegation antes de eliminar as subclasses vazias. O teste passou, mas o código ficou pior. O livro menciona isso de passagem na seção de sequência, mas a lição só entra quando você cai nela.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Terceiro: nem tudo no catálogo serve para tudo. Substituir uma chamada de função por uma classe Strategy inteira em um script Python de 150 linhas é overengineering com capa de good practice. Fowler escreveu o catálogo para sistemas grandes, com equipes que se Turnover a cada dois anos. Se o seu código vai viver seis meses e ser descartado, leve o essencial e esqueça o resto.
Um problema real que eu tive e como resolvi
Tinha uma classe de domínio com 42 campos, herança tripla e um método initialize que durava 300 linhas. Quis aplicar Extract Class para separar endereços de dados cadastrais. O teste unitário passou, mas o integration test que simulava o import CSV quebrava porque um campo de endereço, que eu tinha movido para a classe nova, ainda era referenciado pela view que gerava o relatório mensal. O problema era silencioso: o teste de unidade não cobria a view, e a view não tinha teste algum. A solução foi criar um shim temporário na classe original que delegava para a nova, executar a suite completa, validar o relatório, e só então remover o shim. Duro. Demorou quatro horas em vez de vinte minutos. Mas foi o aprendizado mais útil que eu tive sobre refatoração em equipe: o risco não é o código quebrar durante a mudança; é a mudança revelar dependências que ninguém sabia que existiam.
Onde o livro falha (e o que fazer no lugar)
Primeiro ponto fraco: o catálogo pressupõe acesso ao código-fonte e liberdade para executar testes a qualquer momento. Em sistemas legados com deployment manual que leva duas horas e quebram quando alguém respira errado, a prática virou lenda urbana. Nesses casos, o caminho é ir devagar: isolamento de interfaces, testes de aceitação escritos antes de qualquer mudança estrutural, e commits que só vão para produção quando o release window abre. Segundo ponto: Fowler trata refatoração como atividade isolada do design. Na prática, os dois andam juntos. Um Pull Up Field mal executado pode destruir uma invariant que estava implícita há anos. O remédio é combinar o catálogo com Domain-Driven Design e análise de contratos. Antes de mover um campo, pergunte: qual invariant esse campo protege? Se não souber responder, não mova.
Terceiro ponto: o livro não cobre refatoração de bancos de dados. Migrações schema-on-write são outro universo com regras próprias. Para isso, recomendo a série de artigos do Martin Caldarale sobre migrations seguras, ou o livro "Data Migrations in a Flash" do David Keller, que lida com locking, zero-downtime e rollback de forma mais honesta que a maioria dos guias.
Resumo prático
Se você quer começar hoje: pegue um arquivo, escreva três testes que cubram o comportamento visível, identifique o maior smell, aplique um único movimento do catálogo, execute os testes, confirme igualdade, commit. Repita. Não leia o livro inteiro de uma vez. Ele funciona como dicionário, não como romance. Abra na seção do movimento que resolve o seu problema, aplique, feche. O resto vem com o tempo. E se alguma coisa quebrar: volte o commit, anote o que aconteceu, e repita. Esse é o preço que todo mundo paga e que todo mundo esquece de dizer quando recomenda o livro.