Artigo 42 — Documentação com godoc e boas práticas de comentário
Curso: Dominando Go em 1 Ano Prof. Ricardo Matos Módulo 7 — Ferramentas, CLI e Qualidade
Documentação como parte do código
Em Go, documentação não é um arquivo separado nem uma ferramenta externa — é o próprio código comentado. O godoc extrai comentários diretamente do código fonte e os transforma em documentação navegável, disponível tanto na linha de comando quanto no navegador.
Essa abordagem tem uma consequência poderosa: documentação que não está no código não existe para o godoc. Isso incentiva manter a documentação próxima do que ela descreve — reduzindo a probabilidade de ficar desatualizada.
As regras do godoc
O godoc segue convenções simples e estritas. Comentários de documentação são aqueles imediatamente antes de uma declaração, sem linha em branco entre o comentário e o identificador:
// Package financeiro fornece tipos e operações para gestão financeira,
// incluindo contas bancárias, transferências e relatórios de movimentação.
//
// Uso básico:
//
// conta, err := financeiro.NovaConta("Ricardo", 1000.00)
// if err != nil {
// log.Fatal(err)
// }
// conta.Depositar(500.00)
//
// Para mais exemplos, consulte os arquivos _test.go do pacote.
package financeiro
Regra 1: o comentário começa com o nome do identificador. Isso permite que o godoc gere índices e o texto faça sentido quando lido isoladamente.
Regra 2: sem linha em branco entre o comentário e a declaração. Uma linha em branco quebra a associação — o godoc não vai reconhecer o comentário como documentação daquele identificador.
Regra 3: use frases completas. O primeiro parágrafo é exibido nos índices como sumário.
Documentando funções e métodos
// NovaConta cria e retorna uma nova conta bancária para o titular informado.
// O depósito inicial deve ser maior ou igual a zero; valores negativos retornam erro.
//
// O titular é obrigatório — uma string vazia retorna ErrTitularVazio.
//
// Exemplo:
//
// conta, err := NovaConta("Ana Silva", 500.00)
// if err != nil {
// // tratar erro
// }
func NovaConta(titular string, depositoInicial float64) (*Conta, error) {
if titular == "" {
return nil, ErrTitularVazio
}
if depositoInicial < 0 {
return nil, fmt.Errorf("depósito inicial não pode ser negativo: %.2f", depositoInicial)
}
return &Conta{
titular: titular,
saldo: depositoInicial,
}, nil
}
// Depositar adiciona o valor informado ao saldo da conta.
// Retorna ErrValorInvalido se o valor for menor ou igual a zero.
func (c *Conta) Depositar(valor float64) error {
if valor <= 0 {
return ErrValorInvalido
}
c.mu.Lock()
defer c.mu.Unlock()
c.saldo += valor
return nil
}
// Saldo retorna o saldo atual da conta.
// Esta operação é thread-safe.
func (c *Conta) Saldo() float64 {
c.mu.RLock()
defer c.mu.RUnlock()
return c.saldo
}
Documentando tipos e constantes
// Conta representa uma conta bancária com operações de depósito, saque e transferência.
// Conta é segura para uso concorrente.
type Conta struct {
titular string
saldo float64
mu sync.RWMutex
}
// StatusConta representa o estado atual de uma conta bancária.
type StatusConta int
const (
// StatusAtiva indica que a conta está ativa e operacional.
StatusAtiva StatusConta = iota
// StatusBloqueada indica que a conta foi bloqueada temporariamente.
// Operações de débito são recusadas enquanto a conta estiver bloqueada.
StatusBloqueada
// StatusEncerrada indica que a conta foi encerrada definitivamente.
// Nenhuma operação é permitida em contas encerradas.
StatusEncerrada
)
// ErrSaldoInsuficiente é retornado quando um saque ou transferência
// excede o saldo disponível na conta.
var ErrSaldoInsuficiente = errors.New("saldo insuficiente")
// ErrTitularVazio é retornado quando o nome do titular é uma string vazia.
var ErrTitularVazio = errors.New("titular não pode ser vazio")
// ErrValorInvalido é retornado quando o valor de uma operação é menor
// ou igual a zero.
var ErrValorInvalido = errors.New("valor deve ser maior que zero")
Formatação especial no godoc
O godoc reconhece alguns padrões de formatação automaticamente:
// Processar executa o pipeline de processamento em três fases:
//
// 1. Validação dos dados de entrada
// 2. Transformação e enriquecimento
// 3. Persistência no banco de dados
//
// Considerações de performance:
//
// A fase de transformação pode ser custosa para entradas grandes.
// Para lotes acima de 10.000 itens, considere usar ProcessarEmLotes.
//
// Exemplos de uso típicos:
//
// // Processamento simples
// err := Processar(ctx, dados)
//
// // Com opções
// err := Processar(ctx, dados, ComParalelismo(4), ComTimeout(30*time.Second))
//
// Código de exemplo completo em https://pkg.go.dev/meu-pacote#example-Processar
func Processar(ctx context.Context, dados []byte, opts ...Opcao) error {
Blocos de código são indentados com um tab (ou espaços adicionais). O godoc os renderiza como <pre>.
Listas numeradas com o padrão N. são reconhecidas automaticamente desde o Go 1.19.
Links — URLs completas são automaticamente transformadas em hiperlinks.
Exemplos executáveis
Funções de exemplo são verificadas pelo go test e exibidas na documentação:
// arquivo: financeiro/conta_example_test.go
package financeiro_test
import (
"fmt"
"log"
"meu-modulo/financeiro"
)
func ExampleNovaConta() {
conta, err := financeiro.NovaConta("Ricardo Matos", 1000.00)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Titular: %s\n", conta.Titular())
fmt.Printf("Saldo: R$ %.2f\n", conta.Saldo())
// Output:
// Titular: Ricardo Matos
// Saldo: R$ 1000.00
}
func ExampleConta_Depositar() {
conta, _ := financeiro.NovaConta("Ana", 500.00)
if err := conta.Depositar(250.00); err != nil {
log.Fatal(err)
}
fmt.Printf("Saldo após depósito: R$ %.2f\n", conta.Saldo())
// Output:
// Saldo após depósito: R$ 750.00
}
func ExampleConta_Sacar_saldoInsuficiente() {
conta, _ := financeiro.NovaConta("Carlos", 100.00)
err := conta.Sacar(200.00)
fmt.Println(err)
// Output:
// saldo insuficiente
}
A convenção de nomenclatura para exemplos:
- ExampleFuncao — exemplo para uma função
- ExampleTipo_Metodo — exemplo para um método
- ExampleTipo_Metodo_sufixo — múltiplos exemplos para o mesmo método
Rodando o godoc localmente
# Instalar godoc
go install golang.org/x/tools/cmd/godoc@latest
# Iniciar servidor local na porta 6060
godoc -http=:6060
Acesse http://localhost:6060/pkg/meu-modulo/ para ver a documentação do seu módulo renderizada.
go doc: documentação na linha de comando
# Documentação de um pacote
go doc fmt
# Documentação de uma função específica
go doc fmt.Printf
# Documentação de um tipo
go doc net/http.Request
# Documentação de um método
go doc net/http.Request.Header
# Documentação completa incluindo não-exportados
go doc -all ./financeiro/
# Exemplo específico
go doc -src fmt.Printf # mostra o código fonte
pkg.go.dev: documentação pública
Todo módulo publicado no GitHub (ou qualquer VCS público) aparece automaticamente em pkg.go.dev após ser referenciado por um go get. A documentação é gerada automaticamente a partir dos comentários do código.
Para garantir boa apresentação no pkg.go.dev:
// Package meuservico fornece um cliente HTTP para a API de Pagamentos XYZ.
//
// # Instalação
//
// go get github.com/minha-empresa/meuservico
//
// # Uso rápido
//
// cliente := meuservico.NovoCliente("minha-api-key")
// resposta, err := cliente.CriarPagamento(ctx, meuservico.Pagamento{
// Valor: 100.00,
// Moeda: "BRL",
// Descricao: "Pedido #1001",
// })
//
// # Autenticação
//
// Todas as requisições exigem uma API key válida, obtida no painel em
// https://app.meuservico.com/api-keys
//
// # Tratamento de erros
//
// Erros da API são retornados como *meuservico.ErroAPI, que contém o
// código HTTP e a mensagem de erro detalhada.
package meuservico
Os cabeçalhos # Seção são suportados desde o Go 1.19 e renderizados como <h3> no pkg.go.dev.
README.md e doc.go
Para pacotes com documentação extensa, é comum separar o comentário do pacote em um arquivo dedicado doc.go:
// doc.go — contém apenas o comentário do pacote e a declaração package
// Package cache implementa uma camada de cache em memória com suporte a
// expiração por TTL, eviction por LRU e métricas de hit/miss.
//
// # Exemplo básico
//
// c := cache.Novo(cache.Config{
// Capacidade: 1000,
// TTL: 5 * time.Minute,
// })
//
// c.Set("chave", "valor")
//
// v, existe := c.Get("chave")
// if existe {
// fmt.Println(v)
// }
//
// # Eviction policy
//
// Quando a capacidade máxima é atingida, o item menos recentemente usado
// (LRU — Least Recently Used) é removido automaticamente.
package cache
Convenções de comentário por tipo
// Comentários de pacote: "Package nome fornece/implementa..."
package autenticacao
// Tipos: "NomeTipo representa/é um/a..."
// Usuario representa um usuário autenticado no sistema.
type Usuario struct { }
// Interfaces: "NomeInterface é implementado por..."
// Autenticador é implementado por qualquer tipo que possa validar credenciais.
type Autenticador interface { }
// Funções construtoras: "NovoTipo cria/retorna..."
// NovoUsuario cria e retorna um novo usuário com o email e senha informados.
func NovoUsuario(email, senha string) (*Usuario, error) { }
// Métodos de leitura: "Nome retorna..."
// Email retorna o endereço de email do usuário.
func (u *Usuario) Email() string { }
// Métodos de escrita: "Nome define/atualiza/registra..."
// DefinirSenha atualiza a senha do usuário com o hash fornecido.
func (u *Usuario) DefinirSenha(hash string) { }
// Métodos booleanos: "Nome relata/verifica se..."
// EstaAtivo relata se o usuário está ativo no sistema.
func (u *Usuario) EstaAtivo() bool { }
// Erros sentinela: "Err... é retornado quando..."
// ErrCredenciaisInvalidas é retornado quando email ou senha não conferem.
var ErrCredenciaisInvalidas = errors.New("credenciais inválidas")
// Constantes: explicar o valor quando não é óbvio
const (
// SessaoMaxima define o tempo máximo de uma sessão inativa antes da expiração.
SessaoMaxima = 30 * time.Minute
// TentativasMaximas define o número de tentativas de login antes do bloqueio.
TentativasMaximas = 5
)
Deprecated: marcando APIs obsoletas
// Conectar estabelece uma conexão com o servidor.
//
// Deprecated: use ConectarComContext para suporte a cancelamento e timeout.
// Esta função será removida na versão 3.0.
func Conectar(host string) (*Conexao, error) {
return ConectarComContext(context.Background(), host)
}
// ConectarComContext estabelece uma conexão respeitando o context fornecido,
// permitindo cancelamento e timeout.
func ConectarComContext(ctx context.Context, host string) (*Conexao, error) {
// implementação atual
}
Ferramentas como staticcheck detectam uso de funções marcadas como Deprecated: e emitem avisos.
Documentação de erros esperados
// Transferir move o valor especificado da conta de origem para a de destino.
//
// Erros possíveis:
// - ErrSaldoInsuficiente: saldo da conta de origem é menor que o valor
// - ErrContaBloqueada: conta de origem ou destino está bloqueada
// - ErrValorInvalido: valor é menor ou igual a zero
// - ErrMesmasConta: origem e destino são a mesma conta
func (s *Servico) Transferir(ctx context.Context, origemID, destinoID string, valor float64) error {
Checklist de documentação
Antes de publicar ou fazer code review, verifique:
□ O pacote tem comentário começando com "Package nome..."?
□ Toda função/método exportado tem comentário começando com seu nome?
□ Todo tipo exportado tem comentário descritivo?
□ Erros sentinela exportados têm comentário explicando quando são retornados?
□ Funções complexas têm exemplos executáveis?
□ Parâmetros com comportamento não óbvio estão documentados?
□ APIs obsoletas estão marcadas com "Deprecated:"?
□ O comentário faz sentido quando lido isoladamente do código?
□ go doc ./... não exibe "missing documentation" para símbolos públicos?
Resumo do que foi coberto
Este artigo apresentou documentação em Go de forma completa: as regras do godoc — comentários imediatamente antes das declarações começando com o nome do identificador — formatação especial com blocos de código e listas, exemplos executáveis verificados pelo go test, o servidor local do godoc, o comando go doc para consulta na linha de comando, boas práticas de publicação no pkg.go.dev, o arquivo doc.go para documentação extensa, convenções por tipo de identificador, marcação de APIs obsoletas com Deprecated: e um checklist de qualidade. O próximo artigo explora profiling e otimização de performance.
Referências e leituras complementares
-
Go Blog: Go Doc Comments — Guia oficial completo sobre comentários de documentação. https://go.dev/doc/comment
-
pkg.go.dev — Portal de documentação oficial de todos os módulos Go públicos. https://pkg.go.dev
-
Documentação godoc — Referência da ferramenta godoc. https://pkg.go.dev/golang.org/x/tools/cmd/godoc
-
Go Blog: Testable Examples in Go — Como exemplos executáveis funcionam. https://go.dev/blog/examples
-
Go Code Review Comments — Documentation — Convenções de comentário da equipe Go. https://github.com/golang/go/wiki/CodeReviewComments#commentary
-
staticcheck — SA1019 — Detecção de uso de APIs marcadas como Deprecated. https://staticcheck.dev/docs/checks#SA1019
Próximo artigo: Artigo 43 — Profiling e otimização de performance em Go**
you asked
Sim