The Pragmatic Programmer Summary: What Holds Up After 27 Years (And What Doesn’t)

fagnerbrack.com ~6 min read
View original
  • best
Summary (TL;DR)
The Pragmatic Programmer by Andrew Hunt and David Thomas came out in 1999 and most of its advice still holds up. The book covers continuous learning, DRY, orthogonality, design by contract, incremental development, automation, code reviews, pair programming, testing, technical debt, and adaptability. Three tips no longer hold up as written: DRY as a hard rule, feedback that waits for code review, and automation without a justified return. The author argues DRY can create coupled systems, so wait for duplication to appear three times before abstracting. Pair programming gives earlier feedback than a late review and helps both devs build a mental model. Automate only when the return on investment justifies the effort.

The Pragmatic Programmer Summary: What Holds Up After 27 Years (And What Doesn’t)

“The Pragmatic Programmer: From Journeyman to Master” came out in 1999. Andrew Hunt and David Thomas wrote it for developers who shipped software on CDs. People keep recommending it 27 years later, and after that much time the question is which parts earned it and which parts you can skip.

This post is a summary of The Pragmatic Programmer with verdicts attached. Most of the advice holds up. Three tips don’t hold up as written: DRY as a hard rule, feedback that waits for the code review, and automation without a justified return. I push back on each one in its section, based on my own experience.

Continuous learning

The authors emphasize the importance of being a lifelong learner, as the field of software development is always evolving. Developers should invest in their knowledge by reading books, attending conferences, and learning new programming languages.

A software developer decides to learn a new programming language, programming technique (TDD, Design Pattern, programming paradigm), or problem-solving technique each year, expanding their knowledge and skills. They also attend workshops, webinars, and conferences to stay updated with industry trends and innovations.

DRY principle

“Don’t Repeat Yourself” is a foundational concept in the book, which encourages developers to avoid duplicating code or functionality. By adhering to the DRY principle, developers can reduce complexity, minimize errors, and make maintenance easier.

Instead of writing the same code snippet for handling user authentication/authorisation in multiple parts of an application, the developer creates a reusable function that can be called whenever user authentication/authorization is needed. That could be a library shared among many teams.

Please note abusing DRY can lead to highly coupled systems, so it's necessary to find a balance between DRY and WET (Write Everything Thrice). If you're not sure, wait for duplication to happen at least 3 times where changes in one place require the exact same change in 2 other places.

The cost of guessing wrong grew since 1999. Back then a bad abstraction stayed inside one codebase. Today it ships as a shared package across teams and services, and unwinding it means coordinating changes in code you don’t own.

Orthogonality

This concept suggests that components within a system should have a single, well-defined responsibility and should operate independently of each other. This approach minimizes dependencies and side effects, making systems easier to understand and maintain.

The developer designs a system where the BillingComponent, NavigationComponent, and CustomerReminder back-end cronjob has a single responsibility and can be modified independently, reducing the risk of unintended side effects when changes are made.

This is similar to the "S" part of SOLID: The Single-responsibility principle by Uncle Bob (Robert Cecil Martin).

Design by contract

The authors advocate for clearly defining the expectations and responsibilities between software components. By specifying input and output conditions, developers can create more robust and reliable software.

In a software library, the developer clearly documents the expected input types, ranges, and output formats for each function. This ensures that other developers using the library understand how to interact with the functions and avoid unexpected behaviour. That documentation can be through a document but should preferably use typing or self-documenting code through the art of Duck Typing, a common practice in the JavaScript world for those who don't use TypeScript.

Incremental development

The book recommends using an iterative and incremental approach to software development. By breaking tasks into smaller, manageable pieces and frequently integrating code, developers can identify and resolve issues early in the process.

Here's an example of a team I've worked with in the past, a team working on a payment system for the app. They breaks the problem into smaller tasks:

  1. Integrate with the provider using Postman.
  2. Send the information through the UI with basic HTML input elements.
  3. Implement the design of the screen using CSS.
  4. Implement a retry mechanism preventing double charges so you don't get a call from your CEO
  5. Integrate the screen into the website's global navigation.

That allows the team to focus on completing and integrating one task at a time and parallelize where necessary; the software is always in a working state, albeit not in a very useful state for the final user. This allows the team to identify and fix issues early, preventing a buildup of bugs and reducing overall development time. It also allows you to deploy the code to production under a feature flag so that you can test all your delivery processes.

This tip held up. I wrote about the same idea in Code Less, Think More… Incrementally, and I still split work this way in 2026.

Automate repetitive tasks

The authors encourage developers to automate repetitive tasks, such as testing, building, and deployment. Automation can save time, reduce errors, and ensure consistency across the development process.

A developer sets up automated scripts to run tests, compile code, and deploy updates, ensuring that these tasks are performed consistently and efficiently while minimizing manual errors.

The third tip that doesn’t hold up is this one, taken as a blanket rule. Don’t automate a task where the Return on Investment can’t be justified.

Code reviews and pair programming

The book highlights the benefits of code reviews and pair programming, as these practices can help identify issues, share knowledge, and foster a collaborative environment.

Two developers work together on a challenging piece of code, sharing ideas and insights. After completing the task, they review each other’s work, identifying potential issues and learning from each other’s approaches.

However, the review might come too late, and one of the devs might have built up code on an assumption that goes in the wrong direction. Pair Programming the task from beginning to end in one screen and one task allows for the feedback to happen earlier and for both devs to build a mental model of the problem so they can perform better over time.

Testing and quality assurance

The authors emphasize the importance of thorough testing and quality assurance processes. By writing and maintaining comprehensive test suites, developers can catch errors early and ensure the stability and reliability of their software.

The development team writes and maintains a comprehensive test suite, including unit tests, integration tests, and end-to-end tests. This helps catch errors early and ensures that new features do not introduce regressions.

See also TDD.

Manage technical debt

The book advises developers to be aware of and manage technical debt, which is the accumulation of suboptimal design decisions and shortcuts taken during development. By addressing technical debt regularly, developers can prevent it from becoming unmanageable and hindering future work.

The team regularly reviews their codebase, identifying areas where shortcuts or suboptimal design decisions were made. They allocate time to refactor and improve the code, preventing technical debt from becoming unmanageable and slowing down future development.

This advice held up too. Technical debt is not really a bad thing if you use it correctly.

Adaptability and pragmatism

The authors encourage developers to be adaptable and pragmatic in their approach to problem-solving. Rather than rigidly adhering to specific methodologies or tools, developers should be open to new ideas and willing to change course when necessary.

When a new project management tool gains popularity, the development team evaluates its features and potential benefits. They decide to adopt the new tool, even though it requires changing their established workflow because it offers significant improvements in efficiency and collaboration.

Twenty-seven years on, most of “The Pragmatic Programmer” still earns the recommendation. Wait for the third copy before you apply DRY, get feedback from pairing instead of a late review, and automate only when the return justifies the effort.

If you liked this, you might like readplace.com, built for exactly this kind of reading.

Thanks for reading. If you have some feedback, reach out to me on LinkedIn, Reddit or Github.