Ferramentas: vet, fmt, lint
Esta aula explora as principais ferramentas de qualidade de código em Go: go vet, gofmt e golangci-lint. Você aprenderá a usá-las no dia a dia, como integrá-las ao pipeline de desenvolvimento e como elas ajudam a manter um código limpo, correto e consistente.
Em Go, a qualidade do código não é apenas uma boa prática: é um valor cultural. A linguagem foi projetada para ser simples e legível, e as ferramentas oficiais e da comunidade reforçam isso. Nesta aula, você vai dominar três ferramentas essenciais: go vet, que analisa o código em busca de suspeitas de erros; gofmt, que padroniza a formatação; e golangci-lint, uma suíte completa de linters que eleva a qualidade do seu projeto a um nível profissional.
Vamos começar com os conceitos e depois mergulhar em exemplos práticos, mostrando como usar cada ferramenta no terminal, como interpretar suas saídas e como integrá-las ao seu fluxo de trabalho, seja localmente ou em CI/CD.
go vet
go vet é uma ferramenta oficial da linguagem que examina o código-fonte e relata construções suspeitas, como chamadas de funções com argumentos incorretos, problemas em operações de formatação, ou uso indevido de ponteiros. Ela não é um linter de estilo; seu foco é encontrar bugs reais que podem passar despercebidos em testes.
Para usar, basta executar go vet ./... no diretório do seu módulo. Ele analisa todos os pacotes do diretório atual e subdiretórios. Vamos ver um exemplo de código com problemas que o go vet detecta:
package main
import "fmt"
func main() {
// Erro: %d espera um inteiro, mas recebemos uma string
fmt.Printf("%d", "olá")
// Erro: copiar uma struct com sync.Mutex (go vet detecta)
type Resource struct { mu sync.Mutex; value int }
r1 := Resource{value: 1}
r2 := r1
_ = r2
}
Se você rodar go vet nesse código, verá um aviso como: fmt.Printf format %d has arg "olá" of wrong type string. Isso mostra como a ferramenta ajuda a evitar erros comuns.
Além disso, go vet é executado automaticamente como parte do go test e do go build (desde a versão 1.10). Isso significa que você não precisa rodá-lo separadamente em muitos fluxos, mas é sempre bom fazer uma verificação explícita.
gofmt
gofmt é o formatador oficial de código Go. Ele garante que todos os programas Go tenham a mesma formatação, eliminando discussões sobre indentação, alinhamento e espaçamento. A comunidade Go adotou o estilo do gofmt como padrão, e é praticamente obrigatório em qualquer projeto.
Para formatar um arquivo, use gofmt -w arquivo.go. A opção -w escreve o resultado de volta no arquivo. Você também pode usar -d para mostrar as diferenças sem modificar o arquivo, e -e para reportar todos os erros (não apenas os primeiros 10).
Aqui está um exemplo de código mal formatado:
package main
import "fmt"
func main(){
fmt.Println("olá")
}
Após rodar gofmt -w main.go, o resultado será:
package main
import "fmt"
func main() {
fmt.Println("olá")
}
Note que o gofmt também corrige a indentação, os espaços e até mesmo quebras de linha. Muitos editores e IDEs têm suporte a gofmt on save, o que garante que seu código esteja sempre formatado.
Uma alternativa mais moderna é go fmt, que é um comando que aplica gofmt a todos os arquivos do pacote atual. No entanto, gofmt é mais flexível e é a ferramenta subjacente.
golangci-lint (visão geral)
golangci-lint é uma ferramenta da comunidade que agrega dezenas de linters em um único binário. Ela combina análises estáticas, detecção de erros comuns, problemas de estilo e até mesmo questões de desempenho. É amplamente usada em projetos open source e em ambientes corporativos.
Para instalar, você pode baixar o binário da página de releases ou usar go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest. Depois de instalado, você pode rodar golangci-lint run no diretório do seu projeto.
Um exemplo de código que o golangci-lint pode detectar:
package main
import "fmt"
func main() {
var x int
fmt.Println(x) // x é sempre zero, mas não é um erro
// Exemplo de problema: errcheck - erro não tratado
f, _ := os.Open("arquivo.txt")
defer f.Close()
}
O linter errcheck reclamaria que o erro de os.Open não está sendo tratado. Outros linters populares incluem golint (estilo), govet (que já vimos), staticcheck (análise mais profunda) e gosec (segurança).
O golangci-lint é altamente configurável. Você pode criar um arquivo .golangci.yml na raiz do projeto para habilitar ou desabilitar linters, definir limites de complexidade e muito mais. Recomendo começar com a configuração padrão e ir ajustando conforme a necessidade.
Integração
Integrar essas ferramentas ao seu fluxo de trabalho é essencial para manter a qualidade do código de forma contínua. Aqui estão algumas práticas:
- Editor/IDE: Configure seu editor para rodar
gofmtao salvar (a maioria dos editores Go já faz isso por padrão). Paragolangci-lint, use a extensão oficial do VS Code ou o suporte nativo do GoLand. - Pre-commit hooks: Use ferramentas como
pre-commitouhuskypara rodargo vetegolangci-lintantes de cada commit. Isso evita que código problemático entre no repositório. - CI/CD: Em pipelines como GitHub Actions, GitLab CI ou Jenkins, adicione etapas para executar
go vet ./...egolangci-lint run. Assim, qualquer pull request que não passe nas verificações é bloqueado.
Exemplo de passo em um GitHub Action:
- name: Run go vet
run: go vet ./...
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
Além disso, você pode usar go fmt no CI para garantir que o código está formatado: test -z $(go fmt ./...). Isso falha se houver arquivos não formatados.
Outra integração útil é usar golangci-lint como um hook no seu editor, para que você receba feedback imediato enquanto escreve o código.
Boas práticas e observações finais
Adotar essas ferramentas desde o início do projeto é muito mais fácil do que corrigir um código legado. Mantenha seu código sempre formatado com gofmt, execute go vet regularmente e use golangci-lint como sua rede de segurança. Lembre-se de que essas ferramentas não substituem testes, mas complementam sua estratégia de qualidade.
Outra dica: leia a saída do golangci-lint com atenção. Muitas vezes ela aponta problemas que você não tinha percebido, como uso de variáveis não utilizadas ou códigos mortos. Corrija-os imediatamente para manter o código limpo e sustentável.
Referências
- Documentação oficial do go vet
- Documentação oficial do gofmt
- Site oficial do golangci-lint
- Repositório do golangci-lint no GitHub
- Artigo do blog oficial sobre gofmt
- Effective Go
- Code Review Comments (Wiki do Go)
Exercícios
- Escreva um programa Go que contenha um erro que o
go vetdetecte (por exemplo, um formato de printf incorreto). Executego vetno programa e explique a mensagem de erro.
package main
import "fmt"
func main() {
fmt.Printf("%d", "erro")
}
Ao rodar go vet, a saída será algo como: fmt.Printf format %d has arg "erro" of wrong type string. O erro indica que o verbo %d espera um valor inteiro, mas foi passada uma string.- Crie um arquivo Go com formatação incorreta (por exemplo, sem indentação adequada). Use
gofmt -dpara ver as diferenças e depoisgofmt -wpara formatar. Mostre o antes e o depois.
package main
func main(){
fmt.Println("oi")
}
Depois de gofmt -w:package main
func main() {
fmt.Println("oi")
}
As diferenças incluem a adição de uma linha em branco após o package, espaçamento adequado e indentação com tab.- Instale o
golangci-linte rode no seu projeto atual (ou em um exemplo). Liste os linters que ele executa por padrão e explique o que um deles faz.
golangci-lint run, você verá a lista de linters ativos na saída, como errcheck, govet, ineffassign, staticcheck, unused, etc. Por exemplo, errcheck verifica se os erros retornados por funções estão sendo tratados, evitando que erros sejam ignorados silenciosamente.- Configure uma integração de CI (ex.: GitHub Actions) para um projeto Go que execute
go vetegolangci-lint. Escreva o passo YAML necessário.
name: CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Run go vet
run: go vet ./...
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
- Pesquise sobre o linter
staticcheck(que é incluído no golangci-lint). Dê um exemplo de um problema que ele detecta e como corrigi-lo.
staticcheck detecta, por exemplo, uso de variáveis não utilizadas ou importações desnecessárias. Exemplo:package main
import "fmt"
func main() {
x := 10
fmt.Println("oi")
}
O staticcheck reporta que x é declarado e não usado. A correção é remover a linha x := 10.