Refatoração de código legado em Go: técnicas e estratégias avançadas

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 exige uma abordagem especial

Go (Golang) é conhecido por sua simplicidade e desempenho, mas mesmo nele, com o tempo, surge código legado: pacotes monolíticos, variáveis globais, ausência de interfaces e testes. Refatorar esse código não é apenas "reescrever de forma bonita", mas uma tarefa estratégica da qual dependem a estabilidade e a velocidade do desenvolvimento.

Neste artigo, veremos técnicas avançadas de refatoração de código legado em Go: desde a extração de módulos até a injeção segura de interfaces. Você aprenderá como transformar "código espaguete" em uma arquitetura sustentável sem parar a produção.



1. Diagnóstico e mapeamento do código legado

Antes da refatoração, é necessário entender a estrutura atual. Em Go, existem ferramentas e abordagens integradas para isso:

  • Análise de dependências: use go mod graph e go list -json para visualizar as conexões entre pacotes.
  • Busca por variáveis globais: grep -r "var " *.go — muitas vezes elas são a raiz dos problemas.
  • Identificação de "code smells": funções longas, duplicação, falta de tratamento de erros.
// Exemplo: busca de todas as variáveis globais no projetopackage main

import ( "fmt" "go/parser" "go/token" "os" "path/filepath")

func findGlobals(root string) { filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() || filepath.Ext(path) != ".go" { return nil } fset := token.NewFileSet() f, _ := parser.ParseFile(fset, path, nil, parser.AllErrors) for _, decl := range f.Decls { if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.VAR { fmt.Printf("Variável global em %s: %v", path, genDecl.Specs) } } return nil })}

Importante: antes da refatoração, crie um snapshot completo dos testes (mesmo que não existam — escreva pelo menos testes smoke para os caminhos críticos).



2. Extração estratégica de módulos: do monolito aos pacotes

O código legado geralmente contém um pacote gigante main ou utils. A refatoração avançada começa com a extração granular:

  • Extração por responsabilidade: divida o código em camadas (handler, service, repository).
  • Criação de pacotes internos: use internal/ para ocultar a implementação.
  • Interfaces como contratos: não crie interfaces antecipadamente — extraia-as das implementações concretas.
// Antes da refatoração: tudo em um arquivopackage main

type User struct { ID int Name string}

func SaveUser(db *sql.DB, u User) error { _, err := db.Exec("INSERT INTO users ...", u.ID, u.Name) return err}

// Após a refatoração: divisão em pacotes// internal/repository/user.gopackage repository

type User struct { ID int Name string}

type UserRepository struct { db *sql.DB}

func (r *UserRepository) Save(u User) error { _, err := r.db.Exec("INSERT INTO users ...", u.ID, u.Name) return err}

Dica: use o padrão "Strangler Fig" — substitua gradualmente as funções antigas pelas novas, sem remover o código antigo imediatamente.



3. Eliminação de estados globais e injeção de dependências

Variáveis globais em Go são a principal causa de instabilidade e impossibilidade de teste. A técnica avançada é a inversão de controle (IoC) por meio de construtores e interfaces.

// Problema: logger e config globaisvar logger *log.Loggervar config *Config

func Init() { logger = log.New(os.Stdout, "", log.LstdFlags) config = loadConfig()}

// Solução: injeção de de

Blogs

Book Recommendations