Part I — Foundations
Reliability, Scalability, Maintainability
The three concerns Kleppmann uses to evaluate every data system decision in the rest of the book.
Almost every design decision in a data-intensive system comes down to trading off between three concerns. They sound like generic engineering virtues, but each one has a precise meaning worth pinning down before anything else.
Reliability
A system is reliable if it keeps working correctly even when things go wrong: hardware fails, software has bugs, humans make mistakes. Reliability isn’t “no faults happen” — it’s “the system tolerates faults without the user noticing.” That distinction matters: you design for fault tolerance, not fault avoidance, because faults are inevitable at scale.
Scalability
Scalability is the system’s ability to cope with increased load. But “load” isn’t one number — you have to describe it with load parameters specific to your system: requests per second, the ratio of reads to writes, the number of simultaneously active users, cache hit rate.
Once you can describe load, you can ask the real scalability question: if load grows by 10x, what has to change? And you measure the answer with response time percentiles, not averages.
The average (96ms) sits right in the thick of the distribution and looks perfectly healthy — it tells you nothing about the long tail of slow requests hiding to the right.
function percentile(sortedLatenciesMs, p) {
const index = Math.ceil((p / 100) * sortedLatenciesMs.length) - 1;
return sortedLatenciesMs[Math.max(0, index)];
}
const latencies = [12, 15, 14, 19, 400, 13, 16, 900, 14, 15].sort((a, b) => a - b);
percentile(latencies, 50); // p50 — typical request
percentile(latencies, 99); // p99 — the tail your worst-off users feel
Maintainability
Most of the cost of software isn’t building it — it’s the years of people working on it afterward: fixing bugs, adapting it to new use cases, operating it. Three sub-properties make a system maintainable:
- Operability — make it easy for operations teams to keep the system running smoothly (good monitoring, predictable behavior, sane defaults).
- Simplicity — manage complexity so new engineers can understand the system; fight accidental complexity (complexity that isn’t inherent to the problem, just how it happened to be built).
- Evolvability — make it easy to adapt the system to new requirements as needs change. This is the property that everything in the “Encoding & Schema Evolution” topic exists to protect.