Simplicity
Why simplicity is the price of reliability: system stability versus agility, the virtue of boring, deleting code you own, the negative lines of code metric, minimal APIs, modularity and simple releases.
The last principles chapter is also the shortest, and it is the one every other chapter leans on. Complex systems fail in surprising ways; simple ones fail in ways you can reason about. SREs are the people who have to reason about a system at three in the morning, so they are the natural advocates for keeping it small.
The chapter argues that simplicity is not in tension with velocity. Reliability and agility are both enabled by a system that is easy to understand and change.
In one minute
- "The price of reliability is the pursuit of the utmost simplicity." A system that is too complex for its operators to understand will produce incidents its operators cannot resolve.
- Stability versus agility. A stable system that never changes has no bugs introduced, but also no features. SRE's job is to balance the two, and simplicity is what lets you move fast without breaking things.
- Boring is good. Essential complexity is inherent to the problem; accidental complexity is self-inflicted and SRE should push back on it. Surprises in code are bugs waiting to happen.
- I won't give up my code! Dead code, speculative features and unused flags make the system harder to understand. Delete them. Every line of code is a liability that must be read, tested and understood.
- Negative lines of code as a metric: a change that removes code is often the most valuable one.
- Minimal APIs. Fewer methods and arguments means fewer things to get wrong and easier reasoning about the service. Perfection is attained not when there is nothing more to add, but when there is nothing more to take away.
- Modularity. Loose coupling between binaries, and between binaries and configuration, lets teams change one part without understanding all parts. Versioned APIs let clients move independently.
- Release simplicity. Small, frequent releases are easier to understand, measure and roll back than big bundled ones.
System stability versus agility
A freeze on all changes gives a very stable system, which is why some organisations end up with change windows and launch reviews. But a system that cannot change will not survive contact with reality. The book's position is that reliability is best served not by preventing change but by making each change small, understood and reversible. SRE creates procedures and tools that increase reliability while touching developer agility as little as possible. Simplicity is the common ingredient: a simple system is easier to change safely and easier to keep up.
The virtue of boring
Unlike a novel, source code should have no surprises, suspense or puzzles. Essential complexity comes from the problem itself; a web server has to handle slow clients and that cannot be removed. Accidental complexity comes from the engineering, such as a cache layer that was added for a load that never materialised. SREs should push back on accidental complexity, and should push the systems they are responsible for to remove it when found.
Delete your code
Engineers attach emotional value to code they wrote, and leave in features "in case we need them later". The chapter is blunt: a feature that is not used is a feature that must still be understood, tested, and kept working, and it is a hiding place for bugs. Commented-out code is worse than deleted code because version control already remembers it. If the feature is needed later, it can be rewritten with the knowledge of what is actually needed.
Negative lines of code
Software bloat, the tendency for a program to grow over time, is a known failure mode. Rewarding engineers for lines added produces bloat. Google teams have found that measuring and celebrating removal, the "negative lines" metric, pushes in the right direction. A smaller codebase is easier to test, faster to build, and easier to hold in one head.
Minimal APIs
An API with few methods and few arguments is easier to understand for its consumers and easier to keep reliable for its owners. Each additional method is a commitment to maintain it forever. Deciding what not to offer is as important as deciding what to offer, and resisting the urge to expose every internal knob is a service to your future on-call.
Modularity
Loose coupling lets a change in one binary avoid changes in others. Google uses versioned APIs so that a server can offer old and new behaviour while clients migrate, and treats configuration as separate from code with its own release path. Within a binary, modularity also helps: a change to the logging module should not need an understanding of the storage module. Protocol buffers are mentioned as a concrete tool for evolving data formats without breaking consumers.
Release simplicity
A release with one change is easy to evaluate: measure before and after. A release with a hundred changes is a bisection problem when something goes wrong. Small, frequent releases are the scaled version of the scientific method, one variable at a time. The chapter closes by connecting this to everything before it: error budgets, monitoring, automation and release engineering all work better on a simple system, and the pursuit of simplicity is therefore part of every SRE's job, not a separate project.