The developer's pocket mentor: 100 tips across 53 topics, rewritten for the cult classic's 20th anniversary.
Why this book
Ask ten experienced developers which book they hand to juniors: this one comes up almost every time. The first edition dates back to 1999, and a good chunk of the trade's everyday vocabulary comes straight out of it: broken windows, the rubber duck, DRY. We use these expressions daily without knowing where they were coined.
This anniversary edition is not a reprint with a new cover. The authors call it a Ship of Theseus: "Roughly one-third of the topics in the book are brand new. Of the rest, the majority have been rewritten, either partially or totally" (preface). CORBA and CASE tools are gone; concurrency and security came in. What did not move: common sense. "Technology may have changed, but people haven't."
The ideas that stick
The book is a collection of 53 short topics and exactly 100 numbered tips. Here is what actually stays.
1You are a driver, not a passenger
The book opens on an observation: many developers endure their job. Boring work, outdated stack, painful team. The authors' answer fits in one question: "Why can't you change it?" (Topic 1). Our trade sits near the top of any list of careers where you hold the controls: skills in demand everywhere, remote work, decent pay. "Try to fix it. But don't try forever" (Topic 1). Martin Fowler says it with a pun the authors quote: you can change your organization or change your organization.
This stance has a flip side: responsibility. When something fails, you show up with options, not excuses (Topic 2, whose title says it all: "The Cat Ate My Source Code"). And you maintain your skills like a financial portfolio (Topic 6): invest regularly, diversify, take a few risky bets, because "they're expiring assets."
2One broken window is enough
Why does clean code rot? The book borrows the answer from criminology: an intact building stays intact, but a single broken window left unrepaired tips it into abandonment, because it tells everyone who sees it: nobody cares here. Same mechanism in code: tolerate one rotten module, and the whole team drifts toward "all the rest of this code is crap, I'll just follow suit" (Topic 3).
Tip 5 states the rule: "Don't leave 'broken windows' (bad designs, wrong decisions, or poor code) unrepaired. Fix each one as soon as it is discovered." No time? Board it up: comment out the offending code, display a "Not Implemented" message. Any action that shows someone is keeping the house.
This idea has a twin: the boiled frog (Topic 4), which never jumps out of slowly warming water. "Most software disasters start out too small to notice, and most project overruns happen a day at a time." Broken windows kill through discouragement, the frog through inattention to gradual change.
3All good design boils down to "easier to change"
This is the big addition of the second edition: a meta-rule that unifies everything else, named ETC, Easier to Change. Why is decoupling good? Because what is isolated is easier to change. Why single responsibility? Because a change in requirements maps to a single module. "A thing is well designed if it adapts to the people who use it. For code, that means it must adapt by changing" (Topic 8).
ETC is a value, not a rule: every time you save, did I just make the system easier or harder to change? Concretely, faced with two ways to write the same thing, pick the one that absorbs the next request without reopening the code:
// ✗ hard to change: adding a channel = reopening this function
function notify(channel, msg) {
if (channel === 'email') sendEmail(msg)
else if (channel === 'sms') sendSms(msg)
}
// ✓ easy to change: adding a channel = one line, ELSEWHERE
const channels = { email: sendEmail, sms: sendSms }
function notify(channel, msg) { channels[channel](msg) }
channels.push = sendPushNotif // the new channel, without touching notify()
Both work today. But the second moved the change point out of the logic: that is ETC. Its corollary (Topic 11): there are no final decisions. Treat technical choices "as being written in the sand at the beach", not carved in stone. In twenty years, standard architecture went from big central servers to clusters, cloud, microservices, serverless: betting on the stability of a technical choice is the one bet you always lose.
4DRY is not about copy-paste
DRY is probably the most quoted principle in the trade, and the authors admit it has been massively misunderstood for twenty years. The exact definition: "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system" (Topic 9). The key word is knowledge, not code.
Two functions with identical code do not necessarily violate DRY:
validate_ageandvalidate_quantityboth check that a number is positive. Same code, but two distinct business rules that will evolve separately. Merging them would be the mistake.- Conversely, the same business rule duplicated across the database, the backend and the frontend violates DRY even if the three pieces of code look nothing alike.
The anecdote that hurts: during a Y2K audit, a US state government found more than 10,000 programs, each containing its own version of Social Security number validation.
5Tracer bullets: aim with real code
How do you start a system whose exact target nobody knows yet? The classic approach builds layer by layer (all the database, then the logic, then the interface) and prays it all clicks together at the end. The book proposes the opposite: tracer bullets. In the dark, gunners load phosphorescent rounds among the real ones: they draw the actual trajectory, in actual conditions, and let you adjust your aim.
In code: first build an ultra-thin slice that crosses every layer end to end. One screen, one query, one displayed result. Not a draft: production code, just lean. "Tracer code is not disposable: you write it for keeps" (Topic 12). That is the whole difference with a prototype (Topic 13), disposable by definition: "Prototyping generates disposable code. Tracer code is lean but complete."
What the thin slice changes:
- users see something running within days;
- the team gets a skeleton to flesh out instead of a plan to imagine;
- progress reporting becomes honest: no more module "95% done" for three weeks straight.
6Inheritance is a tax
Topic 31 opens with a quote from Joe Armstrong: "You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." That is inheritance in one sentence: you inherit for one behavior, you get all the state, all the dependencies, and the dependencies of the dependencies. Inheritance is coupling: if Vehicle renames an internal method, code that uses Car breaks in silence.
The book's position is blunt: stop. Not because it is evil, but because the alternatives do better every time:
- interfaces: polymorphism without a hierarchy (
Car implements Drivable); - delegation: has-a beats is-a; the object holds a service and hands it the work;
- mixins: share a bundle of functions with no family tree.
// ✗ inheritance: for ONE method (log), you drag the whole FullService
class Invoice extends FullService {} // the gorilla and the jungle
// ✓ delegation: Invoice HAS-A logger, and hands it just what's needed
class Invoice {
constructor(logger) { this.logger = logger } // just the banana
pay() { this.logger.info('paid') }
}
Same fight against everyday coupling (Topic 28): the call chain customer.orders.find(id).getTotals().grandTotal traverses five levels of internal structure; any of them can break your line. The rule: tell, don't ask; delegate to the object that owns the data. The authors even demote their own Law of Demeter (the anti-call-chain rule they themselves made famous), star of the first edition ("the bloom has faded on that particular rose"), in favor of a simpler version: no more than one dot per access.
7The real benefit of tests is thinking about them
Here is the most unexpected passage in the book. The authors, who helped popularize unit testing, write: "we believe that the major benefits of testing happen when you think about and write the tests, not when you run them" (Topic 41). A test is the first user of your code, and it exposes design flaws before anyone else:
// the function creates its own dependency: impossible to test without a real clock
function isExpired(token) { return token.end < Date.now() }
// to test it, you'd have to actually wait, or hack the system clock…
// writing the test FORCES you to inject time → better design, for free
function isExpired(token, now) { return token.end < now }
isExpired(token, 1000) // testable in one line; the test revealed the flaw
You never ran the test, and it already paid off: trying to call the function is what showed the hidden dependency (the clock) should be injected. That is "thinking about tests" paying more than running them.
The book also documents the failure modes. In 2006, Ron Jeffries, one of the Agile Manifesto signatories, tried to solve Sudoku in strict TDD: five blog posts refining his data representation, tests green at every step, then abandonment with no solver. Peter Norvig started from the algorithm and settled it in a few lines. The book's moral: "a clever person can get sidetracked by the minutia, reinforced by the glow of passing tests."
And then there is Dave's confession: he stopped writing tests for two months, to see. Measured effect: "not a lot." Andy disagreed with publishing the sidebar. Dave's conclusion is anything but a license for laziness: "Should you write tests? Yes. But after you've been doing it for 30 years, feel free to experiment a little."
8"Agile" is an adjective, not a noun
After World War II, islanders in Melanesia built replica runways and control towers out of coconuts and palm fronds, hoping to bring back the cargo planes that had landed during the conflict. The book calls this by its name, cargo cult, and turns it on us (Topic 50): copying Spotify's or Netflix's rituals without their context is building a coconut control tower. Tip 87: "Do What Works, Not What's Fashionable."
Real agility is not a process you can buy; it is a loop (Topic 48):
- work out where you are;
- make the smallest meaningful step toward where you want to be;
- evaluate what changed, and fix what you broke.
The loop applies at every level: renaming a variable, choosing an architecture, steering a project. Weekly stand-ups, eight-week "iterations" and a scheduling tool as the only artifact: that is not agility, that is the costume. "Agile Is Not a Noun; Agile Is How You Do Things" (Tip 83).
Three things I didn't know
- The rubber duck comes from this book: "rubber ducking" goes back to Greg Pugh, a colleague of Dave's at Imperial College, who kept a small yellow duck on his terminal. With this footnote: "Earlier versions of the book talked about talking to your pot plant. It was a typo. Honest."
- Assertions in production paid hundreds of millions: a small unknown company shipped with assertions enabled and a polished error report; impossible-to-reproduce bugs surfaced on their own, and the company "was soon acquired for hundreds of millions of dollars" (Topic 25). The book adds: "Just sayin'."
- The book contains exactly 100 tips, and the last one answers the first. Tip 1: "Care About Your Craft". Tip 100: "It's Your Life. Share it. Celebrate it. Build it. AND HAVE FUN!"
My take, honestly
What strikes you first is the tone. The authors never talk down to the reader: few commandments, lots of stories. And this edition does something I have rarely seen elsewhere: it publicly corrects the previous one. The Law of Demeter gets demoted, DRY gets clarified because it was misread, and on security they write in plain letters "We were wrong." A book that owns its mistakes twenty years later earns trust for everything else.
The limit is mechanical: 53 topics in 350 pages means skimming. The tool chapters (shell, editor, text manipulation) are sensible but thin. The code examples hop from Ruby to Elixir to Clojure without any of them being dug into, and they have already aged. You read this book for the stories and the mental models, not for the code.
But that is exactly its strength: it is a book about the trade, not about a technology. One of the rare books that talks about your code, your career and your responsibility in the same breath. Many of its ideas feel obvious today; they became obvious because this book installed them. Nine developers out of ten should read it, and the tenth already has.
Odilon
Still relevant in 2026?
More than ever, which is almost embarrassing for newer books. Written before AI assistants, it still lands right everywhere it matters: "programming by coincidence" (Topic 38) describes word for word the reflex of accepting generated code you don't understand; plain text (Topic 16) became the native language of LLMs; and the postface demands two questions before every delivery: "Have I protected the user?" and "Would I use this myself?". With Tip 99 ("Don't Enable Scumbags"), it reads as if written for the deepfake era. What has aged: the Ruby and RxJS examples, the paper engineering daybook, and the tools chapter, already caught up by modern IDEs.
Who is it for?
Read it if
- You have 2 to 8 years of experience and want a pocket mentor who talks trade, not framework
- You have only ever read stack books (PHP, React, Go…) and never a book about how to work
- You lead a team and want a shared vocabulary: broken windows, tracer bullets, cargo cult
- You read the first edition: a third of the book is new, the rest was rewritten
Skip it if
- You want technical depth on one precise subject: this book skims 53 of them
- You expect modern code examples to reuse: Ruby and Elixir are not the main course
- Advice books annoy you on principle: this one literally contains 100 tips
Going further
Several ideas from this book can be practiced in my free courses: test-first thinking in the testing course, composition over inheritance in the OOP course, and attack surfaces in the web security course. In the library, Clean Code is the prescriptive cousin, TDD by Example digs into the test discussion of Topic 41, Refactoring turns ETC into named, safe moves, and A Philosophy of Software Design pushes the "easy to change" idea all the way.
Comments (0)