Files
poimen-memory/knowledge/golang-skills.md
T
rock a5ff20c9f7 feat: add 'mem learn' CLI for markdown knowledge ingestion
6 knowledge files: rust, SOLID/DRY, ast-grep, karpathy, golang, caveman
65 chunks ingested to log/knowledge/learn/latest.jsonl
Chunks on ## headings, SHA256 dedup, configurable chunk size
2026-08-29 22:04:14 -07:00

4.3 KiB

Go (Golang) Skills

Core Idioms

  • Accept interfaces, return structs.
  • Errors are values — check them explicitly. if err != nil { return err }.
  • Don't panic in library code. Reserve panic for truly unrecoverable situations.
  • Zero values are useful — var m map[string]int is nil but var s []int is usable.

Error Handling

  • Wrap errors with context: fmt.Errorf("failed to open %s: %w", path, err).
  • Sentinel errors: var ErrNotFound = errors.New("not found"). Check with errors.Is(err, ErrNotFound).
  • Custom error types: type ValidationError struct { Field, Message string }. Check with errors.As().
  • Never ignore errors: _ = doSomething() is a code smell. At minimum, log it.

Concurrency

  • "Don't communicate by sharing memory; share memory by communicating." — use channels.
  • go func() launches goroutine. Always ensure goroutines terminate (context, done channel).
  • sync.WaitGroup to wait for goroutine completion.
  • sync.Mutex when channels are overkill (protecting a counter, map).
  • context.Context for cancellation, timeouts, and request-scoped values. Always first parameter.
  • errgroup.Group for parallel tasks with error propagation.

Channel Patterns

  • ch := make(chan T) unbuffered (synchronous). make(chan T, n) buffered.
  • Fan-out: multiple goroutines read from one channel.
  • Fan-in: multiple channels merged into one via select.
  • Pipeline: chain of stages connected by channels.
  • select with case <-ctx.Done(): for cancellation.
  • Close channels from sender side only. Never close from receiver.

Interfaces

  • Interfaces are satisfied implicitly — no implements keyword.
  • Keep interfaces small: io.Reader has one method. io.ReadWriteCloser composes three.
  • Define interfaces where they're used, not where they're implemented.
  • interface{} (or any) is a code smell — prefer generics or specific interfaces.
  • Type assertions: v, ok := i.(ConcreteType). Type switch: switch v := i.(type) { ... }.

Generics (Go 1.18+)

  • func Map[T, U any](s []T, f func(T) U) []U — generic function.
  • Constraints: comparable, ~int | ~float64, custom interface constraints.
  • Use generics for data structures and utility functions, not business logic.

Project Structure

cmd/
  myapp/main.go       # entrypoint
internal/              # private packages
  domain/              # business logic, no external deps
  repository/          # data access
  handler/             # HTTP handlers
pkg/                   # public library code
  • internal/ enforced by Go compiler — cannot be imported outside module.
  • One package per directory. Package name = directory name.

Testing

  • func TestFoo(t *testing.T) — test functions.
  • Table-driven tests: tests := []struct{ name string; input int; want int }{ ... }.
  • t.Run(name, func(t *testing.T) { ... }) for subtests.
  • t.Parallel() for concurrent test execution.
  • testify/assert for cleaner assertions. testify/mock for mocking.
  • httptest.NewServer() for HTTP integration tests.
  • Benchmarks: func BenchmarkFoo(b *testing.B) { for i := 0; i < b.N; i++ { ... } }.

HTTP Server

  • http.HandlerFunc wraps functions as handlers.
  • Middleware pattern: func Logging(next http.Handler) http.Handler.
  • Use chi or echo for routing. Stdlib http.ServeMux improved in Go 1.22.
  • Always set timeouts: srv := &http.Server{ReadTimeout: 5*time.Second, WriteTimeout: 10*time.Second}.
  • Graceful shutdown: signal.Notify + srv.Shutdown(ctx).

Performance

  • pprof for CPU/memory profiling: go tool pprof http://localhost:6060/debug/pprof/profile.
  • sync.Pool for reducing GC pressure on frequently allocated objects.
  • Pre-allocate slices: make([]T, 0, expectedLen).
  • String building: strings.Builder not + concatenation.
  • Avoid interface boxing in hot paths.

Common Gotchas

  • Loop variable capture in goroutines (fixed in Go 1.22, but still common in older code).
  • Nil interface vs nil pointer: var p *MyType = nil; var i MyInterface = p; i != nil is TRUE.
  • Maps are not safe for concurrent access — use sync.Map or sync.RWMutex.
  • Slice append may or may not create a new backing array — never hold stale slice references.
  • defer evaluates arguments immediately, runs function at return.
  • init() runs before main() — avoid side effects, prefer explicit initialization.