Skip to content

Weekly Review — Month 3 · Week 1 (Days 057–063)

Journal index · Roadmap › this week

📅 The Week in One Line

The foundations of Go concurrency: goroutines, channels, select, and the leak-free pipeline patterns that hold them together.

✅ What I Completed

  • Day 057 — Goroutines & the go statement; sync.WaitGroup; concurrency vs parallelism
  • Day 058 — Channels: unbuffered (rendezvous) vs buffered (decoupled), close + range
  • Day 059 — Channel axioms: the four close panics, nil-channel blocking, directional types
  • Day 060 — select, default, time.After/Timer/Ticker, labelled break
  • Day 061 — Deadlocks vs goroutine leaks; -race, go vet, stack dumps
  • Day 062 — Generators, pipelines, fan-in merge, done-channel cancellation
  • Day 063 — Review + closed-book recall
  • Mini-project: pipeline + worker pool + fan-in exercises, all -race-clean
  • Exercises solved: 3 (pipeline, fanin, workerpool)

💡 Lessons Learned

  • A goroutine is cheap (~2 KB growable stack), but coordination is the real cost — always have an explicit join (WaitGroup or channel).
  • Unbuffered channels are a synchronisation tool, not just transport: the send/receive rendezvous is the point.
  • The sender owns close, exactly once; with multiple senders, hand close to a single closer goroutine after wg.Wait().
  • A nil channel blocking forever is a feature: set a select case's channel to nil to switch it off.
  • Deadlocks announce themselves (runtime panic when all goroutines sleep); leaks are silent and need a done/context cancel signal.

💪 Strengths (what clicked)

  • WaitGroup Add-before-go / deferred-Done / Wait rhythm.
  • Order-preserving linear pipelines (single FIFO channel).
  • Bounding a blocking op with select + time.After.

🧩 Weaknesses (what's still fuzzy)

  • Reading goroutine stack dumps to pinpoint a hang's culprit frame.
  • Multi-sender close coordination beyond the simple closer-goroutine case.
  • Knowing when buffered sizing actually helps under bursty load (needs benchmarks).

🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)

  1. Q: (M1) What does string(65) produce and why?
    A"A" — it's an int→rune conversion to code point U+0041, not "65". Use strconv.Itoa.
  2. Q: (M1) Why can append mutate a slice the caller still holds?
    ASlices share a backing array; if append doesn't grow capacity it writes in place, aliasing the original.
  3. Q: (M2) What does %w do in fmt.Errorf?
    AWraps an error so errors.Is/errors.As can unwrap and match it.
  4. Q: (M2) Why must context.Context be the first parameter?
    AConvention for cancellation/deadline propagation; tooling and readers expect ctx context.Context first.
  5. Q: (M3) Send on a closed channel vs a nil channel?
    AClosed → panic; nil → blocks forever.

🎯 Action Items

  • Practise reading GOTRACEBACK=all stack dumps on a deliberately hung program.
  • Rewrite the generator example using context.Context once Week 2 covers it.
  • Benchmark a buffered vs unbuffered producer/consumer to see when buffering pays off.

🚀 Next Week Goals

  • sync primitives: Mutex, RWMutex, Once, sync.WaitGroup deeper, sync.Map.
  • sync/atomic and the memory model basics.
  • context.Context: cancellation, deadlines, WithTimeout/WithCancel, the value anti-pattern.

📊 Metrics

Hours Days hit Exercises Commits Avg confidence
9 7/7 3 7 3.⅗

Suggested commit: docs(journal): month 3 week 1 review