Communitygithub.com

golang-patterns

Idiomatische Go-Muster, Best Practices und Konventionen für den Bau robuster, effizienter und wartbarer Go-Anwendungen. Verwenden Sie diese bei der Erstellung oder Überprüfung von Go-Code, wenn idiomatische Strukturen oder Konventionen in Frage stehen.

Was ist golang-patterns?

Diese Skill-Richtlinie bietet eine umfassende Referenz idiomatischer Go-Entwicklungsmuster und Best Practices. Sie deckt Kernprinzipien wie Einfachheit, nützliche Nullwerte und die Annahme von Schnittstellen bei gleichzeitiger Rückgabe von Strukturen ab. Die Anleitung behandelt wichtige Bereiche wie Fehlerbehandlung (einschließlich Fehlerverpackung mit Kontext, benutzerdefinierten Fehlertypen und Verwendung von `errors.Is`/`errors.As`), Parallelitätsmuster (Worker-Pools, Kontext für Zeitüberschreitungen, ordnungsgemäßes Herunterfahren und `errgroup`) sowie Schnittstellendesign mit kleinen, fokussierten Schnittstellen. Sie ist in erster Linie für KI-Agenten wie Claude Code, Cursor oder Codex konzipiert und kann während der Code-Erstellung, -Überprüfung oder -Umgestaltung aktiviert werden. Sie enthält klare Codebeispiele, die gute und schlechte Praktiken gegenüberstellen, sowie praktische Abschnitte zur Paketorganisation, Strukturdesign, Speicher- und Leistungsoptimierung und Go-Tooling-Integration (z. B. `golangci-lint`, `go vet`). Die Anleitung betont die Lesbarkeit und Wartbarkeit und enthält eine Kurzreferenz gängiger Redewendungen und eine Liste von Anti-Patterns, die vermieden werden sollten.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/golang-patterns

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Go-Entwicklungsmuster

Idiomatische Go-Muster und Best Practices für den Bau robuster, effizienter und wartbarer Anwendungen.

Wann zu aktivieren

  • Schreiben von neuem Go-Code
  • Überprüfen von Go-Code
  • Umgestalten von vorhandenem Go-Code
  • Entwerfen von Go-Paketen/-Modulen

Kernprinzipien

1. Einfachheit und Klarheit

Go bevorzugt Einfachheit gegenüber Raffinesse. Code sollte offensichtlich und leicht lesbar sein.

// Gut: Klar und direkt
func GetUser(id string) (*User, error) {
    user, err := db.FindUser(id)
    if err != nil {
        return nil, fmt.Errorf("get user %s: %w", id, err)
    }
    return user, nil
}

// Schlecht: Übermäßig raffiniert
func GetUser(id string) (*User, error) {
    return func() (*User, error) {
        if u, e := db.FindUser(id); e == nil {
            return u, nil
        } else {
            return nil, e
        }
    }()
}

2. Den Nullwert nützlich machen

Entwerfen Sie Typen so, dass ihr Nullwert ohne Initialisierung sofort verwendbar ist.

// Gut: Nullwert ist nützlich
type Counter struct {
    mu    sync.Mutex
    count int // Nullwert ist 0, bereit zur Verwendung
}

func (c *Counter) Inc() {
    c.mu.Lock()
    c.count++
    c.mu.Unlock()
}

// Gut: bytes.Buffer funktioniert mit Nullwert
var buf bytes.Buffer
buf.WriteString("hello")

// Schlecht: Erfordert Initialisierung
type BadCounter struct {
    counts map[string]int // nil-Map führt zu Panik
}

3. Schnittstellen akzeptieren, Strukturen zurückgeben

Funktionen sollten Schnittstellenparameter akzeptieren und konkrete Typen zurückgeben.

// Gut: Akzeptiert Schnittstelle, gibt konkreten Typ zurück
func ProcessData(r io.Reader) (*Result, error) {
    data, err := io.ReadAll(r)
    if err != nil {
        return nil, err
    }
    return &Result{Data: data}, nil
}

// Schlecht: Gibt Schnittstelle zurück (verbirgt Implementierungsdetails unnötig)
func ProcessData(r io.Reader) (io.Reader, error) {
    // ...
}

Fehlerbehandlungsmuster

Fehlerverpackung mit Kontext

// Gut: Fehler mit Kontext verpacken
func LoadConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("load config %s: %w", path, err)
    }

    var cfg Config
    if err := json.Unmarshal(data, &cfg); err != nil {
        return nil, fmt.Errorf("parse config %s: %w", path, err)
    }

    return &cfg, nil
}

Benutzerdefinierte Fehlertypen

// Domänenspezifische Fehler definieren
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}

// Sentinel-Fehler für häufige Fälle
var (
    ErrNotFound     = errors.New("resource not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrInvalidInput = errors.New("invalid input")
)

Fehlerprüfung mit errors.Is und errors.As

func HandleError(err error) {
    // Auf bestimmten Fehler prüfen
    if errors.Is(err, sql.ErrNoRows) {
        log.Println("No records found")
        return
    }

    // Auf Fehlertyp prüfen
    var validationErr *ValidationError
    if errors.As(err, &validationErr) {
        log.Printf("Validation error on field %s: %s",
            validationErr.Field, validationErr.Message)
        return
    }

    // Unbekannter Fehler
    log.Printf("Unexpected error: %v", err)
}

Fehler niemals ignorieren

// Schlecht: Fehler mit leerem Bezeichner ignorieren
result, _ := doSomething()

// Gut: Behandeln oder explizit dokumentieren, warum es sicher ist, zu ignorieren
result, err := doSomething()
if err != nil {
    return err
}

// Akzeptabel: Wenn der Fehler wirklich keine Rolle spielt (selten)
_ = writer.Close() // Best-Effort-Bereinigung, Fehler wird anderweitig protokolliert

Parallelitätsmuster

Worker-Pool

func WorkerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {
    var wg sync.WaitGroup

    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobs {
                results <- process(job)
            }
        }()
    }

    wg.Wait()
    close(results)
}

Kontext für Abbruch und Zeitüberschreitungen

func FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {
    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return nil, fmt.Errorf("create request: %w", err)
    }

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, fmt.Errorf("fetch %s: %w", url, err)
    }
    defer resp.Body.Close()

    return io.ReadAll(resp.Body)
}

Ordentliches Herunterfahren

func GracefulShutdown(server *http.Server) {
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

    <-quit
    log.Println("Shutting down server...")

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := server.Shutdown(ctx); err != nil {
        log.Fatalf("Server forced to shutdown: %v", err)
    }

    log.Println("Server exited")
}

errgroup für koordinierte Goroutinen

import "golang.org/x/sync/errgroup"

func FetchAll(ctx context.Context, urls []string) ([][]byte, error) {
    g, ctx := errgroup.WithContext(ctx)
    results := make([][]byte, len(urls))

    for i, url := range urls {
        i, url := i, url // Schleifenvariablen erfassen
        g.Go(func() error {
            data, err := FetchWithTimeout(ctx, url)
            if err != nil {
                return err
            }
            results[i] = data
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        return nil, err
    }
    return results, nil
}

Goroutine-Leaks vermeiden

// Schlecht: Goroutine-Leak, wenn Kontext abgebrochen wird
func leakyFetch(ctx context.Context, url string) <-chan []byte {
    ch := make(chan []byte)
    go func() {
        data, _ := fetch(url)
        ch <- data // Blockiert für immer, wenn kein Empfänger
    }()
    return ch
}

// Gut: Behandelt Abbruch ordnungsgemäß
func safeFetch(ctx context.Context, url string) <-chan []byte {
    ch := make(chan []byte, 1) // Gepufferter Kanal
    go func() {
        data, err := fetch(url)
        if err != nil {
            return
        }
        select {
        case ch <- data:
        case <-ctx.Done():
        }
    }()
    return ch
}

Schnittstellendesign

Kleine, fokussierte Schnittstellen

// Gut: Ein-Methoden-Schnittstellen
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

// Schnittstellen nach Bedarf zusammensetzen
type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

Schnittstellen dort definieren, wo sie verwendet werden

// Im Consumer-Paket, nicht im Provider-Paket
package service

// UserStore definiert, was dieser Service benötigt
type UserStore interface {
    GetUser(id string) (*User, error)
    SaveUser(user *User) error
}

type Service struct {
    store UserStore
}

// Konkrete Implementierung kann in einem anderen Paket sein
// Sie muss nichts über diese Schnittstelle wissen

Optionales Verhalten mit Typbehauptungen

type Flusher interface {
    Flush() error
}

func WriteAndFlush(w io.Writer, data []byte) error {
    if _, err := w.Write(data); err != nil {
        return err
    }

    // Flush, wenn unterstützt
    if f, ok := w.(Flusher); ok {
        return f.Flush()
    }
    return nil
}

Paketorganisation

Standard-Projektlayout

myproject/
├── cmd/
│   └── myapp/
│       └── main.go           # Einstiegspunkt
├── internal/
│   ├── handler/              # HTTP-Handler
│   ├── service/              # Geschäftslogik
│   ├── repository/           # Datenzugriff
│   └── config/               # Konfiguration
├── pkg/
│   └── client/               # Öffentlicher API-Client
├── api/
│   └── v1/                   # API-Definitionen (proto, OpenAPI)
├── testdata/                 # Test-Fixtures
├── go.mod
├── go.sum
└── Makefile

Paketbenennung

// Gut: Kurz, Kleinbuchstaben, keine Unterstriche
package http
package json
package user

// Schlecht: Ausführlich, gemischte Groß-/Kleinschreibung oder redundant
package httpHandler
package json_parser
package userService // Redundantes 'Service'-Suffix

Paketweiten Zustand vermeiden

// Schlecht: Globaler veränderlicher Zustand
var db *sql.DB

func init() {
    db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
}

// Gut: Abhängigkeitsinjektion
type Server struct {
    db *sql.DB
}

func NewServer(db *sql.DB) *Server {
    return &Server{db: db}
}

Strukturdesign

Functional Options Pattern

type Server struct {
    addr    string
    timeout time.Duration
    logger  *log.Logger
}

type Option func(*Server)

func WithTimeout(d time.Duration) Option {
    return func(s *Server) {
        s.timeout = d
    }
}

func WithLogger(l *log.Logger) Option {
    return func(s *Server) {
        s.logger = l
    }
}

func NewServer(addr string, opts ...Option) *Server {
    s := &Server{
        addr:    addr,
        timeout: 30 * time.Second, // Standard
        logger:  log.Default(),    // Standard
    }
    for _, opt := range opts {
        opt(s)
    }
    return s
}

// Verwendung
server := NewServer(":8080",
    WithTimeout(60*time.Second),
    WithLogger(customLogger),
)

Einbettung für Komposition

type Logger struct {
    prefix string
}

func (l *Logger) Log(msg string) {
    fmt.Printf("[%s] %s\n", l.prefix, msg)
}

type Server struct {
    *Logger // Einbettung - Server erhält Log-Methode
    addr    string
}

func NewServer(addr string) *Server {
    return &Server{
        Logger: &Logger{prefix: "SERVER"},
        addr:   addr,
    }
}

// Verwendung
s := NewServer(":8080")
s.Log("Starting...") // Ruft die eingebettete Logger.Log auf

Speicher und Leistung

Slices vorab zuweisen, wenn die Größe bekannt ist

// Schlecht: Wächst Slice mehrfach
func processItems(items []Item) []Result {
    var results []Result
    for _, item := range items {
        results = append(results, process(item))
    }
    return results
}

// Gut: Einzelne Allokation
func processItems(items []Item) []Result {
    results := make([]Result, 0, len(items))
    for _, item := range items {
        results = append(results, process(item))
    }
    return results
}

sync.Pool für häufige Allokationen verwenden

var bufferPool = sync.Pool{
    New: func() interface{} {
        return new(bytes.Buffer)
    },
}

func ProcessRequest(data []byte) []byte {
    buf := bufferPool.Get().(*bytes.Buffer)
    defer func() {
        buf.Reset()
        bufferPool.Put(buf)
    }()

    buf.Write(data)
    // Verarbeiten...
    return buf.Bytes()
}

Zeichenkettenverkettung in Schleifen vermeiden

// Schlecht: Erzeugt viele Zeichenketten-Allokationen
func join(parts []string) string {
    var result string
    for _, p := range parts {
        result += p + ","
    }
    return result
}

// Gut: Einzelne Allokation mit strings.Builder
func join(parts []string) string {
    var sb strings.Builder
    for i, p := range parts {
        if i > 0 {
            sb.WriteString(",")
        }
        sb.WriteString(p)
    }
    return sb.String()
}

// Am besten: Standardbibliothek verwenden
func join(parts []string) string {
    return strings.Join(parts, ",")
}

Go-Tooling-Integration

Grundlegende Befehle

# Bauen und ausführen
go build ./...
go run ./cmd/myapp

# Testen
go test ./...
go test -race ./...
go test -cover ./...

# Statische Analyse
go vet ./...
staticcheck ./...
golangci-lint run

# Modulverwaltung
go mod tidy
go mod verify

# Formatierung
gofmt -w .
goimports -w .

Empfohlene Linter-Konfiguration (.golangci.yml)

linters:
  enable:
    - errcheck
    - gosimple
    - govet
    - ineffassign
    - staticcheck
    - unused
    - gofmt
    - goimports
    - misspell
    - unconvert
    - unparam

linters-settings:
  errcheck:
    check-type-assertions: true
  govet:
    enable:
      - shadow

issues:
  exclude-use-default: false

Kurzreferenz: Go-Redewendungen

RedewendungBeschreibung
Schnittstellen akzeptieren, Strukturen zurückgebenFunktionen akzeptieren Schnittstellenparameter, geben konkrete Typen zurück
Fehler sind WerteBehandle Fehler als erstklassige Werte, nicht als Ausnahmen
Kommuniziere nicht durch gemeinsame SpeichernutzungVerwende Kanäle zur Koordination zwischen Goroutinen
Mache den Nullwert nützlichTypen sollten ohne explizite Initialisierung funktionieren
Ein bisschen Kopieren ist besser als ein bisschen AbhängigkeitVermeide unnötige externe Abhängigkeiten
Klar ist besser als raffiniertPriorisiere Lesbarkeit vor Raffinesse
gofmt ist niemandes Liebling, aber jedermanns FreundFormatiere immer mit gofmt/goimports
Frühzeitig zurückkehrenBehandle Fehler zuerst, halte den Happy Path ohne Einrückung

Anti-Patterns, die vermieden werden sollten

// Schlecht: Nackte Returns in langen Funktionen
func process() (result int, err error) {
    // ... 50 Zeilen ...
    return // Was wird zurückgegeben?
}

// Schlecht: panic für den Kontrollfluss verwenden
func GetUser(id string) *User {
    user, err := db.Find(id)
    if err != nil {
        panic(err) // Mach das nicht
    }
    return user
}

// Schlecht: Kontext in einer Struktur übergeben
type Request struct {
    ctx context.Context // Kontext sollte erster Parameter sein
    ID  string
}

// Gut: Kontext als erster Parameter
func ProcessRequest(ctx context.Context, id string) error {
    // ...
}

// Schlecht: Mischen von Wert- und Zeigerempfängern
type Counter struct{ n int }
func (c Counter) Value() int { return c.n }    // Wert-Empfänger
func (c *Counter) Increment() { c.n++ }        // Zeiger-Empfänger
// Wähle einen Stil und sei konsistent

Denken Sie daran: Go-Code sollte im besten Sinne langweilig sein – vorhersehbar, konsistent und leicht verständlich. Wenn Sie unsicher sind, halten Sie es einfach.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Verwandte Skills