All insights
Architecture

Designing systems that scale before you need them to.

7 min read

“We’ll worry about scale when we have the traffic” is good advice that gets applied badly.

It is true that you should not build for a million users you do not have. It is also true that a handful of decisions made in the first month determine whether scaling later is a project or a rewrite. The skill is telling those two categories apart.

Cheap to reverse, expensive to reverse

Sort every architectural decision into one of two buckets.

Cheap to reverse: which queue library, how the cache is warmed, whether a job runs on a cron or a trigger. Get these wrong and you spend an afternoon fixing them. Do not agonize.

Expensive to reverse: how tenants are isolated, whether identifiers are globally unique, where the boundaries between services fall, what your data model considers a fact. Get these wrong and you spend a year fixing them. Agonize.

Almost all premature optimization happens in the first bucket, and almost all genuine architectural debt accumulates in the second.

API-first is a boundary discipline

Designing the interface before the implementation forces you to answer what something is responsible for before you decide how it works. That ordering is the whole benefit.

It also means the boundary exists on day one. Splitting a well-defined module into a service later is mechanical. Extracting a service from code that never had a boundary is archaeology.

Distributed by assumption, not by default

You do not need microservices. You do need to stop assuming a single process.

Write code that tolerates being run twice concurrently. Make operations idempotent where a retry is plausible. Do not hide state in a local variable that a second instance would not see. None of this costs anything up front, and all of it is painful to retrofit under load.

Observability before you need it

The first serious outage is the worst possible time to discover you cannot see inside the system.

Structured logs, request tracing and a few metrics that reflect user-visible behaviour — not CPU, but latency and error rate on the paths that matter. This is a day-one cost measured in hours, and it is the difference between diagnosing an incident in minutes and guessing for an afternoon.

What this adds up to

None of the above is about handling scale you do not have. It is about not foreclosing options. The goal is a system where growth means adding capacity rather than unpicking assumptions — and that is decided long before the traffic arrives.

Keep reading