Files
poimen-memory/knowledge/golang-skills.md
T
rock 762acea610
Build and Push / Test (push) Failing after 6s
Build and Push / Build and push image (push) Skipped
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

86 lines
4.3 KiB
Markdown

# 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.