Refatoração de código legado em Go: do caos à ordem

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

Introdução: Por que o código legado em Go precisa de refatoração?

Go (Golang) é conhecido por sua simplicidade e desempenho. No entanto, mesmo em projetos Go, com o tempo, acumula-se código legado — construções obsoletas, funções ilegíveis, números "mágicos" e falta de testes. Trabalhar com esse código se torna um pesadelo: cada alteração é arriscada e adicionar novas funcionalidades leva semanas.

Refatoração não é reescrever o projeto do zero. É uma reorganização segura da estrutura interna do código sem alterar seu comportamento externo. Neste artigo, vamos detalhar um plano passo a passo para refatorar código legado em Go, desde a análise até a implementação. Você aprenderá como transformar um "código espaguete" confuso em um projeto limpo, sustentável e testável.



Etapa 1: Auditoria e mapeamento do código legado

Antes de alterar o código, você precisa entender com o que está lidando. Pule esta etapa — e corre o risco de quebrar uma lógica que ninguém lembra.



1.1. Identificação de "bandeiras vermelhas"

Comece procurando antipadrões típicos em Go:

  • Funções God — funções com mais de 100 linhas.
  • Variáveis globais — alto acoplamento e dificuldade de teste.
  • Números/strings mágicos — constantes espalhadas pelo código.
  • Falta de tratamento de erros — ignorar o retorno de error.
  • Pânico em vez de erros — uso de panic/recover para lógica de negócios.
  • Mistura de camadas — consultas SQL dentro de manipuladores HTTP.


1.2. Criação de um mapa de dependências

Use ferramentas como go callgraph ou guru para visualizar chamadas de funções. Isso ajudará a identificar:

  • Dependências cíclicas entre pacotes.
  • Código "morto" que não é chamado em lugar nenhum.
  • Caminhos críticos que não devem ser tocados sem cobertura de testes prévia.


Etapa 2: Criação de uma "rede de segurança" de testes

Refatoração sem testes é um salto sem rede de segurança. Sua tarefa é escrever testes de caracterização que fixem o comportamento atual do sistema, mesmo que pareça incorreto.



2.1. Testes no nível de funções

Comece pelas partes mais críticas e isoladas do código. Exemplo para uma função que será refatorada:

// Código legadofunc CalculatePrice(base float64, discountCode string) float64 {    if discountCode == "SALE10" {        return base * 0.9    }    if discountCode == "VIP20" {        return base * 0.8    }    return base}

// Teste de caracterizaçãofunc TestCalculatePrice(t *testing.T) { tests := []struct { name string base float64 code string want float64 }{ {"sem desconto", 100.0, "", 100.0}, {"desconto 10%", 100.0, "SALE10", 90.0}, {"desconto 20%", 100.0, "VIP20", 80.0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := CalculatePrice(tt.base, tt.code) if got != tt.want { t.Errorf("CalculatePrice(%v, %v) = %v; want %v", tt.base, tt.code, got, tt.want) } }) }}


2.2. Testes de integração com Golden Files

Para estruturas complexas (respostas JSON, geração de relatórios), use a técnica de "arquivos dourados". Grave a saída atual em um arquivo e, durante a refatoração, compare com ele.

func TestHandler(t *testing.T) {    // Executa a requisição    req := httptest.NewRequest("GET", "/api/data", nil)    rec := httptest.NewRecorder()    myHandler(rec, req)

// Compara com o padrão expected, _ := os.ReadFile("testdata/golden.json") if !bytes.Equal(rec.Body.Bytes(), expected) { t.Errorf("Output mismatch") }\

Blogs

Book Recommendations