Go Benchmarks: Writing Ones That Actually Tell You Something

Go has first-class benchmarking built into the testing package. go test -bench=. is enough to get started. The hard part isn’t running benchmarks — it’s writing ones that measure what you intend to measure. These are the patterns I’ve found essential and the mistakes I’ve made repeatedly enough to write down. ...

March 17, 2020 · 6 min · MW

Context Propagation in Go: Deadlines, Cancellation, and Tracing

context.Context appears in the signature of almost every non-trivial Go function. It’s the idiomatic way to carry deadlines, cancellation signals, and request-scoped values across API boundaries and goroutines. After years of reading Go codebases, the misuse patterns are as common as the correct uses. ...

February 19, 2020 · 5 min · MW

Go Module System: Dependency Management Done Right (Mostly)

Go modules are one of the more carefully designed dependency management systems I’ve worked with. The core ideas — versioned module paths, minimum version selection, reproducible builds via go.sum — are sound. After running services on modules since 1.11, the rough edges are predictable enough to document. ...

January 8, 2020 · 5 min · MW

Error Handling in Go: Patterns That Actually Work at Scale

When I started writing Go after years of Java, the error handling felt tedious. Every function returns an error. Every callsite checks if err != nil. There’s no try/catch, no exception hierarchy, no automatic stack traces. The verbosity was jarring. A year into building services at the fintech startup, I’d changed my view. The verbosity is real and the boilerplate is real, but the explicitness surfaces things that exception-based languages hide. The question is how to handle errors well rather than just correctly. ...

September 11, 2019 · 7 min · MW

Channels vs Mutexes: When to Use Which in Go

Go has a famous concurrency proverb: “Do not communicate by sharing memory; instead, share memory by communicating.” This is good advice. It’s also misapplied regularly. Channels are not universally better than mutexes — they’re a different tool for a different set of problems. After years of Go in production, here’s when I reach for each. ...

August 7, 2019 · 5 min · MW

Building the First Production Service at a Startup: Decisions Under Uncertainty

Three months into the startup, the prototype was working and investors were asking for a production timeline. We had a Postgres database, a Python script doing the core business logic, and no infrastructure to speak of. The decision: rewrite in Go, build proper infrastructure, or ship the Python and iterate? And if we rewrite, what does “proper infrastructure” mean when you have six engineers and four months of runway? ...

June 26, 2019 · 5 min · MW

Goroutines Are Not Threads: The Mental Model Shift

The first thing every Java developer learns about goroutines is that they’re cheap. Start a million of them, no problem. The mental model that follows from this — “goroutines are threads but lighter” — is close enough to be useful and wrong enough to cause confusion. Here’s the refined model. ...

April 22, 2019 · 6 min · MW

Go for the Seasoned Java Developer: What Feels Familiar, What Doesn't

I had written maybe 500 lines of Go before the new role. Within two months it was my primary language. This is the honest transition account — not a “Go vs Java” opinion piece, but what the practical experience of switching felt like. ...

February 20, 2019 · 4 min · MW

Why I Left: On Risk, Pace, and Ownership

I left a well-paying, intellectually interesting job at a large financial institution to join a company with fewer than twenty people and less than a year of runway. My colleagues thought I’d lost perspective. My family was diplomatically concerned. Here’s the honest version of the reasoning. ...

January 9, 2019 · 4 min · MW

Schema Evolution in Avro: The Hard Lessons from Production

Three months after deploying Kafka with Avro schemas and the Confluent Schema Registry, we had a production incident where a schema change caused a downstream consumer to silently produce incorrect output — wrong field values, no error thrown, no monitoring alert triggered. That incident rewired how the team thought about schema evolution. The tools don’t protect you from all the failure modes. Understanding the rules and building organisational processes around them is what does. ...

October 4, 2018 · 5 min · MW
Available for consulting Distributed systems · Low-latency architecture · Go · LLM integration & RAG · Technical leadership
[email protected]