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 substitui o antigo GOPATH, permitindo que projetos definam suas dependências de forma explícita e versionada. Com modules, você pode trabalhar fora do GOPATH e ter controle preciso sobre as versões das bibliotecas que seu projeto utiliza.

Nesta aula, exploraremos os arquivos go.mod e go.sum, o comando go get, as regras de versionamento semântico e como gerenciar dependências de forma eficiente. Ao final, você será capaz de iniciar um novo módulo, adicionar dependências e entender como o Go resolve versões.

go.mod e go.sum

O arquivo go.mod é o coração de um módulo Go. Ele define o nome do módulo (geralmente o repositório ou caminho do pacote), a versão do Go utilizada e as dependências do projeto com suas versões. Quando você executa go mod init <module-name>, o Go cria esse arquivo automaticamente.

O go.sum contém hashes criptográficos (SHA-256) das dependências baixadas, garantindo a integridade e segurança do código. Ele é gerado automaticamente e não deve ser editado manualmente. Sempre que uma dependência é adicionada ou atualizada, o go.sum é atualizado.

Exemplo de go.mod:

module github.com/meuprojeto/exemplo

go 1.21

require (
	github.com/gorilla/mux v1.8.1
	github.com/lib/pq v1.10.9
)

Exemplo de go.sum (trecho):

github.com/gorilla/mux v1.8.1 h1:TuMoUvkRETdXqU+3a2JqFg94GKNY4G57W9iM5J5k8ck=
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. Quando executado, ele baixa o pacote especificado, atualiza o go.mod e o go.sum, e coloca o código no cache local. Você pode especificar uma versão usando @versão ou @latest (padrão).

Exemplos de uso:

# Adicionar a 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.0

# 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 go mod tidy é uma boa prática para limpar o go.mod e go.sum, removendo dependências que não são mais necessárias e adicionando as que estão faltando.

Versionamento

O Go adota o versionamento semântico (SemVer) para módulos. As versões seguem o formato vMAJOR.MINOR.PATCH. Mudanças incompatíveis (breaking changes) devem ser indicadas com incremento na versão MAJOR. O Go também suporta prefixos como v0 para desenvolvimento inicial e v1 para versão estável.

Quando você depende de um módulo que ainda não atingiu a versão estável (v0.x.x), o Go assume que qualquer versão pode conter breaking changes. Para módulos com versão major >= 2, o caminho do módulo deve incluir o sufixo /v2, /v3, etc. Isso permite que diferentes versões maiores coexistam.

Exemplo de dependência com versão major >=2:

require (
	github.com/algum/modulo/v2 v2.3.4
)

O Go também utiliza o conceito de "versão mínima" (Minimal Version Selection - MVS). Isso significa que, ao resolver dependências, o Go escolhe a versão mínima necessária que satisfaz todas as restrições, evitando conflitos.

Dependências

Gerenciar dependências em Go é simples com modules. Você pode adicionar dependências diretamente no código e usar go mod tidy para sincronizar. O Go também oferece o comando go mod vendor para criar uma pasta vendor com todas as dependências, útil para ambientes offline ou revisão de código.

Dependências transitivas são automaticamente resolvidas. Se você usa a biblioteca A que depende da B, o Go baixa ambas. Você pode visualizar a árvore de dependências com go mod graph.

Boas práticas:

  • Sempre execute go mod tidy antes de commitar.
  • Evite depender de versões latest em produção; fixe versões específicas.
  • Use go get -u periodicamente para atualizar dependências, mas teste antes.
  • Para módulos privados, configure GOPRIVATE ou use replace no go.mod.

Referências

Exercícios

  1. Crie um novo módulo chamado github.com/meuapp/hello usando go mod init. Em seguida, adicione a dependência github.com/fatih/color na versão mais recente. Mostre o conteúdo do go.mod após a adição.

    ✓ Resposta:
    go mod init github.com/meuapp/hello
    go get github.com/fatih/color

    Conteúdo do go.mod:

    module github.com/meuapp/hello
    
    go 1.21
    
    require github.com/fatih/color v1.16.0
    
  2. No módulo criado no exercício 1, escreva um programa que imprime "Hello, World!" em vermelho usando o pacote color. Execute o programa e verifique a saída.

    ✓ Resposta:
    package main
    
    import "github.com/fatih/color"
    
    func main() {
        color.Red("Hello, World!")
    }

    Execute com go run main.go (assumindo que o arquivo se chama main.go).

  3. Use go get -u ./... para atualizar todas as dependências do módulo do exercício 1. Depois, execute go mod tidy e verifique se o go.sum foi atualizado.

    ✓ Resposta:
    go get -u ./...
    go mod tidy

    O go.sum será atualizado com os novos hashes se houver atualizações.

  4. Adicione uma dependência que não é usada no código (por exemplo, github.com/google/uuid). Execute go mod tidy e verifique se a dependência foi removida do go.mod.

    ✓ Resposta:
    go get github.com/google/uuid
    go mod tidy

    Após go mod tidy, a dependência não utilizada será removida do go.mod.

  5. Crie um módulo que dependa de dois pacotes: github.com/gorilla/mux e github.com/lib/pq. Use go mod graph para exibir a árvore de dependências e identifique se há dependências transitivas.

    ✓ Resposta:
    go get github.com/gorilla/mux github.com/lib/pq
    go mod graph

    Exemplo de saída:

    github.com/meuapp/hello github.com/gorilla/mux@v1.8.1
    github.com/meuapp/hello github.com/lib/pq@v1.10.9
    github.com/gorilla/mux@v1.8.1 github.com/gorilla/context@v1.1.1

    Aqui, github.com/gorilla/context é uma dependência transitiva de mux.

Boas Práticas e Observações Finais

Sempre versionar seu módulo seguindo SemVer e manter o go.mod limpo com go mod tidy. Evite usar replace a menos que necessário para substituir dependências locais ou forks. Para projetos maiores, considere usar go mod vendor para garantir builds reproduzíveis. Lembre-se de que o Go Modules é uma ferramenta poderosa que simplifica o gerenciamento de dependências, tornando o ecossistema Go mais robusto e confiável.