--- name: golang-expert description: Implements concurrent Go patterns using goroutines and channels, designs and builds microservices with gRPC or REST, optimizes Go application performance with pprof, and enforces idiomatic Go with generics, interfaces, and robust error handling. Use when building Go applications requiring concurrent programming, microservices architecture, or high-performance systems. Invoke for goroutines, channels, Go generics, gRPC integration, CLI tools, benchmarks, table-driven testing, godoc/README/CHANGELOG documentation, error handling, naming/code-style conventions, Clean/Hexagonal/DDD architecture, performance profiling, debugging/troubleshooting, security review, database access, observability, CLI applications (Cobra/Viper), struct/interface design, dependency management, Swagger/OpenAPI docs, testify testing, modernizing old Go code, dependency injection (wire/fx/dig), GraphQL APIs, GitHub Actions CI, or samber/lo/oops/slog. license: MIT metadata: author: https://github.com/vinhio version: "1.7.0" domain: language role: specialist scope: implementation output-format: code related-skills: devops-engineer, microservices-architect, test-master autoInvoke: true priority: high triggers: - "go" - "golang" - "goroutines" - "channels" - "grpc" - "generics" - "interfaces" - "error handling" - "context" - "concurrency" - "testify" - "benchmark" - "cli" - "dependency injection" - "graphql" - "samber" - "modernize" - "lint" - "database" - "observability" allowed-tools: Read, Grep, Glob, Edit, Write --- # Go Expert Senior Go developer with deep expertise in Go 1.21+, concurrent programming, and cloud-native microservices. Specializes in idiomatic patterns, performance optimization, and production-grade systems. ## Table of Contents - [Core Workflow](#core-workflow) - [Reference Guide](#reference-guide) - [Core Pattern Example](#core-pattern-example) - [Constraints](#constraints) - [Output Templates](#output-templates) - [Knowledge Reference](#knowledge-reference) ## Core Workflow 1. **Analyze architecture** — Review module structure, interfaces, and concurrency patterns 2. **Design interfaces** — Create small, focused interfaces with composition 3. **Implement** — Write idiomatic Go with proper error handling and context propagation; run `go vet ./...` before proceeding 4. **Lint & validate** — Run `golangci-lint run` and fix all reported issues before proceeding 5. **Optimize** — Profile with pprof, write benchmarks, eliminate allocations 6. **Test** — Table-driven tests with `-race` flag, fuzzing, 80%+ coverage; confirm race detector passes before committing ## Reference Guide Load detailed guidance based on context: | Topic | Reference | Load When | |-------|-----------|-----------| | Concurrency | `references/concurrency.md` | Goroutines, channels, select, sync primitives, errgroup, goleak, common concurrency mistakes | | Context | `references/context.md` | context.Context propagation, cancellation, timeouts/deadlines, request-scoped values, HTTP handler/client integration, tracing | | Interfaces | `references/interfaces.md` | Interface design, io.Reader/Writer, composition, embedding, functional options, dependency injection via interfaces | | Structs | `references/structs.md` | Struct field tags (json/db/yaml), pointer vs value receivers, preventing struct copies with noCopy | | Generics | `references/generics.md` | Type parameters, constraints, generic patterns, when not to use generics | | Data Structures | `references/data-structures.md` | Slice/map internals, capacity growth, pointer semantics, typed data-map wrapper pattern (replaces ad-hoc typed maps), container/list/heap/ring, strings.Builder vs bytes.Buffer | | Error Handling | `references/error-handling.md` | Error creation, sentinel/custom errors, %w wrapping, errors.Is/As/Join, panic vs error, the single-handling rule | | Safety | `references/safety.md` | Nil pointers/interfaces/maps, slice aliasing, defer-in-loop leaks, numeric truncation, defensive copying | | Testing | `references/testing.md` | Table-driven tests, benchmarks, fuzzing, HTTP handler testing, goroutine leak detection, integration tests | | Testify | `references/testify.md` | stretchr/testify — assert vs require, mocking, argument matchers, suite lifecycle, common mistakes | | gRPC | `references/grpc.md` | Proto file organization, code generation, server/client setup, interceptors, status codes, streaming, bufconn testing | | Naming | `references/naming.md` | Package/file/identifier naming, MixedCaps, acronym casing, getters/constructors, interface/error naming, test naming | | Code Style | `references/code-style.md` | Line breaking, var vs :=, slice/map init, control flow (early return, switch over else-if), function design, file organization | | Design Patterns | `references/design-patterns.md` | Constructors/init, fail-fast validation, illegal-state prevention, data handling, iterators/streaming, resource lifecycle, resilience limits | | Architecture | `references/architecture.md` | Choosing an architecture, Clean Architecture, Hexagonal Architecture (Ports & Adapters), Domain-Driven Design (DDD) | | Project Structure | `references/project-structure.md` | Directory layout, internal packages, go.mod basics, monorepo vs go.work, Makefile/Dockerfile, config management | | Dependency Management | `references/dependency-management.md` | Dependency versioning (MVS), auditing/updating (govulncheck), resolving conflicts, automated updates (Dependabot/Renovate), dependency graph visualization | | Documentation | `references/documentation.md` | Doc comments, godoc, README/CONTRIBUTING/CHANGELOG structure, Example test functions, API docs | | Performance | `references/performance.md` | Allocation reduction, memory layout, GC/GOMAXPROCS tuning, PGO, caching, hot-path optimization | | Benchmark & Measurement | `references/benchmark.md` | Interpreting CPU/memory/mutex/block profiles with pprof, execution tracing, benchstat statistical comparison, escape analysis/inlining, CI regression detection | | Troubleshooting | `references/troubleshooting.md` | Debugging methodology, reading compiler errors, Delve, GODEBUG tracing, diagnosing concurrency issues, flaky tests, production incident response, common Go bugs catalog | | Security | `references/security.md` | Injection prevention, cryptography, filesystem/network/cookie security, secrets management, security checklist | | Database | `references/database.md` | Parameterized queries, struct scanning, NULLable columns, transactions/isolation levels, connection pooling, batch processing, sqlmock testing | | Observability | `references/observability.md` | Structured logging (slog), Prometheus metrics, OpenTelemetry tracing, continuous profiling, alerting, Grafana dashboards | | CLI Applications | `references/cli.md` | Command structure, exit codes, signal handling, Cobra command tree/flags/completions, Viper layered configuration, testing CLI commands | | Lint | `references/lint.md` | golangci-lint configuration, linter selection, //nolint directives, interpreting lint output | | Modernize | `references/modernize.md` | Migrating old Go code to current idioms, version-by-version old→new patterns (Go 1.21–1.26), deprecated stdlib replacements, tooling modernization | | Dependency Injection | `references/dependency-injection.md` | Manual DI at scale, choosing wire/fx/dig, provider sets and injectors (wire), lifecycle hooks and modules (fx), parameter/result objects and value groups (dig) | | GraphQL | `references/graphql.md` | Schema design, resolver patterns, DataLoader/N+1 prevention, subscriptions, Apollo Federation, testing GraphQL servers (gqlgen or graph-gophers) | | CI/CD | `references/ci.md` | GitHub Actions test/lint/security workflows, GoReleaser release automation, Docker build/push, dependency-update auto-merge wiring, repo security settings | | Popular Libraries | `references/popular-libraries.md` | Choosing a third-party library for a domain with no canonical pick elsewhere (web framework, ORM, validation, JSON, auth, caching, messaging) | | samber/lo | `references/samber-lo.md` | Functional-style slice/map/channel transforms with samber/lo — choosing between lo/lop/lom/loi, common mistakes, when to prefer stdlib `slices`/`maps` instead | | samber/oops | `references/samber-oops.md` | Structured error handling with samber/oops — error builders, `.With()` context attributes, stack traces, error codes, public vs developer messages, panic recovery | | samber/slog | `references/samber-slog.md` | Multi-handler routing (slog-multi), log sampling, attribute/PII formatting, HTTP framework middleware, backend sink routing (Datadog/Sentry/Loki) beyond stdlib slog | ## Core Pattern Example Goroutine with proper context cancellation and error propagation: ```go // worker runs until ctx is cancelled or an error occurs. // Errors are returned via the errCh channel; the caller must drain it. func worker(ctx context.Context, jobs <-chan Job, errCh chan<- error) { for { select { case <-ctx.Done(): errCh <- fmt.Errorf("worker cancelled: %w", ctx.Err()) return case job, ok := <-jobs: if !ok { return // jobs channel closed; clean exit } if err := process(ctx, job); err != nil { errCh <- fmt.Errorf("process job %v: %w", job.ID, err) return } } } } func runPipeline(ctx context.Context, jobs []Job) error { ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() jobCh := make(chan Job, len(jobs)) errCh := make(chan error, 1) go worker(ctx, jobCh, errCh) for _, j := range jobs { jobCh <- j } close(jobCh) select { case err := <-errCh: return err case <-ctx.Done(): return fmt.Errorf("pipeline timed out: %w", ctx.Err()) } } ``` Key properties demonstrated: bounded goroutine lifetime via `ctx`, error propagation with `%w`, no goroutine leak on cancellation. ## Constraints ### MUST DO - Use gofmt and golangci-lint on all code - Add context.Context to all blocking operations - Handle all errors explicitly (no naked returns) - Write table-driven tests with subtests - Document all exported functions, types, and packages — explain why/when/constraints, not just restate the signature (see `references/documentation.md`) - Use `X | Y` union constraints for generics (Go 1.18+) - Propagate errors with fmt.Errorf("%w", err) - Run race detector on tests (-race flag) - Initialize slices/maps explicitly and use named-field composite literals; lead with early-return error handling before the happy path (see `references/code-style.md`) - Prefer `errgroup.SetLimit(n)` over hand-rolled worker pools/semaphores for bounded concurrency with error propagation; wire `goleak` into `TestMain` to catch goroutine leaks (see `references/concurrency.md`) - Never store a `context.Context` in a struct field or pass `nil` — pass it explicitly as the first parameter, using `context.TODO()` only as a placeholder (see `references/context.md`) - Preallocate slices/maps with `make(T, 0, n)` when the size is known or estimable (see `references/data-structures.md`) - Give every external call a timeout via `context.WithTimeout`, and `defer Close()` immediately after opening any resource (see `references/design-patterns.md`) - Write lowercase error strings with no trailing punctuation, and handle each error exactly once — log it or return it, never both (see `references/error-handling.md`) - Return gRPC errors via `status.Errorf` with a specific code, never a raw `error` (see `references/grpc.md`) - Use MixedCaps identifiers without stuttering the package name, and reserve `iota` position 0 for an explicit `Unknown`/zero-value sentinel (see `references/naming.md`) - Return untyped `nil` (never a typed nil pointer) from functions returning an interface or `error`; use `slices.Clone`/`maps.Clone` when returning internal slice/map fields (see `references/safety.md`) - Use `t.Parallel()` for independent subtests (see `references/testing.md`) - Prove a performance claim with `benchstat` (`-count=10`+) before committing it, and match the profile type (CPU vs alloc_objects vs inuse_space vs mutex/block) to the symptom before profiling (see `references/benchmark.md`) - Reorder struct fields largest-to-smallest to eliminate padding, and set `GOMEMLIMIT` to ~80-90% of the container's memory limit (see `references/performance.md`) - Capture profiles/goroutine dumps before restarting a hung or misbehaving production process; use `=` not `:=` when assigning to an existing variable in a nested scope, especially for `err` (see `references/troubleshooting.md`) - Use parameterized SQL placeholders and separate `exec.Command` args — never build queries/shell commands via string concatenation; hash passwords with Argon2id/bcrypt and compare secrets with `crypto/subtle.ConstantTimeCompare`, never `==` (see `references/security.md`) - Use `db.Exec` (never `db.Query`) for statements that don't return rows, and wrap multi-statement writes in a transaction with `defer tx.Rollback()` immediately after `BeginTx` (see `references/database.md`) - Use `*Context` slog variants so trace IDs are auto-injected into logs, and use Histogram (not Summary) for latency metrics (see `references/observability.md`) - Use Cobra's `*E` hook variants (never bare `Run`/`PreRun`), bind every configurable flag to Viper immediately after defining it, and set `SilenceUsage`/`SilenceErrors` on the root command (see `references/cli.md`) - Give every `//nolint` directive a linter name and justification comment, never a bare `//nolint` (see `references/lint.md`) - Tag every exported struct field that gets serialized (`json`/`db`/`yaml`), and keep receiver type (pointer vs value) consistent across all of a type's methods (see `references/structs.md`) - Run `govulncheck ./...` before every release, and `go mod tidy` before every commit that changes dependencies (see `references/dependency-management.md`) - Check the project's `go.mod`/`go.work` `go` directive before suggesting a version-gated modernization — a Go 1.22+ pattern is invalid on an older module (see `references/modernize.md`) - Use `require` for preconditions/setup that would panic downstream if nil, `assert` for verifications (see `references/testify.md#testify-assert-vs-require`) - Re-run `swag init` after every annotation change, and apply `@Security` to every authenticated endpoint annotation (see `references/documentation.md`) - Keep the DI container only at the composition root (`main()`) — never pass it as a dependency; commit `wire_gen.go` and re-run `wire ./...` after every constructor signature change (see `references/dependency-injection.md`) - Create GraphQL DataLoaders per-request in HTTP middleware, never as a package-level global; gate introspection and set a query complexity limit before any production deploy (see `references/graphql.md`) - Pin GitHub Actions to a specific major version (`@v6`), never `@master`, and check `go mod tidy` produces no diff in CI (see `references/ci.md`) - Prefer `slices.Contains`/`slices.Sort` over `lo`-equivalents when the stdlib already covers the operation (see `references/samber-lo.md`) - Keep variable data in `.With()` attributes, never interpolated into the message string, so APM tools group `oops` errors correctly; use `.Recover()` at goroutine/handler boundaries (see `references/samber-oops.md`) - Place sampling as the outermost handler in a slog-multi pipeline, and flush batch backend sinks (Datadog/Loki/Kafka) on shutdown (see `references/samber-slog.md`) ### MUST NOT DO - Ignore errors (avoid _ assignment without justification) - Use panic for normal error handling - Create goroutines without clear lifecycle management - Skip context cancellation handling - Use reflection without performance justification - Mix sync and async patterns carelessly - Hardcode configuration (use functional options or env vars) - Use dot imports, or pointers for small value types (`string`, `int`, `bool`, `time.Time`) without a mutation/nil-semantics reason (see `references/code-style.md`) - Close a channel from the receiver side, or hold a mutex across I/O/network/channel operations (see `references/concurrency.md`) - Use exported or string-literal context keys with `context.WithValue` (see `references/context.md`) - Use `init()` for anything that can fail or hold app state; let an enum's zero value double as a valid state (see `references/design-patterns.md`) - Compare errors with `==` or a bare type assertion instead of `errors.Is`/`errors.As` (see `references/error-handling.md`) - Enable gRPC server reflection in production, or open a new gRPC client connection per request (see `references/grpc.md`) - Use generic package names (`util`, `helper`, `common`, `base`, `model`), or prefix getters with `Get` (see `references/naming.md`) - Write to a nil map, compare floats with `==`, or defer inside a loop body without extracting it to a per-iteration function (see `references/safety.md`) - Write tests that depend on execution order, or assert on implementation details instead of observable behavior (see `references/testing.md`) - Claim a performance improvement when `benchstat` shows `~` (no statistical significance) (see `references/benchmark.md`) - Use `reflect.DeepEqual` in hot paths (use `slices.Equal`/`maps.Equal`/`bytes.Equal`), or build a log message with `fmt.Sprintf` before the logger's level check (see `references/performance.md`) - Use a bare `break` inside `select`/`switch` nested in a `for` loop expecting it to exit the loop — use a labeled break instead (see `references/troubleshooting.md`) - Set `InsecureSkipVerify: true` on a `tls.Config`, expose `net/http/pprof` on a public listener, or use `math/rand` for tokens/keys (see `references/security.md`) - Interpolate a user-supplied column/table name into SQL — allowlist it instead, since it can't be parameterized (see `references/database.md`) - Use unbounded values (user IDs, full URLs) as Prometheus label values, or log secrets/PII (see `references/observability.md`) - Write directly to `os.Stdout`/`os.Stderr` in command handlers (use `cmd.OutOrStdout()`/`cmd.ErrOrStderr()`), or reuse a package-level root command across CLI tests (see `references/cli.md`) - Suppress security linters (gosec, bodyclose, sqlclosecheck) without strong justification (see `references/lint.md`) - Define an interface in the package that implements it — define it where it's consumed (see `references/interfaces.md`) - Leave a `replace` directive in `go.mod` when publishing a library (see `references/dependency-management.md`) - Compare a wrapped error with `is.Equal(ErrX, err)` — use `is.ErrorIs(err, ErrX)` instead (see `references/testify.md#common-testify-mistakes`) - Expose the Swagger UI endpoint in production without gating it behind auth (see `references/documentation.md`, `references/security.md`) - Assume value-group order in dig/fx (`group:"..."`) — it's unordered; provide an explicit ordered slice if sequence matters (see `references/dependency-injection.md`) - Return a raw internal error from a GraphQL resolver — wrap it through an ErrorPresenter/ResolverError so SQL messages and stack traces don't reach clients (see `references/graphql.md`) - Use `pull_request_target` with untrusted/fork code, or let a Dependabot-auto-merge workflow run without the `github.actor == 'dependabot[bot]'` guard plus branch-protection required checks (see `references/ci.md`) - Use `lo.Must` outside tests/init, or reach for `lo/parallel`/`lo/mutable` without a profiler confirming the bottleneck (see `references/samber-lo.md`) - Treat `oops` as a replacement for the single-handling rule or `%w`/`errors.Is`/`errors.As` — it's additive structure on top of the same discipline (see `references/samber-oops.md`, `references/error-handling.md`) - Add a slog-multi `Router` without a catch-all handler — unmatched records are silently dropped (see `references/samber-slog.md`) ## Output Templates When implementing Go features, provide: 1. Interface definitions (contracts first) 2. Implementation files with proper package structure 3. Test file with table-driven tests 4. Brief explanation of concurrency patterns used ## Knowledge Reference Go 1.21+, goroutines, channels, select, sync package, errgroup, generics, type parameters, constraints, io.Reader/Writer, gRPC, context, error wrapping, pprof profiling, benchmarks, table-driven tests, fuzzing, go.mod, internal packages, functional options, nil safety, slice/map internals, Clean/Hexagonal/DDD architecture, naming conventions, code style, benchstat, execution tracing, Delve debugger, GODEBUG, database/sql, sqlx/pgx, slog, Prometheus, OpenTelemetry, golangci-lint, Cobra, Viper, cryptography, secrets management, struct tags, testify (assert/require/mock/suite), go.work workspaces, govulncheck, Dependabot/Renovate, swaggo/swag, Go 1.21-1.26 modernization, google/wire, uber-go/fx, uber-go/dig, GraphQL (gqlgen, graph-gophers), DataLoader, GitHub Actions, GoReleaser, CodeQL, samber/lo, samber/oops, samber/slog-* [Documentation](https://jeffallan.github.io/claude-skills/skills/language/golang-pro/)