Monorepositório com Go: organização de código na prática
Monorepositório (monorepo) é uma abordagem de gerenciamento de código onde todos os projetos, bibliotecas e serviços são armazenados em um único repositório. Na comunidade Go, essa abordagem está ganhando popularidade devido à sua simplicidade e eficiência. Neste artigo, vamos explorar como organizar um projeto Go em um monorepositório na prática: desde a escolha da estrutura até a configuração de CI/CD.
Por que monorepositório para Go?
Go foi originalmente projetado como uma linguagem para grandes bases de código. Ferramentas como go mod e go work tornam o trabalho com monorepositório natural. As principais vantagens:
- Simplificação de dependências: todos os módulos usam uma versão única de pacotes, sem conflitos de versão.
- CI/CD unificado: um único arquivo de configuração para todos os serviços, mais fácil de manter.
- Refatoração: alterações em uma API de biblioteca refletem imediatamente em todos os consumidores no repositório.
- Padrões unificados: linters, formatadores e code reviews são aplicados a todo o código.
Estrutura do monorepositório: esquema comprovado
Vamos considerar uma estrutura que funciona muito bem para projetos Go de médio porte. Suponha que temos dois serviços: auth-service e api-gateway, além de bibliotecas compartilhadas.
my-project/├── apps/ # Aplicações executáveis│ ├── auth-service/│ │ ├── cmd/│ │ │ └── main.go│ │ ├── internal/│ │ │ ├── handler/│ │ │ ├── service/│ │ │ └── repository/│ │ ├── go.mod│ │ └── go.sum│ └── api-gateway/│ ├── cmd/│ │ └── main.go│ ├── internal/│ │ ├── middleware/│ │ └── routes/│ ├── go.mod│ └── go.sum├── libs/ # Bibliotecas compartilhadas│ ├── config/│ │ ├── config.go│ │ ├── go.mod│ │ └── go.sum│ ├── logger/│ │ ├── logger.go│ │ ├── go.mod│ │ └── go.sum│ └── db/│ ├── postgres.go│ ├── go.mod│ └── go.sum├── scripts/ # Scripts para CI/CD e utilitários│ ├── build.sh│ └── test.sh├── go.work # Go Workspace (opcional)├── .golangci.yml # Configuração do linter├── Makefile # Comandos gerais└── README.mdElementos-chave da estrutura
apps/— todas as aplicações executáveis. Cada aplicação tem seu próprio ponto de entrada (cmd/main.go) e seu própriogo.mod.libs/— bibliotecas de uso geral. Cada biblioteca é um módulo Go separado.scripts/— scripts auxiliares para build, teste e deploy.go.work— arquivo para Go Workspace, simplifica o desenvolvimento local.
Configuração do Go Workspace para desenvolvimento local
Go 1.18+ suporta Workspace através do arquivo go.work. Isso permite referenciar localmente bibliotecas de libs/ sem publicá-las em um repositório remoto.
Crie o go.work na raiz do projeto:
go 1.22
use ( ./apps/auth-service ./apps/api-gateway ./libs/config ./libs/logger ./libs/db)Agora, durante o desenvolvimento, você pode importar as bibliotecas diretamente:
// apps/auth-service/cmd/main.gopackage main
import ( "my-project/libs/config" "my-project/libs/logger")
func main() { cfg := config.Load() log := logger.New(cfg.LogLevel) log.Info("Auth service started")}Nota importante: no go.mod de cada aplicação, a dependência da biblioteca deve apontar para o caminho local usando replace:
// apps/auth-service/go.modmodule github.com/company/my-project/a