Skip to content

Weekly Review — Month 5 · Week 1 (Days 113–119)

Journal index · Roadmap › this week

📅 The Week in One Line

Built the mental model of gRPC from the wire up: protobuf schema → protoc/buf codegen → unary RPC → server/client/bidi streaming → deadlines, metadata, and the status-code error model.

✅ What I Completed

  • Day 113 — Protocol Buffers & .proto files (proto3, field numbers, wire format)
  • Day 114 — Code generation with protoc & buf (two plugins, two output files)
  • Day 115 — Unary RPCs (grpc.NewServer/grpc.NewClient, context-first methods)
  • Day 116 — Server & client streaming (Send/Recv/io.EOF, SendAndClose)
  • Day 117 — Bidirectional streaming (one goroutine per direction, half-close)
  • Day 118 — Deadlines, metadata & status codes (context triad, code→HTTP map)
  • Day 119 — Review + active recall
  • Mini-project: stdlib models of the wire format, framing, deadlines, and the status model
  • Exercises solved: 3 (varint, frames, statuscode) — all green

💡 Lessons Learned

  • On the wire there are no field names — only (field_number << 3) | wire_type. That single fact explains proto3's compatibility rules: rename freely, never renumber/reuse.
  • Codegen is two separate plugins: protoc-gen-go (messages, *.pb.go) and protoc-gen-go-grpc (stubs, *_grpc.pb.go). Embed UnimplementedXxxServer for forward compatibility.
  • A stream is just length-prefixed frames (5-byte header: flag + big-endian length). io.EOF is the clean terminator, never an error to log as failure.
  • The one-goroutine-per-direction rule for streams is the same one-writer discipline as channels; violating it corrupts framing.
  • Deadline, cancellation, and metadata all ride the context — derive child contexts, never reset them, or you silently drop the deadline.
  • Return status.Error(codes.X, msg), not plain errors, so callers can branch on the code and a gateway can map to HTTP.

💪 Strengths (what clicked)

  • Decoding varints/zigzag and gRPC frames by hand — the stdlib examples made the format concrete.
  • The Send/Recv/io.EOF protocol across all three streaming shapes.

🧩 Weaknesses (what's still fuzzy)

  • Surfacing the send goroutine's error cleanly in a bidi client (errgroup vs. channel).
  • Deadline budgeting across multiple hops.
  • Rich status details (status.WithDetails) — only touched the surface.

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

  1. Q: (M4 — concurrency) What's the zero value of a channel and what happens if you send on it?
    Anil; a send (or receive) on a nil channel blocks forever. Useful to disable a select case.
  2. Q: (M2 — slices) Why can append mutate a slice the caller still holds?
    AIf the backing array has spare capacity, append writes in place, so an aliased slice sees the change; once it grows, a new array is allocated and aliasing breaks. Don't rely on either — copy if you need isolation.
  3. Q: (M3 — errors) What does errors.Is do that == doesn't?
    AIt unwraps the error chain (via Unwrap), matching a wrapped sentinel anywhere in the chain — e.g. an error wrapped with %w around io.EOF.
  4. Q: (M1 — interfaces) Why can a non-nil interface hold a nil pointer and not equal nil?
    AAn interface is (type, value). A nil *T stored in an interface gives it a non-nil type word, so iface != nil even though the underlying pointer is nil — the classic nil-interface trap.

🎯 Action Items

  • Write a small bidi client using errgroup to propagate the first error and cancel both directions.
  • Add status.WithDetails/errdetails to one handler and read it on the client.
  • Sketch a per-hop deadline-budget helper.

🚀 Next Week Goals

  • Interceptors (unary + stream), middleware chaining, and auth.
  • TLS / transport credentials for production.
  • gRPC-Gateway / JSON transcoding and grpc-status → HTTP at the edge.

📊 Metrics

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

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