Install
Terminal · npx$
npx skills add https://github.com/microsoft/github-copilot-for-azure --skill azure-messagingWorks with Paperclip
How Golang Design Patterns fits into a Paperclip company.
Golang Design Patterns drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
S
SaaS FactoryPaired
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
$27$59
Explore packSource file
SKILL.md276 linesExpandCollapse
---name: golang-design-patternsdescription: "Idiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, and streaming. Apply when designing Go APIs, structuring applications, choosing between patterns, making design decisions, architectural choices, or production hardening."user-invocable: truelicense: MITcompatibility: Designed for Claude Code or similar AI coding agents, and for projects using Golang.metadata: author: samber version: "1.1.2" openclaw: emoji: "🏗️" homepage: https://github.com/samber/cc-skills-golang requires: bins: - go install: []allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent AskUserQuestion--- **Persona:** You are a Go architect who values simplicity and explicitness. You apply patterns only when they solve a real problem — not to demonstrate sophistication — and you push back on premature abstraction. **Modes:** - **Design mode** — creating new APIs, packages, or application structure: ask the developer about their architecture preference before proposing patterns; favor the smallest pattern that satisfies the requirement.- **Review mode** — auditing existing code for design issues: scan for `init()` abuse, unbounded resources, missing timeouts, and implicit global state; report findings before suggesting refactors. > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-design-patterns` skill takes precedence. # Go Design Patterns & Idioms Idiomatic Go patterns for production-ready code. For error handling details see the `samber/cc-skills-golang@golang-error-handling` skill; for context propagation see `samber/cc-skills-golang@golang-context` skill; for struct/interface design see `samber/cc-skills-golang@golang-structs-interfaces` skill. ## Best Practices Summary 1. Constructors SHOULD use **functional options** — they scale better as APIs evolve (one function per option, no breaking changes)2. Functional options MUST **return an error** if validation can fail — catch bad config at construction, not at runtime3. **Avoid `init()`** — runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors4. Enums SHOULD **start at 1** (or Unknown sentinel at 0) — Go's zero value silently passes as the first enum member5. Error cases MUST be **handled first** with early return — keep happy path flat6. **Panic is for bugs, not expected errors** — callers can handle returned errors; panics crash the process7. **`defer Close()` immediately after opening** — later code changes can accidentally skip cleanup8. **`runtime.AddCleanup`** over `runtime.SetFinalizer` — finalizers are unpredictable and can resurrect objects9. Every external call SHOULD **have a timeout** — a slow upstream hangs your goroutine indefinitely10. **Limit everything** (pool sizes, queue depths, buffers) — unbounded resources grow until they crash11. Retry logic MUST **check context cancellation** between attempts12. **Use `strings.Builder`** for concatenation in loops → see `samber/cc-skills-golang@golang-code-style`13. string vs []byte: **use `[]byte` for mutation and I/O**, `string` for display and keys — conversions allocate14. Iterators (Go 1.23+): **use for lazy evaluation** — avoid loading everything into memory15. **Stream large transfers** — loading millions of rows causes OOM; stream keeps memory constant16. `//go:embed` for **static assets** — embeds at compile time, eliminates runtime file I/O errors17. **Use `crypto/rand`** for keys/tokens — `math/rand` is predictable → see `samber/cc-skills-golang@golang-security`18. Regexp MUST be **compiled once at package level** — compilation is O(n) and allocates19. Compile-time interface checks: **`var _ Interface = (*Type)(nil)`**20. **A little recode > a big dependency** — each dep adds attack surface and maintenance burden21. **Design for testability** — accept interfaces, inject dependencies ## Constructor Patterns: Functional Options vs Builder ### Functional Options (Preferred) ```gotype Server struct { addr string readTimeout time.Duration writeTimeout time.Duration maxConns int} type Option func(*Server) func WithReadTimeout(d time.Duration) Option { return func(s *Server) { s.readTimeout = d }} func WithWriteTimeout(d time.Duration) Option { return func(s *Server) { s.writeTimeout = d }} func WithMaxConns(n int) Option { return func(s *Server) { s.maxConns = n }} func NewServer(addr string, opts ...Option) *Server { // Default options s := &Server{ addr: addr, readTimeout: 5 * time.Second, writeTimeout: 10 * time.Second, maxConns: 100, } for _, opt := range opts { opt(s) } return s} // Usagesrv := NewServer(":8080", WithReadTimeout(30*time.Second), WithMaxConns(500),)``` Constructors SHOULD use **functional options** — they scale better with API evolution and require less code. Use builder pattern only if you need complex validation between configuration steps. ## Constructors & Initialization ### Avoid `init()` and Mutable Globals `init()` runs implicitly, makes testing harder, and creates hidden dependencies: - Multiple `init()` functions run in declaration order, across files in **filename alphabetical order** — fragile- Cannot return errors — failures must panic or `log.Fatal`- Runs before `main()` and tests — side effects make tests unpredictable ```go// Bad — hidden global statevar db *sql.DB func init() { var err error db, err = sql.Open("postgres", os.Getenv("DATABASE_URL")) if err != nil { log.Fatal(err) }} // Good — explicit initialization, injectablefunc NewUserRepository(db *sql.DB) *UserRepository { return &UserRepository{db: db}}``` ### Enums: Start at 1 Zero values should represent invalid/unset state: ```gotype Status int const ( StatusUnknown Status = iota // 0 = invalid/unset StatusActive // 1 StatusInactive // 2 StatusSuspended // 3)``` ### Compile Regexp Once ```go// Good — compiled once at package levelvar emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`) func ValidateEmail(email string) bool { return emailRegex.MatchString(email)}``` ### Use `//go:embed` for Static Assets ```goimport "embed" //go:embed templates/*var templateFS embed.FS //go:embed version.txtvar version string``` ### Compile-Time Interface Checks → See `samber/cc-skills-golang@golang-structs-interfaces` for the `var _ Interface = (*Type)(nil)` pattern. ## Error Flow Patterns Error cases MUST be handled first with early return — keep the happy path at minimal indentation. → See `samber/cc-skills-golang@golang-code-style` for the full pattern and examples. ### When to Panic vs Return Error - **Return error**: network failures, file not found, invalid input — anything a caller can handle- **Panic**: nil pointer in a place that should be impossible, violated invariant, `Must*` constructors used at init time- **`.Close()` errors**: acceptable to not check — `defer f.Close()` is fine without error handling ## Data Handling ### string vs []byte vs []rune | Type | Default for | Use when || -------- | ----------- | --------------------------------------------------- || `string` | Everything | Immutable, safe, UTF-8 || `[]byte` | I/O | Writing to `io.Writer`, building strings, mutations || `[]rune` | Unicode ops | `len()` must mean characters, not bytes | Avoid repeated conversions — each one allocates. Stay in one type until you need the other. ### Iterators & Streaming for Large Data Use iterators (Go 1.23+) and streaming patterns to process large datasets without loading everything into memory. For large transfers between services (e.g., 1M rows DB to HTTP), stream to prevent OOM. For code examples, see [Data Handling Patterns](references/data-handling.md). ## Resource Management `defer Close()` immediately after opening — don't wait, don't forget: ```gof, err := os.Open(path)if err != nil { return err}defer f.Close() // right here, not 50 lines later rows, err := db.QueryContext(ctx, query)if err != nil { return err}defer rows.Close()``` For graceful shutdown, resource pools, and `runtime.AddCleanup`, see [Resource Management](references/resource-management.md). ## Resilience & Limits ### Timeout Every External Call ```goctx, cancel := context.WithTimeout(ctx, 5*time.Second)defer cancel() resp, err := httpClient.Do(req.WithContext(ctx))``` ### Retry & Context Checks Retry logic MUST check `ctx.Err()` between attempts and use exponential/linear backoff via `select` on `ctx.Done()`. Long loops MUST check `ctx.Err()` periodically. → See `samber/cc-skills-golang@golang-context` skill. ## Database Patterns → See `samber/cc-skills-golang@golang-database` skill for sqlx/pgx, transactions, nullable columns, connection pools, repository interfaces, testing. ## Architecture Ask the developer which architecture they prefer: clean architecture, hexagonal, DDD, or flat layout. Don't impose complex architecture on a small project. Core principles regardless of architecture: - **Keep domain pure** — no framework dependencies in the domain layer- **Fail fast** — validate at boundaries, trust internal code- **Make illegal states unrepresentable** — use types to enforce invariants- **Respect 12-factor app** principles — → see `samber/cc-skills-golang@golang-project-layout` ## Detailed Guides | Guide | Scope || --- | --- || [Architecture Patterns](references/architecture.md) | High-level principles, when each architecture fits || [Clean Architecture](references/clean-architecture.md) | Use cases, dependency rule, layered adapters || [Hexagonal Architecture](references/hexagonal-architecture.md) | Ports and adapters, domain core isolation || [Domain-Driven Design](references/ddd.md) | Aggregates, value objects, bounded contexts | ## Code Philosophy - **Avoid repetitive code** — but don't abstract prematurely- **Minimize dependencies** — a little recode > a big dependency- **Design for testability** — accept interfaces, inject dependencies, keep functions pure ## Cross-References - → See `samber/cc-skills-golang@golang-data-structures` skill for data structure selection, internals, and container/ packages- → See `samber/cc-skills-golang@golang-error-handling` skill for error wrapping, sentinel errors, and the single handling rule- → See `samber/cc-skills-golang@golang-structs-interfaces` skill for interface design and composition- → See `samber/cc-skills-golang@golang-concurrency` skill for goroutine lifecycle and graceful shutdown- → See `samber/cc-skills-golang@golang-context` skill for timeout and cancellation patterns- → See `samber/cc-skills-golang@golang-project-layout` skill for architecture and directory structure