Buy The Pragmatic Programmer book on Amazon


The Pragmatic Programmer is found at the top of most engineers' recommended reading lists, and for good reason.

Being an effective programmer goes beyond writing functioning software. The book describes the attitude, style and philosophy that experienced (pragmatic) programmers follow to write robust, maintainable and performant software that ‘delights’ end-users.

The content is organised into self contained chapters that address the common challenges of writing maintainable software: from requirements gathering to coding an application and long term maintenance.

Along the way, the authors provide 97 actionable tips to apply to your daily workflow and next project.

Top Quotes

“Your knowledge and experience are your most important day-to-day professional assets. Unfortunately, they’re expiring assets.”

“You Can’t Write Perfect Software. […] Knowing that no one writes perfect code, including themselves, Pragmatic Programmers build in defenses against their own mistakes.”

“If you can’t describe what you are doing as a process, you don’t know what you’re doing.”

“Rather than construction, software is more like gardening—it is more organic than concrete. "

“Testing Is Not About Finding Bugs. We believe that the major benefits of testing happen when you think about and write the tests, not when you run them.”

Key Takeaways

Mindset and attitude are just as important as your ability to write code

Take Responsibility for the quality and delivery of code

Instead of excuses, provide options. Don’t say it can’t be done; explain what can be done to salvage the situation.

“Don’t leave broken windows”

The authors draw parallels between poorly written source code to ‘broken windows’ in a run-down neighbourhood. Apparently, a single broken window is the biggest catalyst for further damage to a building. Broken windows indicate no one is looking after the premises and invite further antisocial behaviour.

Look for ‘broken windows’ (obvious bugs, poor design, improper formatting etc.) in your source code. When you spot issues, own and fix them quickly.

Don’t let ‘broken windows’ fester in the code base. They signal to others that new code does not have to be of a high standard. Once there is a ‘broken window’ in your code base, the project quality will deteriorate.

Conversely, if you find yourself on a project where the code is pristinely beautiful—cleanly written, well designed, and elegant—you will likely take extra special care not to mess it up.

Invest regularly in your knowledge portfolio

Your knowledge and experience are your most important day-to-day professional assets. Unfortunately, they’re expiring assets.

Make an effort to continually read and upskill on new technologies (at least have an opinion on a technology). Read non-technical books too – they help you engage with the human side of interactions

The process of learning will expand your thinking, opening you to new possibilities and new ways of doing things.

Be deliberate in your communications

“It’s not just what you’ve got, but also how you package it”

Coming up with the best ideas and writing the finest code is ultimately wasted if you cannot communicate and persuade effectively.

Invest time in improving your communication skills, they are just as important as technical skills.

This also applies to writing documentation for your projects.

Good design is easier to change than bad design

Well designed software is easier to maintain and faster to add new features. Be intentional with your design, don’t program subconsciously.

Thihnk of Orthogonality when designing code

Decoupling is key to good design. Two or more things are orthogonal if changes in one do not affect any of the others.

You should eliminate effects between unrelated things. Components should be self-contained, independent and with a single, well -defined purpose.

Orthogonal systems are also easier to test because interactions between the system’s components are formalised and limited. Therefore, testing can be performed more easily at the individual module/function level.

One of the reasons why writing tests for your code is such good practise is that it forces you to think about the orthogonality of your codebase. If the code is not orthogonal it will be hard to write tests. If it is hard to write tests, warning lights should go off indicating that you should rethink your code design.

Prototypes are supposed to be thrown away, don’t be scared to experiment

“Prototyping is a learning experience. Its value lies not in the code produced but in the lessons learned”

Typically in software development, there are multiple different ways of approaching a problem. This can lead to ‘coders block’ and paralysis due to not knowing where to start or which is the most optimal method.

If you are stuck and don’t know which method to choose, create a prototype. Prototyping is an effective method to quickly test ideas. It’s better than not trying at all.

If you find the prototype is not working or you run into too many challenges. Try again. The code is disposable, but at least you gained some new knowledge about the system.

However, before you embark on code-based prototyping make sure everyone understands that the code is disposable – prototypes can be deceptively attractive to people who don’t know that they are just prototypes.

Learn how to use your tools

“Tools amplify your talent. The better your tools, and the better you know how to use them, the more productive you can be”

Always be on the lookout for better ways of doing things

It is extremely important to optimise your workflow for maximum efficiency. Learn keyboard shortcuts, automate repetitive tasks, use the appropriate tools for the job etc.

Minor improvements compound over time.

Power editing

Most time is spent editing and adding to existing code. This is essentially text manipulation. You need to be able to manipulate text as effortlessly as possible – this is the basic raw skill of programming.

The major gain in becoming fluent in your text editor is that you no longer have to think about the mechanics of editing. You can edit at “the speed of thought” (see my other article on typing speed )

Everything should be under version control

Not much to add to this point. It doesn’t matter how small the project is, always use version control from the beginning as the project may quickly involve into a larger more complex project

Version control allows you to efficiently experiment with new features while maintaining a log of working code which can be restored quickly at any time.

You can’t write perfect software so build defenses

“Don’t outrun your headlights”

Design by Contract

Before writing code you should create a contract for it. i.e. set the preconditions and postconditions for what the expected inputs and outputs should be.

Contracts normally manifest themselves in the form of writing tests. Tests help you think about the purpose of a particular component and also make your code more readable as other developers can observe the expected behaviour

Use Assertions to Prevent the Impossible

For example, if the input or output of a component should never be empty or null, use an assertion to check and stop the bad result propagating downstream.

Assertions should not be used in place or real error handling. Use them only to protect against things that should never happen if they would cause problems further down the line.

Don’t Outrun Your Headlights

Always take small, deliberate steps and check for feedback and adjust as appropriate before proceeding.

Testing is not always about finding bugs

“Testing is not about finding bugs, it’s about getting feedback on your code: aspects of design, the API, coupling, and so on. That means that the major benefits of testing happen when you think about and write the tests, not just when you run them.”

If you can’t easily write a test for something it indicates that there might be something wrong with the overall design.

Thinking about testing makes us reduce coupling in our code.

Don’t program by coincidence

“Don’t assume it, prove it”. If your code works, make sure you understand why it works. Write a test for it. Maybe it works in certain situations but not all situations.

No-one knows exactly what they want

Requirements are learned in a feedback loop

Programmers help people understand what they want. Don’t take an initial requirement from a client as a requirement to implement a solution for it. Seek to understand the underlying need and explore solutions for it.

Your job is to help the client understand the consequences of their stated requirements.

Plan for the future

Avoid hardcoding business policies and logic. They will inevitably change during the project or further down the line.

Policies should be treated as metadata. You should implement the general case and pass the policy as metadata which is separated from the code implementation. This keeps your code flexible to future requirements changes

Don’t think outside the Box – Find the Box

The secret to solving puzzles (i.e. client problems) is to identify the real (not imagined) constraints.

Some constraints are absolute, others are merely preconceived notions based on assumptions. As explained in Algorithms to Live By you should look to re-imagine an impossible problem with a related, more simple problem that can be solved.

Further Reading