Weekly Review — Month 2 · Week 4 (Days 050–056)¶
📅 The Week in One Line¶
The engineering around the code: catch bugs with go vet/golangci-lint, automate the workflow with a Makefile, ship variants via build tags & cross-compilation, profile with pprof, enforce it all in GitHub Actions CI, and land a stdlib-only URL-shortener capstone.
✅ What I Completed¶
- Day 050 —
go vet&golangci-lint/staticcheck(analyzers,.golangci.yml,//nolint) - Day 051 —
Makefile& task automation (.PHONY, tab rule,-ldflags -Xversion stamp) - Day 052 — Build tags & cross-compilation (
//go:build, filename suffixes,GOOS/GOARCH) —build-tagsexample - Day 053 —
pprofquickstart (runtime/pproffiles +net/http/pproflive,flatvscum) —pprofexample - Day 054 — GitHub Actions CI for Go (
setup-gocaching, matrix,gofmt -lgate) - Day 055 — Project: URL shortener (base62,
RWMutexstore, 302 redirects) —urlshortenerexample - Day 056 — Month 2 review + recall, tag
v0.2.0 - Runnable examples: 3 (
build-tags,pprof,urlshortener) - Exercises solved: 3 (
base62,normalizeurl,urlstore) — round-trip property test +-race
💡 Lessons Learned¶
go vetruns automatically insidego test; a vet failure fails the test run — clean vet is table stakes, andgolangci-lint/staticcheckare external binaries you run as tools, never imports.- A
Makefilerecipe must start with a literal tab, each line runs in its own shell, and task names belong under.PHONYso a same-named file can't makemakeskip them. - Build constraints resolve at compile time:
//go:buildneeds a blank line beforepackage, per-OS files must be mutually exclusive + exhaustive, andruntime.GOOSreports the build target, not the host. pprofCPU profiles are only valid afterStopCPUProfile;net/http/pprofis a blank import for itsinit; readflat(own time) vscum(incl. callees) to find the real hot spot.gofmt -l .alone exits 0 even when it lists files — the CI gate must betest -z "$(gofmt -l .)".- Maps aren't safe for concurrent writes; the shortener's store needs an
RWMutex(readersRLock, writersLock), proven withgo test -race.
💪 Strengths (what clicked)¶
- Wiring the local gate (
fmt→vet→test -race→build) into both aMakefileand CI — the same checklist, enforced two ways. - Build tags + cross-compilation: the "one of N files is linked" mental model finally feels obvious.
- Designing the shortener around an interface-friendly, lock-guarded store.
🧩 Weaknesses (what's still fuzzy)¶
- Deeper
pprofviews (alloc_spacevsinuse_space, block/mutex profiles) and when to switch toruntime/trace. - Exhaustively reasoning about build-constraint combinations (OS × arch × custom tags) without trial and error.
- CI niceties: artifact upload, required checks, reusable workflows.
🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)¶
- Q: (Wk1) What does
io.Copyreturn, and how do you cap how much it reads?A
It returns (written int64, err error) and copies until EOF (EOF itself isn't reported as an error). Cap it by wrapping the source in io.LimitReader(r, n).
2. Q: (Wk2) What's the reference time layout string in time.Format? A
Mon Jan 2 15:04:05 MST 2006 — i.e. 2006-01-02 15:04:05. The numbers 1,2,3,4,5,6,7 encode month/day/hour/min/sec/year/zone.
3. Q: (Wk2) Where does context.Context go in a function signature, and how do you propagate cancellation to an HTTP request? A
It's the first parameter, conventionally named ctx. Use http.NewRequestWithContext(ctx, ...) so the request is cancelled when the context is.
4. Q: (Wk3) In a table-driven test with subtests, why capture the loop variable before t.Parallel() (pre-Go 1.22)? A
Parallel subtests run after the loop advances; without tt := tt they'd all see the final iteration's value. Go 1.22 made the loop var per-iteration, but capturing is still the safe, explicit habit.
5. Q: (Wk4) Why is fmt.Printf("%d", "x") a compile-success but a bug? A
Printf takes ...any, so any type compiles; the verb/arg contract is unchecked by the compiler. go vet's printf analyzer flags the mismatch statically.
🎯 Action Items¶
- Add a real
Makefile+.github/workflows/ci.ymlat the repo root (currently snippets in the notes). - Profile the shortener under load and record a
flat/cumread-through. - Practice
GOOS/GOARCHcross-builds for windows/amd64 and darwin/arm64 and check the binaries run.
🚀 Next Week Goals¶
- Begin Month 3: deeper concurrency patterns (worker pools,
errgroup-style fan-out, pipelines, graceful shutdown). - Evolve the shortener toward a real service (persistence behind an interface, middleware,
http.Server.Shutdown).
📊 Metrics¶
| Hours | Days hit | Exercises | Commits | Avg confidence |
|---|---|---|---|---|
| 10.5 | 7/7 | 3 | 7 | 3.⅗ |
Suggested commit: docs(journal): week 4 review