The author, the cover and Parnas's paper
The new book was picked by a vote, and the guest reading it is Gordey from the insurance team, which is pulling a huge insurance landscape into one product with pleasant interfaces. Alexander introduces the author: known in computer science as one of the creators of the Raft consensus algorithm, he teaches the Stanford course the book grew out of, so instead of metaphysics it is full of stories about the rakes his students stepped on. Alexander wanted to read it whole after the author's hour-long talk at Google, and did so about a year ago; it did not win the club's vote at once. The twenty-two chapters were split across four meetings, and to complaints that too many were taken the hosts reply that the book is small, and one about managing complexity ought to be simple itself. The tangled arrows on the cover promise that the spaghetti on top becomes something tidy. From the introduction they single out David Parnas's 1972 paper on decomposition criteria, which compares two decompositions of an indexing system by their likely changes.
Chapter one describes two approaches to fighting complexity, the first being to make the code simpler: uniform naming, uniform use of classes, no special cases. Gordey recalls a tracker whose first commit was made when he was starting first grade: bringing 2021 practices into it would only show off what he knows and spoil life for whoever came next, so he wrote as the ancestors decreed, with static classes and helpers — and the code reads the same across the project. One of the hosts adds the well-known formulation about two ways to write a program: so simple that there are obviously no errors, or so complex that there are no obvious errors; the author is for the first and talks a great deal about cognitive complexity. The second half is about process: pure waterfall never worked, since even its author allowed for iterations, while cutting design time yields a system whose decisions looked no further than two days ahead — hard to maintain, no longer agile, never waterfall either.
The author's goals and the nature of complexity
Chapter one closes with the author's goals: to describe the nature of complexity, to show that calling a system complex is not a feeling, and to formalise what strong developers sense but cannot explain. Hence the definitions, the techniques and the red flags scattered through the book. These are not mandatory rules or silver bullets, the author says outright: if a technique does not reduce complexity in your system, it may not be for you, and sometimes the opposite one fits. Alexander expands on intuition: school maths teaches that an ugly result is probably wrong, and chess players speak of moving by hand — in time trouble strong players find the best moves in seconds, trained by a lifetime. Pulled up to the rational level, that feeling turns into an argument you can teach, rather than saying something merely feels off. It is trained by reading other people's code: almost every book the club discusses has somebody's interfaces, Unix ones included.
The definition in chapter two appeals to the participants because it is so plain: complexity is anything that makes a system harder to understand or change; if change is not easy, or it takes a month to grasp what the system does, it is complex. There are three symptoms. Change amplification: one feature spreads across five to seven places because the modules are too tightly coupled. Cognitive load: to do anything you must read documentation and write to the code's authors, in the worst case to people long gone from the company. And the worst, unknown unknowns: problems nobody warns you about because they were never written down. The book's illustration: blue links that somebody once made turn red on hover, forgotten by the time the site is repainted green. Behind the symptoms are two causes: dependencies and obscurity. Obscurity looks like a configuration parameter set to 10,000 with no clue whether it means seconds, milliseconds or hours; its price comes up in the story of an aircraft fuelled in the wrong units, which ran out mid-flight — though, it seems, everyone survived.
From tactical code to deep modules
Chapter three, working code is not enough, sets tactical programming against strategic: the first ships features as fast as possible, the second at least keeps the next change from getting harder. The product manager calls the tactical developer a hero: he saved the day today, tomorrow and the day after; the business adores him, engineers hate him for taking the laurels while they clear up — and once a whole team takes up the style the project is beyond saving. The author draws a chart of progress over time for both approaches, but no numbers stand behind it: at that same Google talk, Alexander recalls, he answered that such data is hard to collect and this is his empirical reasoning. Gordey asks whether adding a feature ever became physically impossible; Alexander recalls a platform for retail customers with a three-week release cycle and a week of manual regression, where his team of three sawed off a branch on its own infrastructure with traffic balanced to it, pulling in shared code every two months, because otherwise it misfired everywhere.
Chapter four is about depth: a module hides as much as possible inside and exposes the simplest interface it can; by module the author means a function, a class and an application alike. Alexander recalls Vlad Khononov stretching the same metaphor onto services, and offers a counter-example — complex logic on function as a service, where every call and dependency sticks out and no abstraction is left. For the author an interface is wider than a signature: it includes the informal part no compiler checks — how to use the method and what side effects it has; hence the teasing of Java getters and setters, which hide nothing. Chapter five covers information hiding: it simplifies the interface and lets a module change without breaking neighbours; the red flags are information leakage and temporal decomposition, where the order of calls dictates the system's structure. Chapter six explains why general-purpose modules are deeper: students wrote separate operations for Delete and Backspace when one is enough — delete a given range of characters. The slide about where to move specialised code turned out to belong to chapter eight, which the next meeting will cover.
What to take away
- 01Complexity is anything that makes a system harder to understand or change; its symptoms are change amplification, cognitive load and unknown unknowns, its causes dependencies and obscurity.
- 02Uniformity sometimes beats modern practice: in an old tracker the guest wrote in the style of its earlier authors so the whole project reads the same way.
- 03Strategic programming pays off even in a startup: an acquaintance of Alexander's laid foundations, load tests and security at once, and passed due diligence more easily than later-stage companies.
- 04A deep module hides more than it shows: an interface is not only a signature but also a description of side effects, and a method built for one special case is a red flag.