Refatoração de código legado em JavaScript: nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Refatoração de código legado em JavaScript: nível avançado



Trabalhar com código legado é uma realidade inevitável para qualquer desenvolvedor, especialmente na área de Node.js. Muitas vezes, esse código é um "pântano" de variáveis globais, callbacks aninhados, funções com centenas de linhas e total ausência de estrutura modular. Métodos simples de refatoração não funcionam aqui: é necessária uma abordagem sistemática e conhecimento de técnicas avançadas. Neste artigo, vamos abordar estratégias que ajudam a transformar o caos em uma arquitetura sustentável sem parar a produção.



1. Análise e mapeamento de dependências



Antes de alterar o código, é preciso entendê-lo. Em projetos legados, a documentação geralmente é inexistente ou desatualizada. O primeiro passo é construir um mapa de dependências.



Ferramentas:

  • Madge — utilitário para visualizar dependências entre módulos. Ele mostra dependências cíclicas e arquivos "mortos".
  • ESLint com plugins — ajuda a identificar variáveis, funções e imports não utilizados.
  • Implantação em ambiente isolado — execute testes (se não houver, escreva pelo menos testes smoke) e registre quais módulos são carregados.


Exemplo: Suponha que temos um arquivo legacy.js com 2000 linhas que usa uma variável global config.



// legacy.js (antes da refatoração)var config = {    apiUrl: 'https://api.example.com',    timeout: 5000};

function fetchData(callback) { // 50 linhas de lógica com ifs aninhados e try/catch // usa o config global if (config.timeout > 0) { // ... } callback(null, data);}


Ação: Com o Madge, vemos que legacy.js é importado em outros 15 arquivos. É um "objeto divino". Nossa tarefa é dividi-lo em módulos atômicos.



2. Estratégia "Strangler Fig" (Figo Estrangulador)



Esse padrão é ideal para refatoração sem parar o sistema. A ideia: não reescrevemos tudo de uma vez, mas substituímos gradualmente partes do sistema antigo por novas, até que o antigo morra por si só.



Implementação em Node.js:

  • Crie um novo módulo com arquitetura limpa.
  • Escreva uma camada de proxy (ou fachada) que redireciona chamadas para o módulo antigo ou novo.
  • Gradualmente, migre os consumidores para o novo módulo.


Exemplo: Substituindo o estilo antigo de callback por Promise/async/await.



// API antiga (baseada em callback)function getUser(id, callback) {    // código legado    callback(null, { id: id, name: 'João' });}

// Nova API (baseada em Promise)async function getUserAsync(id) { // nova implementação com async/await const user = await database.findUser(id); return user;}

// Fachada de proxyasync function getUserFacade(id) { if (USE_NEW_IMPLEMENTATION) { return getUserAsync(id); } else { return new Promise((resolve, reject) => { getUser(id, (err, user) => { if (err) reject(err); else resolve(user); }); }); }}


A flag USE_NEW_IMPLEMENTATION pode ser colocada na configuração ou em um feature toggle. Isso permite ativar o novo código para parte dos usuários (canary release) ou reverter alterações sem implantação.



3. Modularização e isolamento de efeitos colaterais



Código legado frequentemente sofre de efeitos colaterais ocultos: a função altera o estado global, escreve em um arquivo ou chama uma API externa sem retornar o resultado. A refatoração dessas funções envolve extrair a lógica pura.



Técnica: "Extrair Função" (Extract Function) seguida de injeção de dependências (Dependency Injection).



Código problemático:



                

Blogs

Book Recommendations