$npx -y skills add samber/cc-skills-golang --skill golang-design-patternsIdiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, streaming, and more. Apply when explicitly choosing between architec
| 1 | **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. |
| 2 | |
| 3 | **Modes:** |
| 4 | |
| 5 | - **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. |
| 6 | - **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. |
| 7 | |
| 8 | > **Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-design-patterns` skill takes precedence. |
| 9 | |
| 10 | # Go Design Patterns & Idioms |
| 11 | |
| 12 | 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. |
| 13 | |
| 14 | ## Best Practices Summary |
| 15 | |
| 16 | 1. Constructors SHOULD use **functional options** — they scale better as APIs evolve (one function per option, no breaking changes) |
| 17 | 2. Functional options MUST **return an error** if validation can fail — catch bad config at construction, not at runtime |
| 18 | 3. **Avoid `init()`** — runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors |
| 19 | 4. Enums SHOULD **start at 1** (or Unknown sentinel at 0) — Go's zero value silently passes as the first enum member |
| 20 | 5. Error cases MUST be **handled first** with early return — keep happy path flat |
| 21 | 6. **Panic is for bugs, not expected errors** — callers can handle returned errors; panics crash the process |
| 22 | 7. **`defer Close()` immediately after opening** — later code changes can accidentally skip cleanup |
| 23 | 8. **`runtime.AddCleanup`** over `runtime.SetFinalizer` — finalizers are unpredictable and can resurrect objects |
| 24 | 9. Every external call SHOULD **have a timeout** — a slow upstream hangs your goroutine indefinitely |
| 25 | 10. **Limit everything** (pool sizes, queue depths, buffers) — unbounded resources grow until they crash |
| 26 | 11. Retry logic MUST **check context cancellation** between attempts |
| 27 | 12. **Use `strings.Builder`** for concatenation in loops → see `samber/cc-skills-golang@golang-code-style` |
| 28 | 13. string vs []byte: **use `[]byte` for mutation and I/O**, `string` for display and keys — conversions allocate |
| 29 | 14. Iterators (Go 1.23+): **use for lazy evaluation** — avoid loading everything into memory |
| 30 | 15. **Stream large transfers** — loading millions of rows causes OOM; stream keeps memory constant |
| 31 | 16. `//go:embed` for **static assets** — embeds at compile time, eliminates runtime file I/O errors |
| 32 | 17. **Use `crypto/rand`** for keys/tokens — `math/rand` is predictable → see `samber/cc-skills-golang@golang-security` |
| 33 | 18. Regexp MUST be **compiled once at package level** — compilation is O(n) and allocates |
| 34 | 19. Compile-time interface checks: **`var _ Interface = (*Type)(nil)`** |
| 35 | 20. **A little recode > a big dependency** — each dep adds attack surface and maintenance burden |
| 36 | 21. **Design for testability** — accept interfaces, inject dependencies |
| 37 | |
| 38 | ## Constructor Patterns: Functional Options vs Builder |
| 39 | |
| 40 | ### Functional Options (Preferred) |
| 41 | |
| 42 | ```go |
| 43 | type Server struct { |
| 44 | addr string |
| 45 | readTimeout time.Duration |
| 46 | writeTimeout time.Duration |
| 47 | maxConns int |
| 48 | } |
| 49 | |
| 50 | type Option func(*Server) |
| 51 | |
| 52 | func WithReadTimeout(d time.Duration) Option { |
| 53 | return func(s *Server) { s.readTimeout = d } |
| 54 | } |
| 55 | |
| 56 | func WithWriteTimeout(d time.Duration) Option { |
| 57 | return func(s *Server) { s.writeTimeout = d } |
| 58 | } |
| 59 | |
| 60 | func WithMaxConns(n int) Option { |
| 61 | return func(s *Server) { s.maxConns = n } |
| 62 | } |
| 63 | |
| 64 | func NewServer(addr string, opts ...Option) *Server { |
| 65 | // Default options |
| 66 | s := &Server{ |
| 67 | addr: addr, |
| 68 | readTimeout: 5 * time.Second, |
| 69 | writeTimeout: 10 * time.Second, |
| 70 | maxConns: |