Code review em Go: o que verificar para o código não explodir

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

Code review em Go: o que verificar para o código não explodir

\n\n

Code review não é apenas uma marcação no Jira ou um motivo para brigar com um colega nos comentários do pull request. É, talvez, a maneira mais honesta de não dar um tiro no pé em produção. E quando se trata de Go — uma linguagem amada pela simplicidade e odiada por "onde estão os genéricos?" (spoiler: eles já existem) —, a revisão se torna uma arte. Neste artigo, vamos analisar exatamente o que observar durante um code review em Go, para que seu código não apenas funcione, mas também agrade aos olhos. Vamos lá!

\n\n

1. Tratamento de erros: não ignore, não tenha medo

\n\n

Em Go não existem exceções. Aqui tudo é honesto: se uma função pode falhar, ela retorna error. O problema mais comum de iniciantes é ignorar erros usando sublinhado. Lembre-se: "Never ignore an error" não é apenas um mantra, é uma lei.

\n\n

O que verificar no código:

\n
    \n
  • Verificação de err != nil — deve estar em todos os lugares onde a função retorna um erro. Mesmo se você tiver certeza de que "aqui não vai dar erro".
  • \n
  • Registro ou propagação — o erro deve ser registrado com contexto ou retornado para cima. Abafá-lo é falta de educação.
  • \n
  • Comparação com erros sentinela — use errors.Is() e errors.As(), em vez de comparação direta com ==.
  • \n
\n\n
// Ruim: ignorando o erro\nfile, _ := os.Open("config.yaml")\n\n// Bom: verificando e registrando\nfile, err := os.Open("config.yaml")\nif err != nil {\n    log.Printf("não foi possível abrir o config: %v", err)\n    return err\n}\ndefer file.Close()\n
\n\n

2. Goroutines e concorrência: ordem no caos

\n\n

Goroutines são o superpoder do Go. Mas com grandes poderes vêm grandes responsabilidades. Na revisão, frequentemente vemos vazamentos de goroutines, condições de corrida e bloqueios. Code review em Go sem verificar concorrência é como dirigir um carro esportivo sem cinto de segurança.

\n\n

Checklist para goroutines:

\n
    \n
  • Inicialização de goroutines — sempre controle o tempo de vida. Use sync.WaitGroup ou contextos.
  • \n
  • Condições de corrida — verifique se o acesso a dados compartilhados está protegido por mutex ou canal. Execute go test -race.
  • \n
  • Panic em goroutine — se uma goroutine entrar em pânico, todo o programa cai. Em código de produção, use obrigatoriamente recover.
  • \n
\n\n
// Ruim: goroutine sem controle\ngo func() {\n    // pode falhar e matar todo o processo\n    doWork()\n}()\n\n// Bom: com WaitGroup e recover\nvar wg sync.WaitGroup\nwg.Add(1)\ngo func() {\n    defer wg.Done()\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf("goroutine falhou: %v", r)\n        }\n    }()\n    doWork()\n}()\nwg.Wait()\n
\n\n

3. Interfaces: pequenas e objetivas

\n\n

Em Go, interfaces são contratos. Mas, ao contrário do Java, elas não precisam ser enormes. Na comunidade Go, existe o princípio: "Quanto menor a interface, melhor". Um método é ideal. Dois é normal. Três já é suspeito.

\n\n

O que observar:

\n
    \n
  • Tamanho da interface — se tiver mais de 3-4 métodos, considere dividi-la.
  • \n
  • Aceite interfaces, retorne structs — sabedoria clássica do Go. Isso torna o código flexível e testável.
  • \n
  • Não defina interfaces antecipadamente — deixe que o consumidor as crie, não o produtor.
  • \n
\n\n
// Ruim: interface enorme\ntype Storage interface {\n    Save(data []byte) error\n    Load(id string) ([]byte, error)\n    Delete(id string) error\n    List() ([]string, error)\n    Connect() error\n    Close() error\n}\n\n// Bom: interfaces pequenas\ntype Saver interface {\n    Save(data []byte) error\n}\ntype Loader interface {\n    Load(id string) ([]byte, error)\n}                

Blogs

Book Recommendations