How Go's compiler shares generic function bodies by GC shape and uses dictionaries for the concrete types. | Continue reading
Go 1.26 rebuilt go fix on the analysis framework. It modernizes your code and respects the Go version your module declares. The post covers the modernizers, the bigger x/tools suite, and what //go:fix inline can and can't migrate. | Continue reading
A hot cache key expires and a hundred requests issue the same query at once, saturating the database. Go's singleflight package coalesces those duplicate calls into one. How to wire it up, how to measure whether it's firing, and why per-pod coalescing is usually enough. | Continue reading
A for-range over an unclosed channel leaks the receiver. Why three explicit receives are safe, why a range isn't, and catching it with Go 1.27's leak profile. | Continue reading
Notes on Go's accepted goroutine leak profile and how it reuses the GC to find them. | Continue reading
PostgreSQL 19's new WAIT FOR LSN command lets a replica block until it has replayed your write. The read-after-write problem it solves, the workarounds it replaces, and what the timeout, status, and mode options are actually for. | Continue reading
Why I swapped GNU stow's symlink farm for chezmoi: one command to bootstrap a Mac with Homebrew packages and macOS settings, a small daily sync loop, and agent skills shared between Claude Code and Codex. | Continue reading
Mirroring a static Hugo blog onto ATProto with standard.site and Sequoia, plus the GitHub Actions wiring that republishes the records on every push without any manual steps. | Continue reading
Drive-by AI changes break the shared model a team builds around its code, and the ICs end up cleaning up the mess. Why pushing to mainline should come with the pager. | Continue reading
How cmd/go's script tests led me to testscript, and how to use it for CLI tests that exercise argv, stdout, stderr, exit codes, and scratch files. | Continue reading
txtar is a tiny plain-text archive format Russ Cox introduced in 2018 for multi-file test fixtures. The Go Playground, cmd/go's script tests, gopls's marker tests, and rsc.io/rf all reach for it. | Continue reading
The default slog API is loose enough that a careless line ships broken JSON to production. Pin it down with Attr constructors, LogAttrs, a context-borne logger, and sloglint. | Continue reading
Four of the five steps in every unary RPC handler are wire plumbing. Pin the service function signature and they fit in one generic adapter per transport. | Continue reading
A Go closure holds a live reference to whatever it captures, not a snapshot. Real examples of where this trips people up, and how to keep it boring. | Continue reading
Notes on Go's newly accepted uuid proposal and the tradeoffs behind the API. | Continue reading
A quick tour of Go struct tags: how different libraries use them, how you read them at runtime with reflection, and how other tools read them at build time instead. | Continue reading
A quick tour of Go struct tags: how different libraries use them, how you read them at runtime with reflection, and how other tools read them at build time instead. | Continue reading
Go's proposal review group accepted a new uuid package with v4 and v7 generators. Here are the decisions that shaped the final API. | Continue reading
Translating errors at layer boundaries so storage details don't leak into the handler or, worse, into client responses. | Continue reading
Key takeaways from Amazon's 2007 Dynamo paper. | Continue reading
Why logging at every layer of a service produces noise, and how to log only at the handler level while propagating context from below. | Continue reading
Switch, map of functions, and interface registry for dispatching in Go. | Continue reading
Why & backgrounds execution but doesn't stop output from flooding your terminal. | Continue reading
How to test unary gRPC services in Go - handler logic, interceptors, deadlines, metadata propagation, and rich error details - all in-memory with bufconn. | Continue reading
Decoupling business logic from storage in Go, adding transaction support without leaking SQL details, and coordinating atomic writes across multiple repositories using a unit of work. | Continue reading
Adding transaction support to a repository interface without leaking storage details. | Continue reading
Why the middleware-to-handler boundary is a special case for context values. | Continue reading
A simple litmus test for when to use context values in Go. | Continue reading
Decoupling business logic from storage with a small interface in Go. | Continue reading
How to wrap a generated gRPC client behind a clean Go API so users never have to touch protobuf types or connection management directly. | Continue reading
Why the etcd codebase is my go-to reference for building gRPC services in Go. | Continue reading
Exploring the tradeoffs between wrapping errors at every return site versus wrapping only at boundaries, with no definitive answer - just honest tradeoffs for the kind of software I write. | Continue reading
Why your mutex wrapper should accept a closure for mutation instead of a plain value, with examples from the standard library and Tailscale. | Continue reading
How Go 1.20's WithCancelCause and Go 1.21's WithTimeoutCause let you attach a reason to context cancellation, plus a gotcha with manual cancel and the stdlib pattern that covers every path. | Continue reading
How Python and Kotlin provide structured concurrency out of the box while Go achieves the same patterns explicitly using errgroup, WaitGroup, and context. | Continue reading
Practical patterns for mocking in Go without external libraries. Learn to mock functions, methods, interfaces, HTTP calls, and time using only the standard library | Continue reading
Practical patterns for mocking in Go without external libraries. Learn to mock functions, methods, interfaces, HTTP calls, and time using only the standard library | Continue reading
Throughout the years, I’ve been part of a few medium- to large-scale system migrations. As in, rewriting old logic in a new language or stack to gain better scalability, resilience, and maintainability, or to respond more easily to changing business requirements. Whether rewritin … | Continue reading
A man with a watch knows what time it is. A man with two watches is never sure. — Segal’s law Take this example: func validate(input string) (bool, error) { if input == "" { return false, nil } if isCorrupted(input) { return false, fmt.Errorf("corrupt … | Continue reading
When testing Go code that spawns subprocesses, you usually have three options. Run the real command. It invokes the actual binary that creates the subprocess and asserts against the output. However, that makes tests slow and tied to the environment. You have to make sure the same … | Continue reading
Object-oriented (OO) patterns get a lot of flak in the Go community, and often for good reason. Still, I’ve found that principles like SOLID, despite their OO origin, can be useful guides when thinking about design in Go. Recently, while chatting with a few colleagues new to Go, … | Continue reading
Along with propagating deadlines and cancellation signals, Go’s context package can also carry request-scoped values across API boundaries and processes. There’s only two public API constructs associated with context values: func WithValue(parent Context, key, val any) Context fu … | Continue reading
When it comes to test organization, Go’s standard testing library only gives you a few options. I think that’s a great thing because there are fewer details to remember and fewer things to onboard people to. However, during code reviews, I often see people contravene a few common … | Continue reading
When it comes to test organization, Go’s standard testing library only gives you a few options. I think that’s a great thing because there are fewer details to remember and fewer things to onboard people to. However, during code reviews, I often see people contravene a few common … | Continue reading
Go has support for subtests starting from version 1.7. With t.Run, you can nest tests, assign names to cases, and let the runner execute work in parallel by calling t.Parallel from subtests if needed. For small suites, a flat set of t.Run calls is usually enough. That’s where I t … | Continue reading
Go has support for subtests starting from version 1.7. With t.Run, you can nest tests, assign names to cases, and let the runner execute work in parallel by calling t.Parallel from subtests if needed. For small suites, a flat set of t.Run calls is usually enough. That’s where I t … | Continue reading
I like to make the distinction between application structure and architecture. Structure is how you organize the directories and packages in your app while architecture is how different components talk to each other. The way your app talks to other services in a fleet can also be … | Continue reading
I like to make the distinction between application structure and architecture. Structure is how you organize the directories and packages in your app while architecture is how different components talk to each other. The way your app talks to other services in a fleet can also be … | Continue reading