Monorepositorio con Go: organización de código en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

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.md


Elementos clave de la estructura



  • apps/ — todas las aplicaciones ejecutables. Cada aplicación tiene su propio punto de entrada (cmd/main.go) y su propio go.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                

Blogs

Book Recommendations