Go Modules é o sistema oficial de gerenciamento de dependências introduzido no Go 1.11 e tornado padrão a partir do Go 1.16. Ele substituiu o antigo GOPATH, permitindo que projetos sejam desenvolvidos fora dele e tenham suas dependências versionadas de forma precisa e reproduzível.

Nesta aula, vamos explorar os componentes fundamentais do sistema de módulos: os arquivos go.mod e go.sum, o comando go get, o versionamento semântico e as boas práticas para gerenciar dependências.

go.mod e go.sum

O arquivo go.mod é o coração de um módulo Go. Ele define o nome do módulo, a versão do Go utilizada e as dependências do projeto, incluindo suas versões exatas. Quando você cria um novo módulo com go mod init <module-path>, um arquivo go.mod é gerado.

O arquivo go.sum contém hashes criptográficos (SHA-256) de cada versão de dependência baixada. Ele garante a integridade e a reprodutibilidade das builds, pois qualquer alteração nas dependências resultará em hashes diferentes. Ambos os arquivos devem ser versionados no controle de versão.

// Exemplo de go.mod
module github.com/meuprojeto/exemplo

go 1.21

require (
    github.com/gorilla/mux v1.8.1
    golang.org/x/text v0.14.0
)
// Exemplo de go.sum (parcial)
github.com/gorilla/mux v1.8.1 h1:TuMoUvkRETdXqU+3a6mhFfYEBJv5c6G=Q0fRZib5x0=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
...

go get

O comando go get é usado para adicionar, atualizar ou remover dependências. Ele baixa o pacote especificado, atualiza o arquivo go.mod e adiciona os hashes ao go.sum. A partir do Go 1.18, go get por padrão apenas adiciona dependências; para atualizar, use go get -u.

// Adicionar uma dependência na versão mais recente
go get github.com/gorilla/mux

// Adicionar uma versão específica
go get github.com/gorilla/mux@v1.8.1

// Atualizar todas as dependências para a versão mais recente (compatível)
go get -u ./...

// Remover dependências não utilizadas
go mod tidy

O comando go mod tidy é essencial para limpar o go.mod e go.sum, removendo dependências não utilizadas e adicionando as que estão faltando.

Versionamento

Go Modules adota o versionamento semântico (semver) no formato vMAJOR.MINOR.PATCH. Versões estáveis começam com v1 ou superior. Para versões principais (major) diferentes, o Go permite que múltiplas versões principais coexistam, pois o caminho do módulo inclui o sufixo /v2, /v3, etc.

Versões pré-lançamento (ex: v1.0.0-beta1) e pseudo-versões (ex: v0.0.0-20230101123456-abcdef123456) também são suportadas. Pseudo-versões são úteis para testar commits específicos que ainda não foram taggeados.

// Exemplo de módulo com versão principal v2
module github.com/usuario/projeto/v2

go 1.21

require (
    github.com/usuario/projeto/v2 v2.0.0
)

Para atualizar a versão major, utilize go get com o novo caminho: go get github.com/usuario/projeto/v2@v2.0.0.

Dependências

As dependências são gerenciadas de forma descentralizada: o Go baixa os módulos diretamente dos repositórios de origem (como GitHub) ou através de proxies como proxy.golang.org. O arquivo go.sum garante que as versões baixadas correspondam exatamente às esperadas.

Para verificar dependências, use go mod verify. Para listar dependências, go list -m all. Para entender a árvore de dependências, go mod graph. É importante manter as dependências atualizadas e evitar dependências desnecessárias.

// Listar todas as dependências
go list -m all

// Verificar integridade do go.sum
go mod verify

// Mostrar grafo de dependências
go mod graph

Boas práticas: sempre execute go mod tidy antes de commitar, mantenha o go.mod e go.sum no repositório, e evite depender de versões v0 ou pré-lançamento em produção.

Referências

Exercícios

  1. Crie um novo módulo chamado github.com/meuapp/hello usando go mod init.

    ✓ Resposta: Execute no terminal:
    mkdir hello && cd hello
    go mod init github.com/meuapp/hello
    Isso criará um arquivo go.mod com o conteúdo:
    module github.com/meuapp/hello
    
    go 1.21
  2. Adicione a dependência github.com/google/uuid na versão v1.6.0 ao módulo criado.

    ✓ Resposta: Execute:
    go get github.com/google/uuid@v1.6.0
    O go.mod será atualizado para incluir:
    require github.com/google/uuid v1.6.0
  3. Após adicionar algumas dependências, execute o comando para remover dependências não utilizadas.

    ✓ Resposta: Execute:
    go mod tidy
    Esse comando remove dependências não utilizadas do go.mod e adiciona as faltantes.
  4. Atualize todas as dependências do módulo para as versões mais recentes compatíveis.

    ✓ Resposta: Execute:
    go get -u ./...
    Isso atualiza todas as dependências para a última versão minor ou patch (mantendo a major).
  5. Crie um módulo que depende de duas versões diferentes de um mesmo pacote (ex: v1 e v2 do mesmo módulo). Explique como isso é possível.

    ✓ Resposta: Go permite que duas versões principais coexistam porque cada versão major tem seu próprio caminho de módulo. Por exemplo, github.com/user/mod v1.x e github.com/user/mod/v2 v2.x são tratados como módulos diferentes. No go.mod, você pode ter ambos:
    require (
        github.com/user/mod v1.0.0
        github.com/user/mod/v2 v2.0.0
    )
    No código, você importa com o caminho correspondente: import "github.com/user/mod" e import "github.com/user/mod/v2".

Observações finais: O sistema de módulos do Go é robusto e projetado para escalar. Sempre versionar go.mod e go.sum, e use go mod tidy regularmente para manter o projeto limpo. Em ambientes de produção, considere usar um proxy de módulos para garantir disponibilidade e velocidade.