Classic Software Engineering Essays: Key Takeaways
Oct 13, 2026 · @Alex Shank
This table covers 26 classic essays, papers and talks, each read from its source, with up to three takeaways apiece. A blank takeaway cell means the piece really makes only one or two points.
Joel Spolsky (Joel on Software)
| Essay | Takeaway 1 | Takeaway 2 | Takeaway 3 |
|---|---|---|---|
| The Law of Leaky Abstractions (2002) | Every non-trivial abstraction leaks: the layer underneath eventually shows through, as with TCP on a dead link, slow SQL plans, or NFS outages. | Abstractions save time while working, not while learning; you still have to understand what they hide to debug them. | So as tools get higher-level, becoming a proficient programmer gets harder, not easier. |
| Things You Should Never Do, Part I (2000) | Rewriting from scratch is the worst strategic mistake a software company can make; Netscape handed competitors three years. | Old code looks messy because reading code is harder than writing it; the ugly parts are usually hard-won bug fixes. | Fix bad architecture, slow spots and ugly naming incrementally; a rewrite has no reason to turn out better. |
| The Joel Test (2000) | Twelve yes/no questions rate a team in minutes; a score of 10 or below signals serious problems. | Fix bugs before writing new code: bugs get costlier with age, and only a bug-free backlog makes schedules predictable. | Protect flow: quiet offices and the best tools pay off, since one interruption can cost about 15 minutes. |
| Fire and Motion (2002) | The hard part of productivity is starting; once you are in flow, momentum keeps you going. | Move forward a little every day; steady progress keeps time on your side. | Much of what competitors and platform vendors ship is cover fire; don't spend your cycles just reacting to it. |
Classic essays and papers
| Essay | Takeaway 1 | Takeaway 2 | Takeaway 3 |
|---|---|---|---|
| No Silver Bullet — Fred Brooks (1986) | Software difficulty splits into essential (designing the conceptual structure) and accidental (expressing it); past big gains mostly removed accidental difficulty. | Because the essence dominates, no single technique will give a 10x gain; complexity, conformity, changeability and invisibility are inherent. | Attack the essence instead: buy rather than build, prototype to refine requirements, grow systems incrementally, and develop great designers. |
| The Rise of Worse Is Better — Richard Gabriel (1989) | The "New Jersey" style puts implementation simplicity above interface simplicity, correctness and completeness. | A simple, roughly 50% solution spreads like a virus (Unix, C) and is later improved toward 90%. | The "right thing" built first tends to be big, slow and late, but the half-solution you ship must still be basically right. |
| Out of the Tar Pit — Moseley & Marks (2006) | Complexity is the root problem, and mutable state is its biggest cause, followed by control flow and code volume. | Unlike Brooks, they argue most complexity is accidental: avoid it where possible and separate what remains. | Their proposed architecture keeps essential state as relations, logic as pure functions, and performance tweaks as separate hints. |
| Reflections on Trusting Trust — Ken Thompson (1984) | A compiler can be trojaned to re-insert its own backdoor when it compiles itself, leaving no trace in any source code. | You cannot trust code you did not create entirely yourself; source-level review won't catch this. | The lower the level of the tool (assembler, loader, microcode), the harder such a backdoor is to detect. |
| Go To Statement Considered Harmful — Edsger Dijkstra (1968) | People reason about static text far better than processes unfolding in time, so the program text should map simply to its execution. | Unrestricted goto destroys any useful way to describe where a program is, while structured constructs preserve it. | |
| The Cathedral and the Bazaar — Eric Raymond (1997) | Treating users as co-developers is the fastest route to improving code and finding bugs. | Release early and often to keep contributors engaged and feedback flowing. | "Given enough eyeballs, all bugs are shallow": debugging parallelizes across a large base of testers. |
The Cathedral and the Bazaar row draws on the introduction and the two chapters where these lessons appear.
Systems and distributed computing
| Essay | Takeaway 1 | Takeaway 2 | Takeaway 3 |
|---|---|---|---|
| Fallacies of Distributed Computing — Peter Deutsch et al. (1994) | First-time distributed system builders assume the network is reliable, zero-latency, infinite-bandwidth, secure, static, singly administered, free and homogeneous; all eight assumptions fail in the long run. | ||
| Latency Numbers Every Programmer Should Know — Jeff Dean / Peter Norvig | Operation costs span about nine orders of magnitude: L1 cache 0.5 ns, main memory 100 ns, same-datacenter round trip 0.5 ms, disk seek 10 ms, California to the Netherlands and back 150 ms. | Sequential reads are far cheaper than seeks: 1 MB takes about 250 µs from memory, 1 ms from SSD and 20 ms from disk. | |
| The Log — Jay Kreps (2013) | An append-only, totally ordered log underlies databases, replication and consensus, and tables and logs are duals of each other. | A central log turns O(N²) point-to-point data pipelines into O(N) integrations, with each consumer reading at its own pace (Kafka). | Stream processing is just processing logs, and many data systems can be factored into a log plus a serving layer. |
| Notes on Distributed Systems for Young Bloods — Jeff Hodges (2013) | What sets distributed systems apart is frequent partial failure, not latency, so design for failure. | Coordination between machines is very hard: avoid it, and build in backpressure and partial availability. | Metrics, reported as percentiles rather than averages, are the only way to know what production is really doing. |
| Falsehoods Programmers Believe About Names — Patrick McKenzie (2010) | Every common assumption about names (one canonical form, fixed length, one character set, unchanging, unique, a first/last split) is wrong, so systems should not constrain them. |
Design and craft
| Essay | Takeaway 1 | Takeaway 2 | Takeaway 3 |
|---|---|---|---|
| Simple Made Easy — Rich Hickey (2011 talk) | Simple means not intertwined, which is objective; easy means familiar or near at hand, which is relative. Don't conflate them. | Intertwining ("complecting") limits what you can reason about; tests and types are guardrails, and chasing ease over simplicity slows you down over time. | Choose simpler constructs: values over mutable state and objects, functions over methods, plain data like maps and sets, queues, and declarative rules. |
| Choose Boring Technology — Dan McKinley (2015) | Each company gets about three "innovation tokens"; spend them on your actual mission, not on infrastructure. | Boring technology's failure modes are well understood, while new technology carries far more unknown unknowns. | Optimize globally: every added technology brings ongoing operational cost, so first ask how to solve the problem with the current stack. |
| Write Code That Is Easy to Delete, Not Easy to Extend — tef (2016) | Treat lines of code as lines spent: code that is easy to delete keeps maintenance cheap. | Repeat yourself to avoid creating dependencies, and isolate the hard-to-write and likely-to-change parts from everything else. | Sometimes one big lump is better, since one big mistake is easier to delete than many small interleaved ones. |
| Parse, Don't Validate — Alexis King (2019) | Parse input into types that carry what you checked (for example a NonEmpty list) instead of validating and throwing that knowledge away. | Make illegal states unrepresentable, and push the burden of proof to the system's boundary. | Scattered validation ("shotgun parsing") risks acting on input that is only partly valid; parse fully before acting. |
| The Wrong Abstraction — Sandi Metz (2016) | Duplication is far cheaper than the wrong abstraction. | Shared code rots as each new case adds a parameter and a conditional, and sunk-cost thinking keeps it alive. | To recover, inline the abstraction back into its callers, delete what each doesn't use, then re-extract. |
| What Color Is Your Function? — Bob Nystrom (2015) | Async functions are a "color" that spreads: they can only be called from other async code and compose poorly. | Promises and async/await reduce the pain but still split the codebase into two worlds. | Languages with threads, goroutines or fibers (Go, Java, Lua, Ruby) avoid function colors altogether. |
| Teach Yourself Programming in Ten Years — Peter Norvig | Real expertise takes about ten years of deliberate practice, not 24 hours or 21 days. | Learn by doing: write programs, read others' code, and work alongside and after other programmers. | Learn about half a dozen languages across paradigms, and know how long the machine takes to do things. |
The tef row is built from excerpts of the post found through search, because the site blocks automated reading.
Career and culture
| Essay | Takeaway 1 | Takeaway 2 | Takeaway 3 |
|---|---|---|---|
| On Being a Senior Engineer — John Allspaw (2012) | Seniority means maturity: seek out criticism of your designs, make estimates, and state trade-offs explicitly up front. | Whether people want to work with you largely decides your success; mature engineers raise the skills of those around them. | Stay aware of cognitive biases such as hindsight bias and the planning fallacy, and don't care who gets credit. |
| Beating the Averages — Paul Graham (2001) | Programming languages differ in power, and you should generally use the most powerful one you can. | The "Blub paradox": programmers can't see the power of languages above their own, because their language shapes how they think. | For a startup, a technical edge that competitors don't understand (Lisp, for Viaweb) is a real weapon. |
| Maker's Schedule, Manager's Schedule — Paul Graham (2009) | Makers need time in blocks of at least half a day, while managers work in one-hour slots. | One meeting can wreck a maker's whole afternoon, or even a day. | Cluster meetings where they don't interrupt, such as office hours at the end of the day. |
| Programming as Theory Building — Peter Naur (1985) | Programming is building a theory (a mental model) in the programmers' heads; code and documentation are secondary, lossy records of it. | A program "dies" when the team holding its theory disperses, and reviving it from code and docs alone is nearly impossible. | Programmers are not replaceable parts, and no method can substitute for the theory they hold. |
Sources
Each essay title above links to the copy that was read. Some came from mirrors or transcripts because the original site blocked automated reading or had no extractable text:
- Worse Is Better: MIT 6.033 mirror (dreamsongs.com blocked)
- Go To Statement Considered Harmful: EWD215 transcription, the typescript published in CACM
- Simple Made Easy: talk transcript
- Programming as Theory Building: full-text transcription (the scanned PDF had no readable text)
- The Cathedral and the Bazaar: introduction, The Importance of Having Users, Release Early, Release Often
- Fallacies of Distributed Computing: the list as published and Wikipedia