Monorepositorio con Go: organización del código en la práctica
Un monorepositorio (monorepo) es un enfoque de gestión de código donde todos los proyectos, bibliotecas y servicios se almacenan en un único repositorio. En la comunidad de Go, este enfoque está ganando popularidad debido a su simplicidad y eficiencia. En este artículo, analizaremos cómo organizar un proyecto Go en un monorepositorio en la práctica: desde la elección de la estructura hasta la configuración de CI/CD.
¿Por qué un monorepositorio para Go?
Go fue diseñado originalmente como un lenguaje para grandes bases de código. Herramientas como go mod y go work hacen que trabajar con un monorepositorio sea natural. Las principales ventajas:
- Simplificación de dependencias: todos los módulos usan una versión única de paquetes, sin conflictos de versiones.
- CI/CD unificado: un solo archivo de configuración para todos los servicios, más fácil de mantener.
- Refactorización: un cambio en la API de una biblioteca se refleja inmediatamente en todos los consumidores del repositorio.
- Estándares unificados: linters, formateadores y code reviews se aplican a todo el código.
Estructura del monorepositorio: esquema probado
Consideremos una estructura que funciona muy bien para proyectos Go de tamaño mediano. Supongamos que tenemos dos servicios: auth-service y api-gateway, además de bibliotecas compartidas.
my-project/├── apps/ # Aplicaciones ejecutables│ ├── 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 compartidas│ ├── 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 y utilidades│ ├── build.sh│ └── test.sh├── go.work # Workspace Go (opcional)├── .golangci.yml # Configuración del linter├── Makefile # Comandos comunes└── README.mdElementos clave de la estructura
apps/— todas las aplicaciones ejecutables. Cada aplicación tiene su propio punto de entrada (cmd/main.go) y su propiogo.mod.libs/— bibliotecas de uso común. Cada biblioteca es un módulo Go independiente.scripts/— scripts auxiliares para compilación, pruebas y despliegue.go.work— archivo para Go Workspace, simplifica el desarrollo local.
Configuración de Go Workspace para desarrollo local
Go 1.18+ admite Workspace a través del archivo go.work. Esto permite referenciar localmente bibliotecas desde libs/ sin necesidad de publicarlas en un repositorio remoto.
Cree go.work en la raíz del proyecto:
go 1.22
use ( ./apps/auth-service ./apps/api-gateway ./libs/config ./libs/logger ./libs/db)Ahora, durante el desarrollo, puede importar las bibliotecas directamente:
// 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: en el go.mod de cada aplicación, la dependencia de la biblioteca debe apuntar a la ruta local mediante replace:
// apps/auth-service/go.modmodule github.com/company/my-project/a