Monorepository mit Go: Code-Organisation in der Praxis
Ein Monorepository (Monorepo) ist ein Ansatz zur Codeverwaltung, bei dem alle Projekte, Bibliotheken und Dienste in einem einzigen Repository gespeichert werden. In der Go-Community gewinnt dieser Ansatz aufgrund seiner Einfachheit und Effizienz an Popularität. In diesem Artikel werden wir praktisch erläutern, wie man ein Go-Projekt in einem Monorepository organisiert: von der Strukturwahl bis zur CI/CD-Konfiguration.
Warum ein Monorepository für Go?
Go wurde ursprünglich als Sprache für große Codebasen konzipiert. Werkzeuge wie go mod und go work machen die Arbeit mit einem Monorepository natürlich. Die Hauptvorteile sind:
- Vereinfachung von Abhängigkeiten: Alle Module verwenden eine einheitliche Paketversion, es gibt keine Versionskonflikte.
- Einheitliches CI/CD: Eine Konfigurationsdatei für alle Dienste, einfacher zu warten.
- Refactoring: Eine API-Änderung in einer Bibliothek wirkt sich sofort auf alle Nutzer im Repository aus.
- Einheitliche Standards: Linter, Formatierer und Code-Reviews werden auf den gesamten Code angewendet.
Monorepository-Struktur: Ein bewährtes Schema
Betrachten wir eine Struktur, die für Go-Projekte mittlerer Größe hervorragend funktioniert. Nehmen wir an, wir haben zwei Dienste: auth-service und api-gateway, sowie gemeinsame Bibliotheken.
my-project/├── apps/ # Ausführbare Anwendungen│ ├── 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/ # Gemeinsame Bibliotheken│ ├── config/│ │ ├── config.go│ │ ├── go.mod│ │ └── go.sum│ ├── logger/│ │ ├── logger.go│ │ ├── go.mod│ │ └── go.sum│ └── db/│ ├── postgres.go│ ├── go.mod│ └── go.sum├── scripts/ # Skripte für CI/CD und Hilfsprogramme│ ├── build.sh│ └── test.sh├── go.work # Go Workspace (optional)├── .golangci.yml # Linter-Konfiguration├── Makefile # Allgemeine Befehle└── README.mdSchlüsselelemente der Struktur
apps/— alle ausführbaren Anwendungen. Jede Anwendung hat ihren eigenen Einstiegspunkt (cmd/main.go) und ein eigenesgo.mod.libs/— gemeinsam genutzte Bibliotheken. Jede Bibliothek ist ein separates Go-Modul.scripts/— Hilfsskripte für Build, Tests und Deployment.go.work— Datei für Go Workspace, vereinfacht die lokale Entwicklung.
Einrichtung des Go Workspace für die lokale Entwicklung
Go 1.18+ unterstützt Workspace über die Datei go.work. Dies ermöglicht es, lokal auf Bibliotheken aus libs/ zu verweisen, ohne sie in ein entferntes Repository veröffentlichen zu müssen.
Erstellen Sie go.work im Projektstammverzeichnis:
go 1.22
use ( ./apps/auth-service ./apps/api-gateway ./libs/config ./libs/logger ./libs/db)Jetzt können Sie während der Entwicklung Bibliotheken direkt importieren:
// 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")}Wichtiger Hinweis: In der go.mod jeder Anwendung muss die Abhängigkeit von der Bibliothek über replace auf den lokalen Pfad verweisen:
// apps/auth-service/go.modmodule github.com/company/my-project/a