Navigating Org Change as an Engineer

In the years at the European financial technology firm, the engineering organisation went through three significant restructuring events: a change in engineering leadership, a shift from functional to product-aligned teams, and a consolidation of two separate engineering groups. Each one produced the same kind of disruption and the same kind of opportunities. Org change is uncomfortable. It’s also underanalysed. Most engineers treat it as something happening to them, not something to navigate actively. ...

August 16, 2023 · 5 min · MW

Go's net/http: Building Production HTTP Servers Without a Framework

Go’s net/http is frequently underrated. The ecosystem has frameworks — Chi, Gin, Echo, Fiber — and they’re fine choices, but the standard library gets you remarkably far without additional dependencies. After building several production APIs that stayed on raw net/http, here’s the honest assessment of what you can and can’t do without a framework, and the patterns that make it work. ...

July 5, 2023 · 6 min · MW

ClickHouse for Application Analytics: Fast Aggregations Without Spark

The requirement: an internal analytics dashboard showing trading activity metrics — volume, trade count, latency distributions, error rates — sliced by instrument, venue, time window, and a dozen other dimensions. Data volume: about 4 billion events per day, 90-day retention. Query pattern: ad-hoc OLAP — arbitrary group-bys, time ranges, filters. We evaluated TimescaleDB (Postgres extension), Apache Druid, ClickHouse, and “just use BigQuery.” We chose ClickHouse. After a year in production, I’d make the same choice. ...

May 17, 2023 · 5 min · MW

Database Access Patterns in Go: sqlx, pgx, and When to Use an ORM

The first question on every new Go service with a database: standard library database/sql? sqlx? pgx directly? An ORM like GORM? sqlc for code generation? The honest answer is that the right choice depends on the access pattern, the team’s SQL proficiency, and how much you value type safety at the cost of verbosity. Here’s what each option looks like in practice. ...

April 5, 2023 · 6 min · MW

Feature Flags at Scale: Beyond the On/Off Switch

The first feature flag I implemented was a boolean in a config file. Toggle it to true, deploy, feature is on. Toggle to false, deploy, feature is off. Simple. The fifteenth feature flag was a percentage rollout with user cohort targeting, metric-based automatic rollback, and a kill-switch that worked without a deployment. The gap between those two implementations is what this post is about. ...

February 28, 2023 · 6 min · MW

Writing Idiomatic Go

Go has a strong house style that experienced practitioners converge on. Some of it is enforced by gofmt and golint. The rest is transmitted through code reviews, the standard library, and writing enough Go to feel the natural grain of the language. After several years of Go, here are the patterns that mark idiomatic code and why they work. ...

January 11, 2023 · 6 min · MW

Structured Logging in Go: slog, zerolog, and What Actually Matters

Unstructured logging is a debugging tool. Structured logging is an observability tool. The difference: unstructured logs tell a human what happened; structured logs tell a machine what happened, and the machine can then tell a human efficiently. Unstructured: 2022-11-23 10:58:34 ERROR failed to process order ORD-12345 for user usr_abc: connection refused Structured: {"time":"2022-11-23T10:58:34Z","level":"ERROR","msg":"failed to process order", "order_id":"ORD-12345","user_id":"usr_abc","error":"connection refused", "service":"order-service","version":"1.2.3"} The structured log can be indexed, filtered, aggregated, and alerted on. order_id:ORD-12345 returns all logs for that order across all services. The unstructured log requires grep and hope. ...

November 23, 2022 · 5 min · MW

Postmortems as a Learning Tool: Structure, Culture, and Follow-Through

We had an incident that took down pricing for 23 minutes during the London open. High severity, real monetary impact, humbling root cause: a configuration value that worked in staging silently didn’t apply in production due to an environment variable naming collision. The postmortem process that followed was one of the better-run ones I’ve participated in. Here’s what made it useful. ...

October 5, 2022 · 6 min · MW

Memory Layout in Go: Structs, Alignment, and Cache Performance

This is the JVM false-sharing problem in a different language. The rules differ slightly, the tooling differs, but the underlying hardware constraint — cache lines are 64 bytes and sharing one across goroutines is expensive — is identical. ...

August 17, 2022 · 5 min · MW

On-Call Culture That Doesn't Burn Out Your Team

On-call has a bad reputation in software engineering, and often deservedly so. Being paged at 3am for an alert that didn’t need to wake anyone is demoralising. Being on-call for systems you didn’t build, don’t understand, and can’t fix is terrifying. Being paged multiple times a night for weeks is a health risk. But on-call done well is a powerful practice. It creates direct feedback between the reliability of what you build and the experience of carrying it. When engineers are responsible for their own systems, they ship more reliable systems. Here’s the version that worked at the European fintech firm. ...

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