Depuração de código Go: do iniciante ao profissional em uma noite

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

Por que seu código Go falha e como corrigir isso sem dor de cabeça

\n\n

Você escreveu um código Go que considera perfeito. A compilação foi um sucesso, os testes estão verdes... mas em produção tudo vai pelos ares. Familiar? Bem-vindo ao mundo real do desenvolvimento, onde bugs não são erros de iniciantes, mas parte do crescimento profissional. Hoje vamos abordar a depuração de código Go de forma que você não apenas encontre erros, mas previna seu aparecimento durante a escrita.

\n\n

Go é uma linguagem que oferece ao desenvolvedor ferramentas poderosas para depuração diretamente "de fábrica". Mas muitos usam apenas fmt.Println e se perguntam por que suas goroutines se comportam como gatos em telhado quente. Vamos corrigir isso de uma vez por todas.

\n\n

Técnica nº1: Print inteligente — quando log.Fatal não é necessário

\n\n

Sim, eu sei o que você vai dizer: "Por que eu preciso do delve se posso imprimir uma variável?" E você estará certo em 80% dos casos. Mas o problema não é fmt.Println, e sim como você o usa.

\n\n

Migrando de Println para structured logging

\n\n

Em vez de espalhar dezenas de prints, use o pacote log ou slog (disponível desde Go 1.21):

\n\n
package main\n\nimport (\n    "log/slog"\n    "os"\n)\n\nfunc main() {\n    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))\n    \n    // Em vez de fmt.Println("erro:", err)\n    if err := doSomething(); err != nil {\n        logger.Error("operação falhou", \n            "error", err,\n            "module", "data_processor",\n            "attempt", 3,\n        )\n    }\n}\n
\n\n

Essa abordagem fornece logs estruturados, fáceis de analisar, filtrar e interpretar. Em produção, isso evitará ligações noturnas.

\n\n

Dica: compilação condicional para logs de debug

\n\n

Para não poluir a produção, use build tags:

\n\n
//go:build debug\n\npackage main\n\nvar debug = true\n
\n\n
//go:build !debug\n\npackage main\n\nvar debug = false\n
\n\n

Execute com a flag -tags debug — obtém logs detalhados. Sem a flag — produção limpa.

\n\n

Técnica nº2: Delve — seu detetive particular para Go

\n\n

Se a depuração com print é uma bicicleta, o Delve é uma Tesla. Este depurador foi criado especificamente para Go e entende goroutines, interfaces e até generics. A instalação é simples:

\n\n
go install github.com/go-delve/delve/cmd/dlv@latest\n
\n\n

Pontos de parada que sabem pensar

\n\n

Delve permite definir não apenas breakpoints, mas pontos condicionais:

\n\n
(dlv) break main.go:25 if userID == 42\n(dlv) continue\n
\n\n

O depurador só parará quando userID for igual a 42. Imagine quanto tempo isso economiza ao depurar loops.

\n\n

Inspeção de goroutines

\n\n

O mais temido em Go são deadlocks e race conditions. Delve mostra todas as goroutines ativas:

\n\n
(dlv) goroutines\n  Goroutine 1 - User: ./main.go:10 main.main (0x109a5b6)\n  Goroutine 2 - User: ./main.go:15 main.worker (0x109a6c8)\n* Goroutine 3 - User: ./main.go:22 main.worker (0x109a6c8)\n
\n\n

O asterisco indica a goroutine atual. Alterne entre elas:

\n\n
(dlv) goroutine 2\n(dlv) stack\n
\n\n

Trabalhando com memória: vendo o que há dentro

\n\n

O comando locals mostra todas as variáveis locais, e print exibe seus valores com tipos:

\n\n
(dlv) locals\ndata = []int len: 100000, cap: 100000\nresult = map[string]int ["error": 5, "success": 99995]\n(dlv) print data[0:5]\n[]int len: 5, cap: 100000, [42, 17, 89, 3, 256]\n
\n\n

Técnica nº3: Profiling com pprof — encontrando gargalos

\n\n

Seu código funciona, mas é lento? pprof é o profiler embutido do Go. Ele mostra onde o programa "engasga" e onde consome memória.

\n\n

Adicionando endpoint HTTP

\n

Blogs

Book Recommendations