Organizando Pacotes e Módulos em Go

Rafik Moreira -
23 de maio de 2026

Organizando Pacotes e Módulos em Go: Guia Completo

Um dos maiores desafios ao começar um projeto em Go é decidir como organizar o código. Diferente de outras linguagens que impõem convenções estritas, Go oferece flexibilidade e, com isso, a responsabilidade de fazer escolhas conscientes.

Este guia explora as melhores práticas oficiais do Go para nomenclatura e organização de pacotes, aplicando-as a um exemplo prático de sistema de gerenciamento de tarefas.

Por que a organização importa?

Um projeto bem estruturado traz benefícios imediatos:

  • Clareza: outros desenvolvedores (e você mesmo no futuro) entendem rapidamente onde encontrar cada funcionalidade
  • Manutenibilidade: mudanças e refatorações ficam mais seguras e previsíveis
  • Reutilização: código bem organizado é mais fácil de compartilhar entre projetos
  • Performance de build: estrutura adequada evita dependências circulares e compilações lentas

Estes benefícios se acumulam ao longo do tempo, tornando a organização inicial um investimento que compensa no futuro.

Fundamentos: Pacotes e Módulos

Antes de mergulharmos na estrutura, é importante entender dois conceitos:

Pacote (Package)

Um pacote é uma coleção de arquivos Go no mesmo diretório que declaram o mesmo nome de pacote. Representa a unidade básica de organização de código em Go.

package users

Módulo (Module)

Um módulo é uma coleção de pacotes relacionados versionados juntos. É definido por um arquivo go.mod na raiz do projeto.

module github.com/rafikmoreira/account-manager

go 1.26

Princípios de Nomenclatura

1. Nomes de pacotes devem ser curtos e claros

Segundo a documentação oficial do Go, bons nomes de pacotes são minúsculos, sem underscores ou mixedCaps. Devem ser substantivos simples que descrevem claramente o conteúdo do pacote.

Evite:

package taskServiceClient
package priority_queue
package util
package common

Prefira:

package task
package category
package auth
package notification

2. Evite repetição entre pacote e conteúdo

Como o código cliente sempre usa o nome do pacote como prefixo ao referenciar tipos e funções exportadas, não repita informações desnecessariamente.

Evite:

package task

type TaskManager struct {}
func NewTaskManager() *TaskManager {}

Prefira:

package task

type Manager struct {}
func NewManager() *Manager {}

O código cliente fica mais conciso e idiomático:

manager := task.NewManager()

Em vez de task.TaskManager, o cliente usa apenas task.Manager, evitando redundância.

3. Use abreviações com moderação

Abreviações são aceitáveis quando amplamente conhecidas e reconhecidas pela comunidade Go. A biblioteca padrão oferece exemplos de abreviações bem estabelecidas:

Bons exemplos:

  • strconv (string conversion)
  • fmt (formatted I/O)
  • http (HyperText Transfer Protocol)
  • syscall (system call)

Evite abreviações obscuras:

  • usrmgmt (user management)
  • acctsvc (account service)

Se a abreviação tornar o nome ambíguo ou pouco claro, use o nome completo.

Estruturas Comuns de Projetos

A seguir, exploramos diferentes padrões de organização, do mais simples ao mais complexo.

Pacote Básico

Para projetos simples, todo o código pode ficar na raiz:

taskman/
  go.mod
  task.go
  task_test.go
  filter.go
  filter_test.go
module github.com/rafikmoreira/taskman

Arquivo task.go:

package task

type Task struct {
    ID          string
    Title       string
    Description string
    Completed   bool
}

Usuários importam com:

import "github.com/rafikmoreira/taskman"

Projeto com Pacotes de Suporte

Quando o projeto cresce, use o diretório internal/ para pacotes auxiliares que você não quer expor publicamente:

taskman/
  go.mod
  task.go
  task_test.go
  internal/
    validation/
      validation.go
      validation_test.go
    storage/
      sqlite.go
      sqlite_test.go

O diretório internal/ possui uma propriedade especial: código dentro dele não pode ser importado por outros módulos. Esta funcionalidade, implementada pelo comando go, permite manter APIs privadas. Use internal/ para implementações que podem mudar sem aviso prévio, protegendo dependências externas de quebras.

Múltiplos Pacotes Exportáveis

Para bibliotecas que oferecem múltiplas funcionalidades relacionadas:

taskman/
  go.mod
  task.go
  task_test.go
  category/
    category.go
    category_test.go
  label/
    label.go
    label_test.go
  priority/
    priority.go
    priority_test.go
  internal/
    audit/
      audit.go

Usuários podem importar especificamente o que precisam:

import "github.com/rafikmoreira/taskman"
import "github.com/rafikmoreira/taskman/category"
import "github.com/rafikmoreira/taskman/label"
import "github.com/rafikmoreira/taskman/priority"

Exemplo Completo: Sistema de Gerenciamento de Tarefas

Vamos projetar um sistema completo de gerenciamento de tarefas, aplicando todas as práticas que vimos.

Requisitos do Sistema

  • Criar e gerenciar tarefas com título, descrição e status
  • Organizar tarefas por categorias e etiquetas
  • Definir prioridades e prazos
  • Filtrar e buscar tarefas
  • Enviar notificações de lembretes
  • Gerar relatórios de produtividade
  • API REST e CLI para acesso

Estrutura Proposta

taskman/
  go.mod
  README.md
  
  cmd/
    api-server/
      main.go
    cli/
      main.go
  
  internal/
    server/
      server.go
      routes.go
      middleware.go
    storage/
      sqlite.go
      migrations/
    config/
      config.go
  
  pkg/
    task/
      task.go
      task_test.go
      repository.go
    category/
      category.go
      category_test.go
      repository.go
    label/
      label.go
      label_test.go
    priority/
      priority.go
      priority_test.go
    notification/
      email.go
      notification.go
      notification_test.go
    report/
      report.go
      generator.go

Detalhamento dos Diretórios

Diretório cmd/

O diretório cmd/ contém os pontos de entrada da aplicação. Cada subdiretório representa um programa executável diferente.

Instalação pelo usuário:

go install github.com/rafikmoreira/taskman/cmd/api-server@latest
go install github.com/rafikmoreira/taskman/cmd/cli@latest

Diretório internal/

Contém implementações específicas do projeto que não devem ser reutilizadas por módulos externos.

Diretório pkg/ (Opcional)

Contém lógica de negócio que pode ser importada por outros projetos. Este diretório é opcional e não faz parte das convenções oficiais do Go.

Segundo a documentação oficial, pacotes exportáveis podem estar diretamente na raiz do módulo ou em subdiretórios. O uso de pkg/ é uma convenção adotada por alguns projetos grandes (como Kubernetes) para tornar explícito que o código é público, diferenciando-o de cmd/ e internal/. Projetos menores geralmente não necessitam desta camada adicional.

Erros Comuns e Como Evitá-los

Pacotes "Utilitários" Genéricos

Segundo a documentação oficial, pacotes nomeados como util, common ou misc são problemáticos porque não fornecem nenhuma indicação sobre o conteúdo.

Solução: Agrupe funcionalidades relacionadas em pacotes bem nomeados. Em vez de um pacote utils, crie pacotes específicos como stringset, auth e validation.

Pacotes Monolíticos de API

Colocar todas as interfaces em um único pacote (geralmente chamado api, types ou interfaces) é outro erro comum. Esses pacotes sofrem dos mesmos problemas que util, crescendo sem limites e acumulando dependências desnecessárias.

Solução: Separe em pacotes por contexto de domínio. Em vez de um único pacote api, crie pacotes específicos como task, category e label.

Dependências Circulares

Dependências circulares entre pacotes são proibidas em Go e resultam em erros de compilação.

task/ → category/ → task/  (não compila)

Solução: Extraia interfaces comuns ou reorganize as dependências para eliminar o ciclo.

Lógica Concentrada no Pacote Main

Concentrar toda a lógica da aplicação no pacote main dificulta testes e reutilização.

Solução: Extraia a lógica para pacotes apropriados. O pacote main deve servir apenas como ponto de entrada, orquestrando chamadas aos demais pacotes.

Diretrizes de Layout por Tipo de Projeto

Biblioteca Pura

Código para ser importado por outros projetos. Use a raiz para o pacote principal:

mylib/
  go.mod
  mylib.go
  mylib_test.go
  feature1/
    feature1.go
    feature1_test.go
  feature2/
    feature2.go
  internal/
    helpers/

Este layout é apropriado para projetos focados em fornecer funcionalidades reutilizáveis como bibliotecas.

Aplicação CLI

Para ferramentas de linha de comando, a lógica deve estar em internal/ e o executável em cmd/:

mytool/
  go.mod
  cmd/
    mytool/
      main.go
  internal/
    cli/
      commands.go
      flags.go
    processor/
      processor.go

Este layout é apropriado para ferramentas que não exportam pacotes para uso externo, apenas executáveis.

Servidor/API

Para projetos com servidor e lógica de negócio:

myserver/
  go.mod
  cmd/
    server/
      main.go
  internal/
    server/
      server.go
      routes.go
    database/
      postgres.go
  pkg/
    domain1/
      domain1.go
    domain2/
      domain2.go

Este layout é apropriado quando o servidor pode compartilhar lógica de domínio com outros projetos. Caso contrário, mantenha toda a lógica em internal/.

Projeto Misto

Para bibliotecas que também fornecem ferramentas auxiliares:

myproject/
  go.mod
  core.go
  core_test.go
  feature/
    feature.go
  cmd/
    tool1/
      main.go
    tool2/
      main.go
  internal/
    shared/

Este layout é apropriado quando uma biblioteca fornece comandos úteis para os usuários além da funcionalidade de importação.

Quando Migrar Entre Estruturas

Conforme o projeto evolui, pode ser necessário reestruturá-lo. Sinais comuns de que é hora de reorganizar:

De Raiz para internal/

Quando o código cresce mas não há intenção de expor pacotes publicamente, mova-os para internal/.

Antes:
project/
  go.mod
  handler.go
  database.go

Depois:
project/
  go.mod
  internal/
    handler/
    database/

De internal/ para Pacotes Exportáveis

Quando outros projetos precisam reutilizar código que está em internal/, mova-o para a raiz do módulo ou para um subdiretório apropriado.

Antes:
internal/
  auth/

Depois:
pkg/
  auth/

Adicionar cmd/

Quando há necessidade de múltiplos executáveis ou quando se deseja separar biblioteca de ferramentas CLI, adicione o diretório cmd/.

Antes:
project/
  main.go
  pkg/

Depois:
project/
  cmd/
    server/
      main.go
    cli/
      main.go
  pkg/

Checklist de Boas Práticas

Ao organizar um projeto Go, verifique os seguintes aspectos:

Nomenclatura

  • Os nomes dos pacotes são substantivos simples e descritivos?
  • Evitei nomes genéricos como util, common, helpers?
  • O nome do pacote não se repete nos tipos/funções exportados?
  • Abreviações usadas são amplamente conhecidas?

Estrutura

  • Código privado está em internal/?
  • Cada pacote tem uma responsabilidade clara e única?
  • Comandos executáveis estão em cmd/?
  • O go.mod está na raiz do projeto?
  • Não há dependências circulares?

Testabilidade

  • A estrutura facilita testes?
  • Testes estão junto aos arquivos (*_test.go)?
  • Interfaces permitem mocking de dependências?

Documentação

  • Há um README.md explicando o projeto?
  • Pacotes principais têm comentários de documentação?
  • Exemplos de uso estão claros?

Conclusão

Organizar bem um projeto Go requer combinar as convenções da comunidade com as necessidades específicas do domínio. As diretrizes apresentadas são baseadas na documentação oficial e na experiência coletiva da comunidade Go.

Princípios fundamentais:

  1. Comece simples: evite criar estruturas complexas prematuramente. Adicione diretórios conforme surgir a necessidade real.
  2. Use internal/ generosamente: exponha apenas o que será suportado publicamente. Mantenha implementações internas privadas.
  3. Nomes são importantes: invista tempo escolhendo bons nomes de pacotes. Nomes claros tornam o código auto-explicativo.
  4. Refatore quando necessário: a estrutura deve evoluir com o projeto. Reorganize quando a estrutura atual não atender mais as necessidades.
  5. Aprenda com a comunidade: observe projetos Go estabelecidos e a biblioteca padrão para absorver padrões comprovados.

Seguir essas práticas resulta em código mais idiomático, manutenível e alinhado com as expectativas da comunidade Go.

Próximos passos:

  • Estude o código-fonte da biblioteca padrão do Go
  • Analise projetos open source estabelecidos em Go no GitHub
  • Refatore projetos existentes aplicando essas diretrizes
  • Participe de revisões de código com foco em estrutura e organização

Referências e Leituras Complementares

Documentação Oficial

Recursos da Comunidade

A biblioteca padrão do Go serve como excelente referência prática. Explore os pacotes em pkg.go.dev/std para ver exemplos de organização aplicada em código de produção.