Post 01 · DDIA Ch. 1–2

Foundations

Twitter serves ~300k timeline reads/s and ~12k tweets/s — same product, opposite extremes. Before you can build for that, you need three tools: a way to see the load, a way to measure it honestly, and a data model that fits the shape.

Six visuals. Two chapters. One story: what a data-intensive app actually has to survive.

Twitter's timeline is a read-heavy workload sitting on top of a write-heavy social graph. Two ways to build it: fan-out on read (join followers' tweets at query time — cheap writes, expensive reads) or fan-out on write (materialise each user's timeline on every tweet — cheap reads, expensive writes for anyone with millions of followers). Neither is right; Twitter runs a hybrid.

Averages hide the users who suffer. If p50 is 10ms and p99 is 2s, one in a hundred requests is a full-page freeze — and those requests are usually the same power users, hitting the biggest queries, over and over. Percentiles are how you see the tail; the tail is where your reputation lives.

Understanding Percentiles

The average sits above p50, dragged up by the tail.

1500ms 250ms 50ms p50 p99 p99.9
0 / 3
p50 (Median) 50% of users
typical request 50ms
p99 (99th) 1 in 100 users
slow / mild queueing 250ms
p99.9 (99.9th) 1 in 1000 users
tail events users feel 1.5s

One page makes N backend calls. Its p99 is the slowest of N. A "1 in 100" event fires per call, not per page.

Takeaway

Average latency lies. p99 is what your users feel.

Everything in the book hangs off three words: reliability (works correctly under adversity), scalability (keeps working as load grows), maintainability (the next engineer can extend it without dread). Every trade-off in the coming chapters is a bet on which of the three matters most right now.

Three pillars of a data-intensive app.

01

Reliability

the system keeps working correctly, even when things go wrong.

HARDWARE FAULTS disks die, RAM flips, racks lose power.
SOFTWARE ERRORS runaway processes, cascading bugs, bad configs.
HUMAN ERRORS operators are the top cause; design to make mistakes safe.
02

Scalability

the system copes when load grows.

LOAD requests/s, follower fan-out, read/write ratio.
PERFORMANCE use percentiles: p99, p99.9. averages hide the tail.
COPING vertical vs horizontal. stateless vs stateful.
03

Maintainability

people can keep working on the system.

OPERABILITY make it easy for ops to keep the lights on.
SIMPLICITY manage accidental complexity.
EVOLVABILITY bend to new requirements without breaking.

everything in ddia hangs off these three concerns. the rest of the book is one long argument about how they trade off.

Reliability, scalability, maintainability — the framework says what you're optimising for. The next question is what you're storing. The shape of your data picks the database.

A résumé looks like a nested document: one person, arrays of jobs, arrays of schools. Store it as JSON and reads are one lookup. Normalise it into SQL tables and reads become joins — but IDs stay stable and referential integrity is free. Turn it into a graph and connections between people become first-class. Same data, three physical shapes, three different sets of queries that are cheap.

The moment your data has real many-to-many relationships — people who share employers, tags that belong to many posts, friends of friends — the document model starts hurting. Joins that the relational model does in one query become application-level nested fetches, and consistency across the copies of a duplicated field becomes your problem. Connectedness pushes you toward relational or graph.

The many-to-many problem

Same edit, two data models.

DOCUMENT 0 writes
"user": "User 1",
"company": "Aetna"
"user": "User 2",
"company": "Aetna"
"user": "User 3",
"company": "Aetna"
RELATIONAL 0 write
companies
id42 name"Aetna"
positions
user1 company_id42 "Aetna"
user2 company_id42 "Aetna"
user3 company_id42 "Aetna"

Three writes vs one. Documents still win on read locality: one lookup returns the whole record.

No universal winner. The decision is: how tree-like is my data, how connected is it, and how often does the shape change? Documents win when reads are one-object, writes are self-contained, and the schema wanders. Relational wins when joins are the norm and constraints matter. Graph wins when the interesting questions are about paths between things.

Pick by shape.

01

Document

one-to-many, self-contained.

PICK WHEN the record has clear boundaries; you read it as one unit.
STRUGGLES AT joins, shared entities, many-to-many.
EXAMPLES MongoDB, DynamoDB, CouchDB.
02

Relational

many-to-many with shared entities.

PICK WHEN entities are referenced from many places; you edit them in one place.
STRUGGLES AT deep, variable graph traversals; free-form nested docs.
EXAMPLES Postgres, MySQL, SQL Server.
03

Graph

highly connected, variable depth.

PICK WHEN the interesting query is a traversal: friends of friends, dependency chains.
STRUGGLES AT sheer volume of flat, tabular data.
EXAMPLES Neo4j, Datomic, JanusGraph.

Same résumé, three physical shapes. Pick by how connected your data is.

Takeaway

The shape of your relationships picks the database. Not hype.