<h2>Entendendo Módulos em Go</h2>
<p>Um módulo em Go é uma coleção de pacotes Go armazenados em um diretório com um arquivo <code>go.mod</code> na raiz. Este arquivo define o nome do módulo, a versão mínima do Go necessária e todas as dependências externas do projeto. Antes do Go 1.11, a comunidade dependia do <code>GOPATH</code> para gerenciar dependências, um modelo que gerava conflitos de versão e dificultava a manutenção. O sistema de módulos resolveu esse problema de forma elegante e robusta.</p>
<p>Quando você cria um novo projeto Go, o primeiro passo é inicializar um módulo. Isso é feito com o comando <code>go mod init</code>, que cria o arquivo <code>go.mod</code>. Este arquivo funciona como um manifesto do seu projeto, similar ao <code>package.json</code> em Node.js ou <code>requirements.txt</code> em Python. O módulo precisa de um nome único, geralmente seguindo a convenção de um caminho de importação (como <code>github.com/seuusuario/seurepositorio</code>).</p>
<pre><code class="language-bash">go mod init github.com/exemplo/meuprojeto</code></pre>
<p>Após executar este comando, você terá um arquivo <code>go.mod</code> semelhante a:</p>
<pre><code class="language-go">module github.com/exemplo/meuprojeto
go 1.21
require (
github.com/google/uuid v1.3.0
)</code></pre>
<p>Este arquivo é fundamental porque documenta exatamente qual versão de cada dependência seu projeto utiliza. O Go também cria um arquivo <code>go.sum</code>, que contém os hashes criptográficos de todas as dependências — isso garante que qualquer outro desenvolvedor ou máquina de CI/CD sempre baixe as mesmas versões verificadas.</p>
<h2>Sistema de Imports e Pacotes</h2>
<p>Em Go, um pacote é a unidade básica de organização de código. Todo arquivo <code>.go</code> pertence a um pacote, declarado na primeira linha não-comentário com <code>package nomedopacote</code>. Pacotes são diretórios, e todos os arquivos em um diretório devem pertencer ao mesmo pacote. Isso é diferente de muitas linguagens onde você pode ter múltiplos módulos em um arquivo.</p>
<p>Quando você quer usar código de outro pacote, você o importa. O sistema de importação em Go é direto: você especifica o caminho do módulo seguido do caminho do pacote. Se você tem um módulo chamado <code>github.com/exemplo/meuprojeto</code> e dentro dele um pacote <code>utils</code>, qualquer outro projeto importaria esse pacote como:</p>
<pre><code class="language-go">import "github.com/exemplo/meuprojeto/utils"</code></pre>
<p>A partir daí, você acessa as funções, tipos e constantes do pacote <code>utils</code> usando a notação ponto. É importante notar que em Go, apenas identificadores que começam com letra maiúscula são exportados (públicos). Isso é uma convenção aplicada rigidamente pelo compilador — não há palavra-chave <code>public</code> ou <code>private</code>.</p>
<pre><code class="language-go">// arquivo: main.go
package main
import (
"fmt"
"github.com/exemplo/meuprojeto/utils"
)
func main() {
resultado := utils.SomarNumeros(5, 3) // SomarNumeros é exportada (maiúscula)
fmt.Println(resultado)
}</code></pre>
<pre><code class="language-go">// arquivo: utils/math.go
package utils
// Exportada (visível para outros pacotes)
func SomarNumeros(a, b int) int {
return a + b
}
// Não exportada (visível apenas dentro do pacote utils)
func validarNumeros(a, b int) bool {
return a > 0 && b > 0
}</code></pre>
<p>Você também pode importar apenas para efeitos colaterais usando <code>_</code>, ou dar um alias a um pacote para evitar conflitos de nome:</p>
<pre><code class="language-go">import (
"database/sql"
_ "github.com/lib/pq" // executa init() mas não usa funções
m "math" // alias para evitar conflito
)</code></pre>
<h2>Organização Prática de Projetos</h2>
<p>A organização de diretórios em um projeto Go segue padrões bem estabelecidos na comunidade. A estrutura típica de um projeto profissional tem diretórios com propósitos específicos: <code>cmd/</code> para aplicações executáveis, <code>pkg/</code> para código reutilizável, <code>internal/</code> para código que não deve ser importado por outros projetos, e <code>test/</code> ou <code>testdata/</code> para testes de integração e dados de teste.</p>
<pre><code>meuapp/
├── go.mod
├── go.sum
├── cmd/
│ ├── meuapp/
│ │ └── main.go
│ └── ferramenta/
│ └── main.go
├── pkg/
│ ├── database/
│ │ ├── db.go
│ │ └── migration.go
│ ├── api/
│ │ ├── handler.go
│ │ └── router.go
│ └── utils/
│ └── validate.go
├── internal/
│ ├── config/
│ │ └── config.go
│ └── service/
│ └── business.go
├── test/
│ └── integration_test.go
└── README.md</code></pre>
<p>O diretório <code>cmd/</code> contém o ponto de entrada das aplicações. Se você constrói múltiplas ferramentas a partir do mesmo código base, cada uma tem seu próprio subdiretório em <code>cmd/</code>. O diretório <code>pkg/</code> contém código que você deseja que outros projetos importem — é seguro desde que você mantenha compatibilidade. Já <code>internal/</code> é especial: Go proíbe que outros módulos importem pacotes dentro de <code>internal/</code>, garantindo que código privado de fato seja privado. Isso é verificado pelo próprio compilador durante <code>go build</code> ou <code>go mod tidy</code>.</p>
<p>Exemplo prático de como importar esses pacotes:</p>
<pre><code class="language-go">// cmd/meuapp/main.go
package main
import (
"fmt"
"meuapp/pkg/database" // importa da própria aplicação
"meuapp/pkg/api"
)
func main() {
db := database.Connect("postgresql://...")
server := api.NewRouter(db)
server.Start(":8080")
}</code></pre>
<pre><code class="language-go">// pkg/api/router.go
package api
import (
"meuapp/internal/config" // OK, mesma aplicação
"meuapp/pkg/database"
)
type Router struct {
db *database.Connection
}
func NewRouter(db database.Connection) Router {
return &Router{db: db}
}</code></pre>
<pre><code class="language-go">// internal/config/config.go
package config
func LoadConfig() map[string]string {
return map[string]string{
"database_url": "postgresql://...",
}
}</code></pre>
<p>Se outro projeto tentasse <code>import "meuapp/internal/config"</code>, Go recusaria com um erro de compilação. Isso protege a arquitetura do seu projeto.</p>
<h2>Gerenciando Dependências com go mod</h2>
<p>O comando <code>go mod tidy</code> é seu melhor amigo. Ele remove dependências não utilizadas e adiciona dependências que faltam. Sempre execute-o antes de fazer commit do seu código — garante que <code>go.mod</code> e <code>go.sum</code> estejam sempre sincronizados com o código.</p>
<pre><code class="language-bash">go mod tidy</code></pre>
<p>Para adicionar uma dependência explicitamente, você usa <code>go get</code>. Este comando baixa a versão especificada e atualiza os arquivos <code>go.mod</code> e <code>go.sum</code>:</p>
<pre><code class="language-bash">go get github.com/gorilla/mux@v1.8.0
go get github.com/lib/pq@latest
go get -u ./... # atualiza todas as dependências diretas</code></pre>
<p>Às vezes você quer entender quais dependências seu projeto tem e por quê. O comando <code>go mod graph</code> mostra o grafo de dependências:</p>
<pre><code class="language-bash">go mod graph</code></pre>
<p>A saída mostra as relações: <code>meuapp github.com/gorilla/mux@v1.8.0</code> significa que seu módulo depende diretamente de <code>mux</code> na versão 1.8.0.</p>
<p>Para verificar se há vulnerabilidades conhecidas em suas dependências:</p>
<pre><code class="language-bash">go list -json -m all | nancy sleuth</code></pre>
<p>(Usando o tool <code>nancy</code>, que você instala com <code>go install github.com/sonatype-nexus-community/nancy@latest</code>)</p>
<p>Um arquivo <code>go.mod</code> bem mantido fica assim:</p>
<pre><code class="language-go">module github.com/exemplo/meuservidor
go 1.21
require (
github.com/gorilla/mux v1.8.0
github.com/lib/pq v1.10.7
)
require (
github.com/stretchr/testify v1.8.0 // indirect
)
retract v0.0.1 // bug crítico encontrado</code></pre>
<p>A seção <code>require</code> lista dependências diretas que seu código importa. A seção <code>indirect</code> mostra dependências que são necessárias por suas dependências diretas — Go as inclui automaticamente quando você executa <code>go mod tidy</code>. A tag <code>retract</code> permite depreciar versões inteiras, útil quando você descobre um bug crítico após publicar.</p>
<p>Quando você trabalha com versões, Go segue versionamento semântico: <code>v1.2.3</code> significa major.minor.patch. Uma dependência pode ser atualizada para patch (<code>1.2.4</code>) e minor (<code>1.3.0</code>) sem quebra esperada, mas major (<code>2.0.0</code>) pode ter breaking changes — você precisa atualizar seu código para usar a nova API.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://golang.org/doc/modules" target="_blank" rel="noopener noreferrer">Go Modules - Official Documentation</a></li>
<li><a href="https://golang.org/doc/effective_go#package-names" target="_blank" rel="noopener noreferrer">Effective Go - Package management</a></li>
<li><a href="https://blog.golang.org/using-go-modules" target="_blank" rel="noopener noreferrer">Using Go Modules - Go Blog</a></li>
<li><a href="https://github.com/go-modules-by-example" target="_blank" rel="noopener noreferrer">Go Modules by Example</a></li>
<li><a href="https://golang.org/ref/spec#Packages" target="_blank" rel="noopener noreferrer">The Go Programming Language Specification</a></li>
</ul>
<p><!-- FIM --></p>