Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Start Simple and Evolve
HLD

Start Simple and Evolve

Ship the simplest architecture that meets today's requirements, then evolve on evidence — the growth path every big system actually took.

The Principle

Design for today’s scale with a named path to tomorrow’s — not for an imagined future. Every famous large system passed through a boring stage: Facebook was one PHP monolith on MySQL; Amazon started as a single service; Instagram famously served millions of users on Django + Postgres with a tiny team.

The skill being tested in design interviews is not “draw the final billion-user architecture.” It is: start at the correct simple point, then evolve it step-by-step under pressure, naming the trigger that forces each step.

The Canonical Evolution Path

 STAGE 1: BASELINE                    STAGE 2: READS GROW
 ┌────────┐   ┌─────┐   ┌────────┐    ┌────────┐   ┌─────┐   ┌────────┐
 │ Client │──►│ App │──►│ Postgres│    │ Client │─►│ CDN │─►│App × N │
 └────────┘   └─────┘   └────────┘    │        │  └─────┘   │  ┌────┐│
                                      └────────┘            │─►│ LB ││
 works to ~10k users                                        │  └────┘│
                                                            └───┬────┘
                                                    reads hit DB hard

        STAGE 4: WRITE SCALE ◄────────────────── STAGE 3: ADD CACHE/REPLICAS
        ┌──────────┐                             App × N → Redis cache (hot reads)
        │ Sharded  │                                     → read replicas
        │ Postgres │   trigger: single writer            trigger: cache misses +
        └────▲─────┘   saturates, replicas              replica lag visible
             │         can't help writes
        Queue buffers heavy writes,
        async workers smooth spikes

Each arrow has a trigger and an action. That pairing — not the final diagram — is the design knowledge.

Trigger → Action Table

Trigger (evidence, not vibes)Action
DB CPU high on SELECTs; static assets dominate bandwidthAdd CDN
Repeated identical queries; DB still bottleneck after indexesAdd cache layer
Read load saturates primaryAdd read replicas (watch replication lag)
Single writer near saturation; replicas can’t help writesShard or move hot tables to write-optimized store
Request timeouts during traffic spikes; users blocked on slow workQueue + async workers
One service’s deploy cadence blocks others; teams collideExtract that service

Why Not Start at Stage 4?

The end-state architecture carries permanent taxes:

  • Sharding from day one: no data to shard, but every query now routes through partition logic; resharding later would be cheaper than living with premature shards.
  • Microservices day one: distributed tracing, eventual consistency, and network debugging before product-market fit proves the product deserves them.
  • Kafka + Flink + K8s + multi-region: operational surface exceeds team size; the system manages the engineers instead of vice versa.

Complexity added before evidence arrives is complexity that never leaves.

What “Evolutionary” Design Requires Up Front

Simple does not mean naive. Two cheap early decisions keep evolution possible:

  1. Stateless app tier — horizontal scaling later must be trivially possible.
  2. One clear write path per data type — sharding later needs a single owner to split.

Conversely, some choices actively block evolution: business logic inside stored procedures, in-process sessions, direct cross-table joins everywhere.

Interview Framing

The highest-signal interview pattern: draw the boring baseline, state its capacity (“this handles roughly X”), then walk the trigger→action chain as the interviewer raises load. Answering “we’d start with microservices and Cassandra” without triggers reads as memorized end-states — the opposite of design judgment.

My Private Notes

Notes are auto-saved locally to this device.