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

What Big-Bank Engineering Taught Me About System Design

I joined the large financial institution expecting to find bureaucracy that slowed down engineering. I did find that. I also found something I didn’t expect: certain constraints imposed by regulation, scale, and risk aversion produced genuinely better engineering decisions than I’d been making at the smaller trading firm. This is about the non-obvious lessons. ...

August 23, 2018 · 4 min · MW

Event Sourcing in Financial Systems: Real Benefits, Real Costs

Financial systems are natural candidates for event sourcing. Regulators want to know the state of positions at any point in time. Audit trails are not optional. The need to replay a day’s events to debug a pricing anomaly comes up regularly. These requirements — which other domains treat as optional — map directly onto event sourcing’s core properties. That said, event sourcing in production has costs that the enthusiast literature systematically underplays. Here’s an honest accounting. ...

July 11, 2018 · 6 min · MW

Backpressure in Practice: Keeping Fast Producers from Killing Slow Consumers

The system that prompted this post was a trade enrichment pipeline. The input was a Kafka topic receiving ~50,000 trade events per minute during market hours. The enrichment step required a database lookup — pulling counterparty and instrument data — that averaged 2ms per trade. 50,000 trades/minute = ~833 trades/second. At 2ms per lookup, a single thread can handle 500 lookups/second. To keep up, we needed at least two threads and ideally a small pool. We had six threads and a queue in front of them. During a market event that pushed the rate to 200,000 trades/minute, the queue grew without bound, memory climbed, and the service eventually OOM’d. Classic backpressure failure. ...

June 14, 2018 · 6 min · MW
Available for consulting Distributed systems · Low-latency architecture · Go · LLM integration & RAG · Technical leadership
hello@turboawesome.win