Posts

Year
Topic
architectureapivendor-evaluation
5 min read

What the API Returns vs What the Docs Claim

Evaluating whether one sports-data provider could replace another. The published capability matrix and the trial API disagreed, so the analysis was rebuilt on probes against the live endpoint. On deriving your consumption from code rather than memory, citing evidence per verdict, and labelling one appendix explicitly unproven.

databasespostgresidempotency
5 min read

Idempotency Belongs in the Database

A replayed store notification must not duplicate a purchase. Application-level checks are necessary and insufficient — under concurrent delivery the only thing that reliably holds is a constraint. On choosing the key, the correction we had to make to it mid-run, and why the criterion names the enforcement mechanism rather than the outcome.

testingmigrationarchitecture
6 min read

The Best Test Fixtures Were Already in Production

The monolith had been storing every raw store notification for years — 720,183 of them. That turned a rewrite from a fixtures exercise into a replay exercise. On recognising an accidental corpus, seeding an ephemeral database so the harness can never touch live data, and why storing the raw payload is the cheapest thing you will ever do.

architectureawssqs
6 min read

A Store Never Waits on Our Database

App Store and Google Play retry aggressively when you're slow, so a handler that writes to Postgres before acknowledging turns a slow query into a retry storm. On separating durability from processing, the decision record we had to supersede once we worked out what "durable" needed to mean, and why nothing may be acknowledged that isn't recorded.

testingmigrationgo
6 min read

Coverage, Not Just Agreement

A parity harness reporting 100% agreement tells you nothing until you know what it asked. On making coverage a gate rather than a statistic, declaring the gaps out loud, and scoping a replay to the deterministic core so the claim you publish is one you can defend.

gotestingmigration
7 min read

Proving a Rewrite Against 243,325 Real Purchases

Before the new service answered a single user, it computed entitlement for every purchase we had and its answers were compared offline against the monolith's. Zero disagreements. The engineering is entirely in what "zero" required: pinning the clock, writing the logic twice on purpose, and making every disagreement diagnosable without a rerun.

goobservabilityopentelemetry
5 min read

Tracing: Wired but Silent

We instrumented a new Go service with OpenTelemetry on day one and configured it to emit nothing, because no collector had been chosen. On separating a code decision from an operational one, why that beats both "add it later" and "pick a backend now", and the small print that makes it honest.

godatabasespostgres
6 min read

A Database Connection That Cannot Hurt the Monolith

The new service reads the old service's database during the shadow phase, which makes it a liability unless the connection is constrained by construction. On acceptance criteria phrased as capabilities a service must lack, why readiness and liveness must not agree about the database, and configuration that fails loudly at startup.

architecturedeploymentmigration
6 min read

A Cutover That Can Be Reversed

Reversibility as an acceptance criterion rather than a rollback plan written the night before. On phasing an extraction so each step can be undone, why "we can revert the deploy" stops being true the moment data moves, and the criterion that what stays behind must be as explicit as what moves.

architecturesystem-designdocumentation
6 min read

An Architecture Specified in Numbers, Not Adjectives

"Scalable and reliable" is not a specification — it's a wish with good PR. On writing a target architecture as mechanisms and budgets, requiring every design to name its tradeoffs alongside its boundaries, and giving every known failure mode a queryable signal before any of it is built.

architecturedatabasesdata-ownership
6 min read

Who Else Reaches Into This Database?

The blocking question for any extraction. On enumerating every service that touches a shared database with direction and evidence, discovering which entities are keyed to an external provider — and why a single-provider key quietly makes your history depend on a vendor you might replace.

architecturemicroservicesapi
6 min read

Inventorying Every Surface a Monolith Exposes

You cannot rebuild a service until you know exactly what it promises the outside world. On deriving that list from the code rather than from memory — REST routes, deployed applications, real-time channels, notification triggers — and making the inventory an artefact that tests enforce rather than a document that rots.

architectureobservabilityaws
6 min read

Quantify the Failure Before You Redesign It

"Subscribing is unreliable" was the premise for extracting a service out of our monolith. Before designing anything I measured it in the production log group — and the failure wasn't flakiness at all. It was a state machine rejecting purchases it should have accepted, 3,995 times in seven days, behind one opaque error code.

golangddiaarchitecture
14 min read

There Are No Solutions, Only Trade-Offs: DDIA Chapter 1 and Five Decisions I Actually Made

The first chapter of Designing Data-Intensive Applications, 2nd edition, isn't about techniques—it's about trade-offs. Reading it against five real backend decisions at a sports platform: monolith vs distributed, shared database vs database-per-service, systems of record vs derived data, cloud vs self-hosting, and data minimization as a liability decision.

golangstream-processinggrpc
14 min read

How DDIA's Stream Processing Concepts Apply to Real-Time Notification Systems

Connecting Designing Data-Intensive Applications' stream processing concepts—event streams, fan-out, backpressure, materialized views, and exactly-once semantics—to real architectural decisions in a live sports notification system built with Go, gRPC, and AWS SNS.

gogrpcaws-sns
7 min read

Building a High-Performance Push Notifications Service in Go

Building a push notifications service that handles millions of events reliably requires careful architectural decisions. In this post, I'll walk through how I built a notifications backend in Go that processes events via gRPC and delivers push notifications through AWS SNS.

golangarchitectureCQRS
6 min read

The Hidden Costs of CQRS in Production

What the tutorials don't tell you about eventual consistency, debugging distributed state, and the operational complexity that comes with separating reads from writes.

golangarchitectureclean-architecture
13 min read

CQRS and Event Sourcing in Go: Practical Patterns from the Trenches

Building scalable systems often means accepting that the traditional CRUD approach won't cut it. When audit requirements get strict, when read and write patterns diverge, or when you need to answer

golangdistributed-systemsarchitecture
11 min read

Managing Race Conditions in Event-Driven Systems with Go

Building distributed systems means accepting that events won't always arrive in the order they were created. When Services communicate asynchronously through message queues and event streams, race conditions become inevitable. This guide exploires practical strategies for handling out-of-order events using Go.