Módulos e pacotes em Go: go.mod, dependências e versionamento

Capítulo 3

Tempo estimado de leitura: 8 minutos

+ Exercício

O que são módulos e pacotes em Go

Em Go, pacote é a unidade de organização e reutilização de código: um diretório com arquivos .go que declaram o mesmo package. Já um módulo é uma coleção versionada de pacotes, definida por um arquivo go.mod na raiz. O módulo determina: (1) o caminho de importação base, (2) a versão mínima do Go usada, e (3) as dependências externas e suas versões.

Na prática: você importa pacotes pelo caminho (ex.: fmt ou github.com/google/uuid), e o módulo resolve de onde vem cada import e em qual versão.

Criando um módulo com go mod init (passo a passo)

Crie uma pasta para o projeto e inicialize o módulo. O nome do módulo normalmente é o caminho do repositório (quando você pretende publicar), mas pode ser um nome local durante estudos.

mkdir hello-modules && cd hello-modules go mod init example.com/hello-modules

Isso cria um go.mod inicial. Um exemplo típico:

module example.com/hello-modules go 1.22

module define o prefixo dos imports do seu próprio código. go define a versão mínima/target da linguagem e influencia comportamentos do sistema de módulos e do compilador.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Importando pacotes padrão

Pacotes da biblioteca padrão não entram como dependências no go.mod. Exemplo:

package main import ( "fmt" "time" ) func main() { fmt.Println("Agora:", time.Now()) }

Os imports fmt e time são resolvidos localmente pela toolchain do Go.

Importando pacotes externos (e como a dependência entra no módulo)

Quando você importa um pacote externo, o Go baixa o módulo correspondente e registra a dependência no go.mod (e checksums no go.sum).

Exemplo usando UUID:

package main import ( "fmt" "github.com/google/uuid" ) func main() { id := uuid.New() fmt.Println("ID:", id.String()) }

Ao rodar o comando que resolve dependências (por exemplo, ao compilar/testar), o Go adiciona a dependência. No fluxo moderno, você pode adicionar explicitamente com go get:

go get github.com/google/uuid@latest

Depois, o go.mod passa a ter uma seção require:

module example.com/hello-modules go 1.22 require github.com/google/uuid v1.6.0

Entendendo go.mod na prática

O go.mod é a “fonte da verdade” das dependências diretas do seu módulo. As partes mais comuns:

  • module ...: caminho do módulo (prefixo dos imports internos).
  • go ...: versão do Go alvo.
  • require ...: dependências e versões.
  • replace ... (opcional): substitui um módulo por outro caminho/versão (muito usado em desenvolvimento local).
  • exclude ... (raro): impede uma versão específica.

Exemplo com replace (útil quando você tem um módulo local em desenvolvimento):

replace example.com/outro-modulo => ../outro-modulo

Isso faz o Go usar o diretório local em vez de baixar do repositório remoto.

Entendendo go.sum (integridade e reprodutibilidade)

O arquivo go.sum contém hashes criptográficos (checksums) das versões dos módulos baixados. Ele ajuda a garantir que o conteúdo baixado hoje é o mesmo conteúdo baixado amanhã, evitando alterações inesperadas na cadeia de dependências.

Pontos importantes:

  • go.sum pode ter entradas de dependências diretas e indiretas.
  • É normal ele ter mais linhas do que o go.mod.
  • Você deve versionar go.sum junto com o código para builds reprodutíveis.

Adicionar, atualizar e remover dependências (fluxo moderno)

Adicionar uma dependência

Você pode adicionar de duas formas comuns:

  • Importar no código e rodar um comando que resolva módulos (ex.: go test), deixando o Go atualizar go.mod/go.sum.
  • Usar go get explicitamente.
go get github.com/google/uuid@latest

Para fixar uma versão específica:

go get github.com/google/uuid@v1.5.0

Atualizar dependências

Para atualizar uma dependência para a última versão compatível (dentro do mesmo major, em geral):

go get -u github.com/google/uuid

Para atualizar todas as dependências (use com cuidado em projetos reais):

go get -u ./...

Para atualizar para uma versão exata:

go get github.com/google/uuid@v1.6.0

Remover dependências

Em Go, você normalmente remove uma dependência removendo o import/uso do pacote e depois limpando o grafo de módulos com go mod tidy.

go mod tidy

go mod tidy faz duas coisas principais: (1) adiciona dependências que estão sendo usadas mas não estão declaradas, e (2) remove dependências que não são mais necessárias (incluindo indiretas), ajustando go.mod e go.sum.

Inspecionando módulos e versões com go list -m

Para ver o módulo principal:

go list -m

Para listar todos os módulos no build (diretos e indiretos):

go list -m all

Para ver detalhes (inclui diretório, versão, substituições):

go list -m -json all

Para verificar por que um módulo está no grafo (quem o puxa):

go mod why -m github.com/google/uuid

Versionamento semântico (SemVer) do ponto de vista do consumidor

Como consumidor de uma biblioteca, você quer atualizações seguras e previsíveis. O versionamento semântico usa o formato MAJOR.MINOR.PATCH:

  • PATCH (ex.: 1.6.0 → 1.6.1): correções de bug, sem quebrar compatibilidade.
  • MINOR (ex.: 1.6.0 → 1.7.0): novas funcionalidades compatíveis (não deve quebrar código existente).
  • MAJOR (ex.: 1.x → 2.0.0): mudanças incompatíveis (pode quebrar seu código).

Em Go Modules, majors a partir de v2 normalmente aparecem no caminho do módulo/import. Exemplo típico:

  • v1: example.com/lib
  • v2: example.com/lib/v2

Como consumidor, isso significa que atualizar de v1 para v2 geralmente exige mudar imports e possivelmente adaptar chamadas. Já atualizações de patch/minor dentro do mesmo major tendem a ser mais seguras.

Boas práticas para você como consumidor:

  • Prefira atualizar dentro do mesmo major quando quiser baixo risco.
  • Fixe versões quando precisar de reprodutibilidade estrita (ex.: em ambientes regulados), e use go mod tidy para manter o grafo consistente.
  • Antes de grandes atualizações, inspecione o changelog e rode sua suíte de testes.

Exercício: criando dois pacotes internos (internal/) e públicos (pkg/)

Objetivo

Você vai criar um módulo com:

  • Um pacote em internal/ (uso restrito ao módulo).
  • Um pacote em pkg/ (API pública para outros módulos consumirem).
  • Um main que usa ambos.

Estrutura sugerida

hello-modules/   go.mod   cmd/     app/       main.go   internal/     secret/       secret.go   pkg/     greet/       greet.go

Passo 1: criar o pacote público em pkg/greet

Crie pkg/greet/greet.go:

package greet import "fmt" // Hello é parte da API pública do módulo. func Hello(name string) string { if name == "" { name = "mundo" } return fmt.Sprintf("Olá, %s!", name) }

Note que Hello começa com letra maiúscula: isso o torna exportado (visível para outros pacotes).

Passo 2: criar o pacote interno em internal/secret

Crie internal/secret/secret.go:

package secret // token não é exportado (minúsculo). func token() string { return "abc-123" } // TokenForLog expõe algo controlado para uso interno do módulo. func TokenForLog() string { return token() }

Qualquer pacote fora do seu módulo não conseguirá importar example.com/hello-modules/internal/secret. Essa é uma regra do Go: diretórios sob internal/ só podem ser importados por código dentro do diretório pai (e seus subdiretórios) que contém internal.

Passo 3: criar o executável em cmd/app

Crie cmd/app/main.go:

package main import ( "fmt" "example.com/hello-modules/internal/secret" "example.com/hello-modules/pkg/greet" ) func main() { fmt.Println(greet.Hello("Gopher")) fmt.Println("token interno:", secret.TokenForLog()) }

Passo 4: validar dependências e limpeza do módulo

Rode:

go mod tidy go list -m all

Como esse exercício usa apenas biblioteca padrão, o go.mod deve permanecer sem require de módulos externos.

Boas práticas: exposição de APIs e organização de pacotes

Quando usar internal/

  • Use para código que você quer poder refatorar sem se preocupar com consumidores externos.
  • Ótimo para detalhes de implementação, integrações, helpers e camadas que não devem virar contrato público.

Quando usar pkg/

  • Use quando você quer sinalizar explicitamente que aquele pacote é pensado para ser importado por outros módulos.
  • Mantenha a API pequena e estável: exporte o mínimo necessário.

Dicas para desenhar uma API pública melhor

  • Evite exportar tipos/funções “por conveniência”: uma vez exportado, vira compromisso de compatibilidade.
  • Prefira nomes claros e coesos: pacotes com responsabilidade única e nomes curtos.
  • Documente com comentários em identificadores exportados (ex.: // Hello ...), pois isso alimenta a documentação do Go.
  • Não exponha detalhes internos (struct fields, tipos concretos) se você pode expor interfaces ou funções de alto nível.
  • Evite ciclos de import: se dois pacotes dependem um do outro, reavalie a separação de responsabilidades.

Armadilhas comuns com módulos

  • Import path inconsistente: o caminho em module ... deve bater com os imports internos do projeto.
  • Atualizar tudo sem critério: go get -u ./... pode introduzir mudanças indiretas; prefira atualizar dependências específicas.
  • Esquecer o go mod tidy: é o comando que mantém o módulo “honesto” em relação ao que o código realmente usa.

Agora responda o exercício sobre o conteúdo:

Ao remover o uso de um pacote externo do seu código Go, qual é o fluxo mais adequado para garantir que as dependências em go.mod e go.sum sejam atualizadas corretamente?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Em Go, a remoção correta é tirar o import/uso no código e rodar go mod tidy, que remove dependências não necessárias (diretas e indiretas) e mantém go.mod e go.sum consistentes.

Próximo capitúlo

Sintaxe essencial de Go: variáveis, constantes, controle de fluxo e arrays/slices

Arrow Right Icon
Capa do Ebook gratuito Go (Golang) para Iniciantes: Fundamentos, Concorrência e Estrutura de Projetos
17%

Go (Golang) para Iniciantes: Fundamentos, Concorrência e Estrutura de Projetos

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.