Someone asked me the other day which programming books are worth reading. I found an old blog post of mine from 2011 (!) and my favorites have barely changed, which is telling. And with AI writing much of the code these days, I think these books are more useful, not less.

These books give you the vocabulary to talk to AI agents. On the Pragmatic Engineer podcast, Matt Pocock suggests "mining" classic books for "leading words". The ideas in these books have stood the test of time, and LLMs know them well. These terms help you describe what good looks like and spot when the output falls short.

The programming books I keep coming back to

These are the ones I recommended on my old blog over a decade ago, and I'd hand the same list to a developer today:

  • The Pragmatic Programmer (Hunt & Thomas). The one I tell everyone to start with. DRY, "don't live with broken windows," and a warning against programming by coincidence. The helicopter analogy to explain orthogonality really stuck with me. It's about the habits behind good code, which is language-agnostic.

  • Code Complete (McConnell). The deep reference on construction. How to name things, structure routines, and reason about complexity. Dense, but you can read a chapter at a time and always learn something new. Over the years I've noticed that many things I keep telling developers in code reviews have come from this book (for example the danger of global state, and the value of keeping routines short).

  • Refactoring (Fowler). A vocabulary for improving existing code in safe, small steps. The mechanical discipline here is what separates "I rewrote it" from "I improved it". Fowler's Patterns of Enterprise Application Architecture is on my reading list as well.

  • Clean Code (Martin). Another classic. It's about writing code for the people who read and maintain it. Your code is read far more often than it is written (I hope devs will keep reading code!), so self-documenting names matter. The Single Responsibility Principle (SRP) has also been one of the most important principles for me to learn and apply over the years. It overlaps with The Pragmatic Programmer's teaching on DRY code and keeping complexity low.

  • The Passionate Programmer (Chad Fowler). More about building a career you actually want, which is half the job. Parts might be outdated given where the industry is going, but back in ~2011 (my Sun/Oracle days) this book pushed me to think broader and take action.


There's also SIG's short Building Maintainable Software book (~130 pages); the essentials distilled into 10 easy-to-follow principles. Read it in 2016 for their certification, and I still refer to it.

On complexity, I also highly recommend John Ousterhout's A Philosophy of Software Design. His core argument: complexity is the root cause of many software problems, and managing it takes deliberate design. The ideas carry straight over to working with LLMs: deep modules, information hiding, and clear abstractions.

Why these matter more in the AI age

The obvious objection: who reads 300-page books when an AI will explain any concept on demand and write the code for you?

That's backwards. When AI writes the first draft, your job shifts from typing code to judging it. Is this abstraction right? Is this coupling going to hurt in six months? Did the model just write something that works but for the wrong reason?

That last one is the trap. The Pragmatic Programmer calls it programming by coincidence: code that runs, but nobody can say why.

def get_active_users(users):
    return [u for u in users if u.last_login and u.status == 1]

This works. But what is status == 1? A magic number. Six months from now, you may not know what status 1 means. Worse, if that value's meaning changes elsewhere, this code silently becomes wrong.

Better to use an enum:

from enum import IntEnum

class Status(IntEnum):
    ACTIVE = 1
    SUSPENDED = 2

def get_active_users(users):
    return [u for u in users if u.last_login and u.status == Status.ACTIVE]

It's a trivial example, but the point scales. The magic number isn't the real problem: the code works while hiding a decision nobody made on purpose. A model makes dozens of those small decisions for you, and you need the judgment to notice which ones matter (AI as an accelerator, not a compass).

The same vocabulary works in your prompts: tell an agent "keep these modules orthogonal" or "no programming by coincidence, explain why this works," and you've given it a far more precise constraint than "make this code cleaner."


LLMs can give you the snippet and explanation. Sound judgment comes from studying good ideas, applying them, reviewing real code, and seeing experienced engineers reason about tradeoffs. Reading these classics has always been part of that for me.

See also: why learn to code if AI can code and AI Is an Accelerator, Not a Compass.


Want to read The Pragmatic Programmer with other developers? I'm starting a book club ๐ŸŽ‰ - one chapter a week, starting Monday 5 October. Where? In my Python Agentic AI community. Join and you can follow along in the #books channel. ๐Ÿ“˜ ๐Ÿš€

What's the one book that changed how you think about code? This list has barely moved in 15 years. What would you add?