DEV Community

Cover image for Kernighan, Fowler, Torvalds: 7 Debugging Quotes Every Senior Still Repeats
Ken Imoto
Ken Imoto

Posted on

Kernighan, Fowler, Torvalds: 7 Debugging Quotes Every Senior Still Repeats

Some engineering lines refuse to fade.

They survive because every senior ends up repeating them in code review, year after year, usually on a Thursday afternoon when a junior ships something that works and shouldn't.

I spent the last few months decoding a hundred of these for a short Kindle book. Below are seven, from three names that keep surfacing when the topic is debugging: Brian Kernighan, Martin Fowler, Linus Torvalds. Each quote has its original public source. Each one has a modern code-review move I use when I quote it.


1. "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?"

Brian Kernighan & P. J. Plauger, The Elements of Programming Style, 2nd ed., ch. 2, 1978.

Half a century later, this is the single question I ask when a PR shows up with a one-line regex, a nested ternary, or a reduce that collapses six operations into one line. Not "is it correct." How will you ever debug it?

The AI-pair-programming era rediscovers this one every quarter. Give Claude Code or Copilot a prompt like "make this shorter" and it will happily compress four lines into one with a currying trick. The code works. Six months later, nobody (human or model) can rewrite the same function from scratch, because the compressed form hides the steps.

My review rule: if the author needs more than one sentence to explain what the line does, split it. I know, because I've been that author more than once.


2. "The most effective debugging tool is still careful thought, coupled with judiciously placed print statements."

Brian Kernighan, Unix for Beginners, 1979.

I used to be embarrassed by println debugging. Then I watched enough senior engineers reach for it before a debugger that I stopped apologizing.

The quote still holds, with one update. The tool today is console.log, fmt.Println, print(), or whatever your runtime offers, plus a tail of structured logs. Debuggers help when you can reproduce the bug and the state is static. Print statements help when the bug lives in a flow, in production, or at a boundary the debugger can't easily cross: gRPC, serverless cold start, worker queues, flaky async tests.

The actual skill the quote names is careful thought. The prints are only useful once you've guessed where to put them.


3. "Controlling complexity is the essence of computer programming."

Brian Kernighan & P. J. Plauger, Software Tools, p. 319, 1976.

A junior and a senior will both call code "complex." The junior usually means "I don't understand this yet." The senior usually means "nobody will ever understand this again, including the person who wrote it."

I keep this quote pinned when reviewing refactors. The question isn't "is this clever." It's "does the next on-call engineer, at 2 a.m., with no context, have a chance?" Most production bugs I've chased started as a cleverness-driven refactor that added coupling the diff didn't name.

Complexity accrues. Most PRs make it worse. The ones that make it better are rare and should be celebrated.


4. "Any fool can write code that a computer can understand. Good programmers write code that humans can understand."

Martin Fowler, Refactoring: Improving the Design of Existing Code, p. 15, Addison-Wesley, 1999.

This is the one line of Fowler's that engineers who've never read Refactoring can still recite. Fair, because it compresses the whole book: tests exist so humans can change code; names exist so humans can read it; small methods exist so a human can hold one in their head.

The habit I lifted from this: whenever I'm tempted to leave a comment explaining what a block does, I rename or split instead. If the code reads without the comment, the comment was a smell.

LLM code generators love long comments. Rename the function.


5. "If it hurts, do it more often."

Martin Fowler, martinfowler.com, FrequencyReducesDifficulty.

Fowler surfaces this as one of his favorite soundbites. The surface reading sounds like masochism. The real reading: if deploys are painful, deploy daily; if merges are painful, merge every hour; if integration tests are painful, run them on every push.

The pattern survives the current stack. Painful AI-code reviews? Review each PR as soon as it opens, not once a day in a batch. Painful dependency bumps? Automate them nightly instead of quarterly. Painful incident post-mortems? Hold them within 48 hours while people still remember.

Every time I've watched a team avoid a painful activity, the pain compounded. Fowler's rule flips the compounding.


6. "Talk is cheap. Show me the code."

Linus Torvalds, Linux Kernel Mailing List, 25 Aug 2000.

Linus wrote this in the middle of a kernel discussion where someone was proposing changes without an implementation. The adage has outlived its original thread.

Modern application: architecture debates on Slack where no participant has opened the file in question. Design reviews on a tool nobody has prototyped. "We should migrate to X" threads with no benchmark attached. The quote doesn't ban design. It bans debating before anyone has sampled the code. Open a branch. Commit a 30-line proof of concept. Attach the diff to the thread.

I keep a text expander snippet with this quote. I pull it out maybe once a month, and every time it ends the thread in under an hour.


7. "Bad programmers worry about the code. Good programmers worry about data structures and their relationships."

Linus Torvalds, Git mailing list, 2006. (git mailing list via LWN, 2006-07-27)

The underrated debugging quote on this list. Most bugs that reach production aren't in the control flow. They're in the shape of the data: a nullable field someone assumed was present, a one-to-many relationship someone modeled one-to-one, a cache that lies about freshness, a queue that quietly drops ordering guarantees.

When a bug surfaces, the first question I ask is what the data actually looks like right now, and what the code assumed it would look like. More than half the time, the fix is a schema change or a type refinement, and the logic was never wrong. I lost a weekend last year "fixing" logic that was fine — the schema was lying about a nullable column.

Modern echo: in LLM pipelines, the hardest bugs don't live in the prompt. They live in the context layout the prompt silently depends on: what the retriever returned, in what order, with what metadata.


Why these seven, out of a hundred

The engineering world has more quotes than it has reviewed PRs. These seven survive translation across stacks: a 1978 line is still live in a 2026 Claude-Code-generated diff.

If this slice landed, the full set (100 quotes across 10 chapters — code aesthetics, bugs and failure, design, teams, innovation, learning, craftsmanship, open source, the AI era, and an engineer's life) is in 100 Engineering Quotes Decoded. One decoded quote at a time, so you can read a decoding on a coffee break and bring it into code review the same day.

Top comments (0)