Was macht Go Mastery Skill?
Schreibe produktionsreifes, idiomatisches Go für jeden Zweck. Diese Skill kodiert die kollektive Weisheit des Go-Ökosystems ab Go 1.22+ (2024–2026).
Go-Versionsbasis: 1.22 | Features bis: 1.26 | Aktualisiert: Februar 2026
Bevor du Go-Code schreibst, verinnerliche die folgenden Prinzipien. Für tiefgehende Einblicke zu spezifischen Themen lies die referenzierten Dateien.
Referenzdateien – Nach Bedarf lesen
| Datei | Wann lesen |
|---|---|
references/concurrency.md | Jegliche Goroutinen, Channels, Sync-Primitive oder parallele Arbeit |
references/http-and-apis.md | HTTP-Server, Router, Middleware, REST/gRPC-APIs, WebSockets |
references/database.md | SQL, ORMs, Verbindungspools, Migrationen, Transaktionen |
references/testing.md | Unit-Tests, Integrationstests, Benchmarks, Fuzzing |
references/errors-and-resilience.md | Fehlerbehandlung, Wiederholungen, Circuit Breaker, Graceful Degradation |
references/performance.md | Profiling, Speicherreduzierung, GC-Tuning, Benchmarking |
references/cli-and-config.md | CLI-Frameworks, Konfiguration, Umgebungsverwaltung |
references/project-patterns.md | Projektstruktur, DI, Plugin-Systeme, Code-Generierung |
references/platform-and-build.md | Cross-Kompilierung, Windows-Spezifika, Einbettung, Distribution |
references/security.md | Authentifizierung, Secrets, Eingabevalidierung, TLS, OWASP-Muster |
references/modern-go.md | Go 1.21–1.26 Features, veraltete Muster, was Pre-Training falsch macht |
references/advanced-patterns.md | Generics, Zustandsmaschinen, Streaming, Scheduling, KI/LLM-Integration |
references/advanced-resources.md | Kuratierte externe Ressourcen: Compiler/Runtime-Interna, Assembler, unsafe, cgo, Raft, K8s-Operatoren, Wasm, Kryptographie, Profiling, Bücher, Konferenzen, wissenschaftliche Arbeiten |
references/observability.md | OpenTelemetry-Setup, Tracing, Metriken, strukturiertes Logging mit Trace-Korrelation, Health Checks, Flight Recorder, Produktions-Instrumentierungs-Checkliste |
references/ecosystem-and-tooling.md | Kuratierte Listen (awesome-go), Framework-Vergleiche (Web, ORM, CLI, DI, Config), Styleguides, CI/CD, Docker, Release-Management, Schwachstellenscans, Lernplattformen, Go-Governance |
references/internals.md | GMP-Scheduler, Garbage Collector, Speichermodell, Stack-Management, Speicher-Allokator, Compiler-Pipeline, unsafe, Reflection, Compiler-Direktiven |
references/networking.md | TCP/UDP-Server, net.Conn-Deadlines, Verbindungspooling, mTLS, Unix-Sockets, DNS-Resolver, benutzerdefinierte Binärprotokolle, gnet |
references/mcp-and-agents.md | MCP-Server (mcp-go, offizielles SDK), Tools/Ressourcen/Prompts, Agent-Frameworks (ADK, langchaingo, eino), Multi-Agent-Muster, gopls MCP |
references/api-design.md | REST-Benennung, Paginierung (Cursor/Offset), RFC 9457-Fehler, Ratenbegrenzung, API-Versionierung, OpenAPI-Codegen (oapi-codegen), Abwärtskompatibilität, Deprecation-Header |
references/cgo-and-interop.md | CGo-Grundlagen, C-Typzuordnung, Speicherverwaltung über Grenzen hinweg, Zeigerübergaberegeln, Callbacks, statisches/dynamisches Linken, Cross-Kompilierung, reine Go-Alternativen |
references/design-patterns.md | GoF-Muster in Go (Factory, Builder, Strategy, Observer, Decorator), Komposition über Vererbung, Entscheidungsbaum |
references/distributed-systems.md | Raft, Outbox-Muster, Sagas, verteiltes Sperren, Idempotenz, CRDTs, konsistentes Hashing |
references/cloud-native.md | Kubernetes client-go, controller-runtime-Operatoren, Admission Webhooks, Leader Election, Helm/Kustomize |
references/debugging-and-diagnostics.md | Delve-Debugger, Stack-Traces, GODEBUG-Flags, Profiling-Workflow, Symptom-zu-Diagnose-Tabellen |
references/style-synthesis.md | Zusammengeführte Google + Uber + Community-Stilregeln, Benennung, Formatierung, Code-Organisation |
references/modules-and-dependencies.md | go.mod-Operationen, MVS, Workspaces, GOPROXY, GOAUTH, Vendoring, Multi-Modul-Monorepos |
references/encoding-and-serialization.md | JSON (v1/v2), Protocol Buffers, MessagePack, CBOR, CSV, YAML, TOML, Format-Entscheidungstabelle |
references/wasm-and-embedded.md | WebAssembly (WASI, Browser), go:wasmexport, TinyGo, eingebettete/IoT-Muster |
references/migration-guides.md | Idiomatische Go-Übersetzungen von Python, Java, TypeScript, Rust, C++ – Konzeptkarten und Fallstricke |
references/testing-advanced.md | Property-basiertes Testen (rapid), Vertragstests (Pact), Lasttests (Vegeta), Chaos Engineering, synctest advanced |
references/supply-chain-security.md | govulncheck, SBOM-Generierung, SLSA-Framework, cosign, reproduzierbare Builds, GODEBUG-Kompatibilität |
references/ebpf.md | eBPF aus Go (cilium/ebpf), bpf2go-Workflow, Tracing, Networking, Profiling auf Kernel-Ebene |
references/event-driven.md | Kafka, RabbitMQ, NATS-Consumer/Producer, Watermill-Framework, DLQ, Exactly-Once-Muster |
references/data-structures-and-caching.md | container/heap, container/list, LRU-Caches, singleflight, sharded maps, Bloom-Filter, Weak-Reference-Caches, Cache-Strategie-Muster (aside/write-through/write-behind) |
references/ai-ml-beyond-llm.md | ONNX Runtime-Inferenz, Gonum, Vektor-DB-Clients, Embedding-Pipelines, ML-Serving aus Go |
references/file-io.md | Dateioperationen, io.Reader/Writer-Komposition, gepufferte E/A, Streaming, Pfadverarbeitung, os.Root, fs.FS-Abstraktion, fsnotify |
Kernphilosophie
Go ist bewusst einfach. Widerstehe der Versuchung, Komplexität aus anderen Ökosystemen zu importieren.
- Klarheit vor Cleverness. Code wird 10x häufiger gelesen als geschrieben. Explizit schlägt implizit – zukünftige Maintainer (einschließlich deines zukünftigen Ichs) werden es dir danken.
- Komposition vor Vererbung. Bette Interfaces und Structs ein; vermeide tiefe Hierarchien. Go hat keine Klassen, und das ist beabsichtigt – kleine, komponierbare Teile schlagen komplexe Typbäume.
- Akzeptiere Interfaces, gib Structs zurück. Funktionen sollten von Verhalten (Interfaces) abhängen und konkrete Typen bereitstellen. Dies hält Aufrufstellen flexibel, während Implementierungen auffindbar und debuggbar bleiben.
- Mache den Nullwert nützlich. Entwerfe Typen so, dass
var x Tohne Initialisierung einsatzbereit ist. Dies eliminiert eine ganze Klasse von Nil-Pointer-Bugs und lässt APIs natürlich wirken (bytes.Buffer,sync.Mutex,http.Clientfunktionieren alle mit Nullwert). - Fehler sind Werte. Behandle sie; ignoriere sie nie. Wickle sie mit Kontext ein, indem du
fmt.Errorf("doing X: %w", err)verwendest. Verworfene Fehler werden zu stillen Fehlern, die Stunden später in der Produktion auftauchen. - Starte keine Goroutinen, die du nicht stoppen kannst. Jede Goroutine benötigt einen Shutdown-Pfad durch Context-Cancellation oder Channel-Close. Verwaiste Goroutinen verbrauchen auf unbestimmte Zeit Speicher und machen Graceful Shutdown unmöglich.
- Stdlib zuerst. Gos Standardbibliothek ist ungewöhnlich vollständig. Greife nur dann zu Drittanbieterbibliotheken, wenn die Stdlib wirklich zu kurz greift – weniger Abhängigkeiten bedeuten weniger Sicherheitsaudits, weniger Versionskonflikte und schnellere Builds.
- Code ist nicht fertig, bis er
gofmt-sauber ist, baut und vetted. Führegofmt/goimports,go build,go vet,go test -raceundgolangci-lintaus – mache sie zu CI-Gates; der Race-Detektor findet Bugs, die bei Reviews unsichtbar sind. Wenn du Code ohne Tool-Zugriff ausgibst, halte denselben Standard manuell ein: halte ihn gofmt-formatiert und füge nur die Imports ein, die du tatsächlich verwendest (ein ungenutzter Import ist ein Kompilierfehler – der klassische Fehler direkt nach dem Austausch einer Redewendung gegen eine andere). - Ehre den Vertrag des Aufrufers, dann optimiere. Wenn eine Aufgabe genaue Bezeichner, Signaturen, Ausgabeformat oder Typen vorgibt, reproduziere sie exakt – selbst wenn du sie anders benennen oder strukturieren würdest. Standardmäßig die einfachste korrekte Lösung, die die Spezifikation erfüllt; füge Abstraktion, Indirektion oder defensive Schichten nur hinzu, wenn die Komplexität der Aufgabe es erfordert. Die Übereinstimmung mit der geforderten Oberfläche ist Teil der Korrektheit – unnötige Umbenennungen oder Umstrukturierungen brechen Aufrufer und Tests.
Projektstruktur
Starte einfach. Füge Struktur nur hinzu, wenn das Projekt es erfordert.
Einzelne Binärdatei (CLI oder kleiner Service)
myapp/
├── go.mod
├── main.go # package main, Einstiegspunkt
├── app.go # Kernanwendungslogik
├── app_test.go
└── internal/ # private Pakete nach Bedarf
└── parser/
├── parser.go
└── parser_test.go
Mehrere Binärdateien / Produktionsservice
myproject/
├── go.mod
├── cmd/ # Einstiegspunkte – dünne main()-Funktionen
│ ├── api-server/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # privater Anwendungscode (vom Compiler erzwungen)
│ ├── auth/
│ ├── user/ # Domain-Paket: Handler + Service + Repo
│ │ ├── handler.go
│ │ ├── service.go
│ │ ├── repository.go
│ │ └── model.go
│ ├── platform/ # Querschnittsfunktionen: DB, Cache, Logging
│ │ ├── postgres/
│ │ └── redis/
│ └── middleware/
├── pkg/ # OPTIONAL: öffentlich wiederverwendbare Bibliotheken
├── api/ # OpenAPI-Spezifikationen, Protobuf-Definitionen
├── migrations/ # SQL-Migrationsdateien
├── scripts/ # Build-, Deploy- und Entwicklungs-Tooling
├── configs/ # Standardkonfigurationsdateien
└── Makefile
Wichtige Regeln:
internal/wird vom Go-Compiler erzwungen – Code hier kann nicht von externen Modulen importiert werden.cmd/*/main.gosollte dünn sein: Flags parsen, Abhängigkeiten verdrahten,run()aufrufen, Shutdown handhaben.- Gruppiere nach Domain/Feature, nicht nach technischer Schicht. Vermeide
models/,controllers/,services/– das ist Java-artige Schichtung, die gegen Gos Paketmodell kämpft. - Vermeide
utils/,helpers/,common/-Pakete – benenne Pakete nach dem, was sie bereitstellen, da vage Namen nicht verwandten Code anziehen und Imports bedeutungslos machen. - Ein Verzeichnis IST ein Paket. Erstelle keine Verzeichnisse nur zur Organisation.
Namenskonventionen
// Pakete: kurz, Kleinbuchstaben, ein Wort. Keine Unterstriche oder MixedCaps.
package user // gut
package userService // schlecht – MixedCaps
// Exportiert: MixedCaps. Nicht exportiert: mixedCaps. Unterstriche sind legal, aber
// die Community betrachtet sie als Stilfehler – sie signalisieren nicht-idiomatischen Code.
func ParseRequest() // exportiert
func parseHeader() // nicht exportiert
// Interfaces: Methode + „-er"-Suffix für Ein-Methoden-Interfaces
type Reader interface { Read(p []byte) (n int, err error) }
type Validator interface { Validate() error }
// Getter: Owner(), nicht GetOwner(). Setter: SetOwner().
func (u *User) Name() string // Getter – das „Get"-Präfix ist un-Go
func (u *User) SetName(n string) // Setter
// Akronyme: alles Großbuchstaben. URL, HTTP, ID, API – nicht Url, Http, Id, Api.
type HTTPClient struct{}
var userID int
// Fehlervariablen: ErrXxx. Fehlertypen: XxxError.
var ErrNotFound = errors.New("not found")
type ValidationError struct { Field string; Message string }
// Context: erster Parameter, immer ctx genannt. Dies ist eine universelle Go-Konvention,
// die Context-Weitergabe in jeder Codebasis sofort erkennbar macht.
func (s *Service) GetUser(ctx context.Context, id string) (*User, error)
Fehlerbehandlung
Dies ist Gos markantestes Muster. Meistere es.
// Jeden Fehler prüfen – mit Kontext mit %w umschließen
f, err := os.Open(name)
if err != nil {
return fmt.Errorf("opening config %s: %w", name, err)
}
defer f.Close()
// errors.AsType – generische typisierte Fehlerextraktion [Go 1.26+]
// Bevorzugt gegenüber errors.As: typsicher, keine vorab deklarierte Variable erforderlich.
if pathErr, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("failed at path:", pathErr.Path)
}
Wichtige Regeln:
return errohne Kontext macht Debugging schmerzhaft – umschließe immer mitfmt.Errorf("doing X: %w", err).log.Fatal(err)in Bibliothekscode ruftos.Exit(1)auf und überspringt deferred Cleanup – gib Fehler an Aufrufer zurück.panic()ist für Programmierfehler, nicht für Laufzeitbedingungen – gib stattdessen Fehler zurück.- Umschließe Fehler von Drittanbietern mit
%v(nicht%w), um zu vermeiden, dass Aufrufer an den zugrunde liegenden Fehlertyp gekoppelt werden. - Fehlermeldungsstil: Kleinbuchstaben, keine Satzzeichen:
fmt.Errorf("reading config file: %w", err).
Siehe references/errors-and-resilience.md für Sentinel-Fehler, benutzerdefinierte Fehlertypen, errors.Join, Wiederholungsmuster, Circuit Breaker und Graceful Degradation.
Concurrency-Grundlagen
Siehe references/concurrency.md für umfassende Muster einschließlich errgroup, Worker-Pools und Fan-Out/Fan-In. Kernregeln:
- Verwende Context für Cancellation. Jede Goroutine muss
ctx.Done()prüfen – ohne sie gibt es keine Möglichkeit, „Stoppe Arbeit" zu signalisieren. - Bevorzuge
errgroupgegenüber rohemsync.WaitGroup. Bündelt Wait + Fehlersammlung + Context-Cancellation. Sieheconcurrency.mdfür vollständige Beispiele mitSetLimit. - Schütze gemeinsam genutzten Zustand – Channels für Kommunikation, Mutex, wenn es einfacher ist. Kommentiere, was jeder Mutex schützt.
- Jede Goroutine braucht einen Shutdown-Pfad. Keine Cancellation-Prüfung = verwaiste Goroutine = Speicherleck.
- Ein Panic in einer Goroutine killt den gesamten Prozess. Recover in gestarteten Goroutinen oder verwende
sourcegraph/conc.
Neuartige Sync-Primitive:
sync.OnceValue / sync.OnceValues [Go 1.21+] – typsichere Lazy-Initialisierung als Ersatz für sync.Once + Paketvariable:
var loadConfig = sync.OnceValues(func() ([]byte, error) {
return os.ReadFile("config.json") // läuft genau einmal, sicher von jeder Goroutine
})
data, err := loadConfig() // nachfolgende Aufrufe geben das gecachte Ergebnis zurück
sync.WaitGroup.Go [Go 1.25+] – kombiniert Add(1) + go func + Done():
var wg sync.WaitGroup
wg.Go(func() { process(1) })
wg.Go(func() { process(2) })
wg.Wait()
Channel-Größenbestimmung: ungepuffert (0) für Synchronisation, gepuffert (1) für Signale, gepuffert (N) für bekannte begrenzte Arbeit.
Interfaces
// Akzeptiere Interfaces, gib konkrete Typen zurück
type UserStore interface {
GetUser(ctx context.Context, id string) (*User, error)
}
func NewService(store UserStore) *Service { return &Service{store: store} }
// Halte Interfaces klein – 1-3 Methoden. Baue größere aus kleinen zusammen.
type ReadWriter interface { Reader; Writer }
// Definiere Interfaces dort, wo sie verwendet werden, nicht dort, wo sie implementiert werden.
// Ein Paket userservice, das ein Interface definiert, das das Paypal-Paket implementieren muss,
// erzeugt einen unnötigen Import-Zyklus.
// Leere Interfaces (interface{}) sind ein letzter Ausweg. Verwende sie nicht für Parameter,
// die jeden Typ akzeptieren – das untergräbt die Typsicherheit von Go.
Standardbibliothek zuerst
// HTTP-Server ohne Framework
mux := http.NewServeMux()
mux.HandleFunc("GET /api/users/{id}", handler)
http.ListenAndServe(":8080", mux)
// JSON-Encoding/Decoding – keine externe Bibliothek erforderlich
type User struct { Name string `json:"name"` }
json.NewEncoder(w).Encode(user)
Das net/http-Paket von Go 1.22+ unterstützt Methoden-Matching, Pfadvariablen und Middleware-Chaining – für viele Dienste ist kein Drittanbieter-Router mehr erforderlich. Greife zu chi, gin oder echo, wenn du fortgeschrittene Middleware-Ökosysteme oder Nicht-Standard-Routing-Muster benötigst.
Tests schreiben
// Tabellegetriebene Tests mit Sub-Tests
func TestParseUser(t *testing.T) {
tests := []struct {
name string
input string
want User
wantErr bool
}{
{"valid", `{"name":"Alice"}`, User{Name: "Alice"}, false},
{"invalid json", `{bad`, User{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseUser(strings.NewReader(tt.input))
if (err != nil) != tt.wantErr {
t.Fatalf("ParseUser() error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseUser() = %v, want %v", got, tt.want)
}
})
}
}
// Race-Bedingung in Tests erkennen: go test -race ./...
// Dies ist eine CI-Pflicht – der Race-Detektor hat eine nachgewiesene Erfolgsbilanz
// beim Auffinden von Datenrennen, die Code-Reviews übersehen.
Wichtige Regeln:
testing.Tist Wert, kein Zeiger – verwende*testing.T.- Verwende
t.Helper(), um Helferfunktionen als Testhelfer zu markieren – dies verbessert die Fehlerberichterstattung, indem Helfer aus dem Stack-Trace entfernt werden. - Bevorzuge
cmpoptsodergo-cmpfür Deep-Equal-Vergleiche, die keine Export-Felder benötigen. t.Cleanup()für Ressourcenbereinigung – idiomatischer alsdeferin Tests und funktioniert korrekt mit Sub-Tests.
Siehe references/testing.md für Integrationstests, Benchmarks und Fuzzing.
So verwendest du diese Referenzdateien
Jede Datei in references/ enthält:
- Eine klare Problemerkennung – wann dieses Muster anwenden
- Codebeispiele – komplett, ausführbar, mustergültig
- Anti-Patterns – was nicht zu tun ist
- Prüflisten – Woran du denken musst, bevor du PR sendest
- Begründung – Warum dieser Ansatz der richtige für Go ist
Für ein neues Projekt: Lies die Referenz zur Projektstruktur einmal, dann lies nach Bedarf. Mit der Zeit wirst du die Inhalte verinnerlichen und die Referenzen nur noch für ungewohnte Probleme konsultieren.