Pacotes e o sistema de módulos com go mod

1. Fundamentos de Pacotes em Go

Em Go, todo código fonte pertence a um pacote. A estrutura de diretórios define a hierarquia de pacotes, e a declaração package no topo de cada arquivo determina a qual pacote ele pertence. Um diretório pode conter múltiplos arquivos, desde que todos declarem o mesmo nome de pacote.

// main.go
package main

import (
    "fmt"
    "meumodulo/calculadora"
)

func main() {
    resultado := calculadora.Somar(2, 3)
    fmt.Println("Resultado:", resultado)
}
// calculadora/soma.go
package calculadora

// Somar retorna a soma de dois inteiros
func Somar(a, b int) int {
    return a + b
}

Importar pacotes segue caminhos absolutos a partir da raiz do módulo. É possível usar aliases para evitar conflitos de nome:

import (
    calc "meumodulo/calculadora"
    "fmt"
)

Ciclos de importação ocorrem quando o pacote A importa B, e B importa A (direta ou indiretamente). Go detecta isso em tempo de compilação. Para evitar, reavalie a responsabilidade de cada pacote — extraia interfaces ou mova tipos compartilhados para um pacote comum de menor acoplamento.

2. Introdução aos Módulos com go mod

Um módulo é uma coleção de pacotes Go versionados como uma unidade. O arquivo go.mod na raiz define o caminho do módulo, a versão do Go e as dependências.

Inicialize um módulo:

go mod init github.com/usuario/meuprojeto

Isso gera:

module github.com/usuario/meuprojeto

go 1.22

O versionamento semântico (v1.2.3) é obrigatório para dependências publicadas. Go usa tags Git no formato v1.0.0 para identificar versões.

3. Gerenciamento de Dependências

Adicione uma dependência externa:

go get github.com/gorilla/mux@v1.8.1

O comando go mod tidy limpa dependências não utilizadas e adiciona as faltantes:

go mod tidy

Para atualizar para a versão mais recente:

go get -u github.com/gorilla/mux

Para remover, basta deletar as referências no código e executar go mod tidy.

Pseudo-versões são usadas quando não há tag semântica disponível, no formato v0.0.0-20240301123456-commit_hash:

go get github.com/alguem/lib@commit_hash

4. O Arquivo go.sum e Integridade

O go.sum contém checksums (hash SHA-256) de cada dependência baixada. Ele garante que builds sejam reproduzíveis e seguros contra adulteração.

github.com/gorilla/mux v1.8.1 h1:TuMoUvkRETdXqU+3x7d9pE4gK3c4iA5c3I0i0iK5Y=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=

Se o checksum não corresponder, o go build falha. Para resolver conflitos (raro), use:

go mod tidy

Ou remova entradas específicas manualmente e execute go mod verify.

5. Módulos Locais e Substituições

Durante o desenvolvimento, é comum apontar para um módulo local com replace:

module github.com/usuario/meuprojeto

go 1.22

require github.com/usuario/biblioteca v0.0.0

replace github.com/usuario/biblioteca => ../biblioteca-local

Isso permite testar mudanças sem publicar. Para múltiplos módulos no mesmo repositório, cada subdiretório pode ter seu próprio go.mod.

Módulos privados exigem configuração de autenticação no ~/.netrc ou variáveis de ambiente GOPRIVATE:

export GOPRIVATE=github.com/empresa/*

6. Workspaces (Go 1.18+)

Workspaces permitem gerenciar múltiplos módulos simultaneamente sem modificar go.mod de cada um.

go work init ./modulo-a ./modulo-b

Isso cria go.work:

go 1.22

use (
    ./modulo-a
    ./modulo-b
)

Adicione mais módulos:

go work use ./modulo-c

Quando usar workspaces vs. replace? Workspaces são ideais para desenvolvimento local de múltiplos módulos inter-relacionados (ex: monorepo). Replace é melhor para ajustes pontuais em dependências específicas sem impacto global.

7. Boas Práticas e Padrões

Organize pacotes por responsabilidade, não por tipo. Evite nomes genéricos como util ou common:

meuprojeto/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── auth/
│   ├── db/
│   └── handler/
└── pkg/
    └── api/

Nomeação: pacotes devem ter nomes curtos, descritivos e em minúsculo. O nome do pacote deve ser o mesmo do diretório.

Para versionamento v2+, altere o caminho do módulo:

module github.com/usuario/projeto/v2

Isso permite coexistência de versões maiores no mesmo projeto.

Conclusão: O sistema de módulos do Go, combinado com pacotes bem estruturados, oferece um gerenciamento de dependências robusto, seguro e simples. Dominar go mod é essencial para qualquer desenvolvedor Go profissional.

Referências