🐹 Cheatsheet: Intermediate Go: Build Concurrent Backend Services

Scope: concurrency foundations, HTTP service + data access, and shipping with gRPC, profiling, and containers.


Module 1: Concurrency as the Spine

1.1 Types, Interfaces, Errors

Concept Rule of thumb
Value semantics Struct passed by value = copy. Mutate via pointer *T receiver only when needed
Interface size Small (1-3 methods). Define at the consumer, not the producer
Nil interface trap var e error = (*MyErr)(nil) is non-nil; return explicit nil
Error wrapping fmt.Errorf("...: %w", err) keeps the chain
Error inspection errors.Is for sentinels, errors.As for typed errors
Panic Only for unrecoverable programmer bugs, never for control flow
var ErrNotFound = errors.New("not found")

if errors.Is(err, ErrNotFound) { /* sentinel match */ }
var pe *PathError
if errors.As(err, &pe) { /* typed match */ }

[!TIP] Wrap with %w and add context at each layer. Unwrap down to the sentinel only at the boundary that decides behavior.

1.2 Goroutines, Channels, Context

Need Use
Hand off data / ownership Channel
Guard state that stays put sync.Mutex / sync.RWMutex
Request deadline + cancellation context.Context
Wait for N goroutines sync.WaitGroup
One-time init sync.Once

Rules:

  • Every goroutine needs an exit path. No fire-and-forget.
  • Pass ctx as the first parameter; never store it in a struct.
  • select on ctx.Done() to respect cancellation.
  • Close a channel from the sender only. Receivers never close.
  • Buffered channel = bounded queue; size it deliberately.
select {
case <-ctx.Done():
    return ctx.Err()
case v := <-ch:
    handle(v)
}

1.3 Bounded Fan-Out with errgroup

This cheatsheet is part of the paid section. Sign in and purchase the course to view the full content. Sign in