The Pragmatic Programmer
Akshay Khot
Posted on January 12, 2021
If there is one book that has had the biggest influence on me as a professional software developer, The Pragmatic Programmer would be it. I read the original book many years ago, and it changed how I view software development. I recently re-read the newer version of the book, which was published last year to celebrate its 20th anniversary. Here is a complete summary of the book.
Note: It's not a detailed book review, but a collection of passages from the book that resonated with me the most. Hope it helps.
Keep a Work Journal
To record what you did, what you learned, what to do better next time, what mistakes you made, and how to avoid them in the future.
When you stop to write something down, your brain may switch gears, almost as if talking to someone---a great chance to reflect. You may start to make a note and then suddenly realize that what you'd just done, the topic of the note, is just plain wrong.
There's an added benefit, too. Every now and then you can look back at what you were doing oh-so-many-years-ago and think about the people, the projects, and the awful clothes and hairstyles.
Debugging
The first rule: Don't Panic. It is very important to step back a pace, and actually think about what could be causing the symptoms that you believe indicate a bug.
Resist the urge to fix just the symptoms you see: it is more likely that the actual fault may be several steps removed from what you are observing, and may involve a number of other related things. Always try to discover the root cause of a problem, not just this particular appearance of it.
- You may need to interview the user who reported the bug to gather more data than you were initially given.
- Artificial tests don't exercise enough of an application. You must brutally test both boundary conditions and realistic end-user usage patterns. You need to do this systematically.
A very simple but particularly useful technique for finding the cause of a problem is simply to explain it to someone else. It sounds simple, but in explaining the problem to another person you must explicitly state things that you may take for granted when going through the code yourself. By having to verbalize some of these assumptions, you may suddenly gain new insight into the problem.
Master Your Tools
First, look at yourself while you're working. Every time you find yourself doing something repetitive, get into the habit of thinking "there must be a better way." Then find it.
Once you've discovered a new, useful feature, you now need to get it installed into your muscle memory, so you can use it without thinking. The only way we know to do that is through repetition. Consciously look for opportunities to use your new superpower, ideally many times a day. After a week or so, you'll find you use it without thinking.
Don't Outrun Your Headlights
In software development, our "headlights" are similarly limited. We can't see too far ahead into the future, and the further off-axis you look, the darker it gets. So Pragmatic Programmers have a firm rule: Take Small Steps---Always.
Always take small, deliberate steps, checking for feedback, and adjusting before proceeding. Consider that the rate of feedback is your speed limit. You never take on a step or a task that's "too big."
Configuration
When code relies on values that may change after the application has gone live, keep those values external to the app. When your application will run in different environments, and potentially for different customers, keep the environment- and customer-specific values outside the app. For more details, see this post.
Domain Languages
The language you choose influences how you think about a problem, and how you communicate.
Always try to write code using the vocabulary of the application domain. In some cases, Pragmatic Programmers can go to the next level and program using the vocabulary, syntax, and semantics---the language---of the domain.
While You Are Coding
We should avoid programming by coincidence---relying on luck and accidental successes---in favor of programming deliberately.
Always be aware of what you are doing. If you're not sure why it works, you won't know why it fails. Proceed from a plan, but be ready to change the plan if the environment changes. Prioritize your effort. Spend time on the important aspects.
Test your assumptions.
Document your assumptions, and also test your assumptions. If your assumption is right, you can make a better, informed choice. If your assumption was wrong, well, be glad you tested it.
Don't let existing code dictate future code. All code can be replaced if it is no longer appropriate. Even within one program, don't let what you've already done constrain what you do next---be ready to refactor
Prioritize
If you don't have fundamentals or infrastructure correct, brilliant bells and whistles will be irrelevant. Prioritize your effort. Spend time on the important aspects.
Why Write Tests
Testing is part of programming. To write good tests, you have to understand the code you are writing the tests for. That's a huge benefit of writing tests. We usually work with a slight understanding of the code and think that we will worry about the edge cases, or error handling later, and never come to it.
Naming Things
Things should be named according to the role they play in your code. When you consider the role of a variable or function, you're thinking about what is special about it, what it can do, and what it interacts with. Rename and refactor when your understanding of a thing changes. Avoid misleading names.
Requirements: No one knows exactly what they want
Requirements rarely lie on the surface. Normally, they're buried deep beneath layers of assumptions, misconceptions, and politics. Even worse, often they don't exist at all.
The typical client comes to us with a need. A response to a current problem. The need may be for a change to an existing system or it may ask for something new, it can be either expressed in business terms or technical ones. The mistake new developers make is to take this need and implement a solution for it. Good programmers help the clients understand what exactly they want.
Requirements are learned in a feedback loop. Your job is to help the client understand the consequences of their stated requirements. You do that by generating feedback and letting them use that feedback to refine their thinking.
Even at the end of a project, we're still interpreting what our client wants. In fact, by that point, we're likely to have more clients: the QA people, operations, marketing, and maybe even test groups of customers.
Maintain a glossary.
As soon as you start discussing requirements, users and domain experts will use certain terms that have specific meaning to them. Create and maintain a project glossary---one place that defines all the specific terms and vocabulary used in a project. All participants in the project, from end-users to support staff, should use the glossary to ensure consistency. This implies that the glossary needs to be widely accessible---a good argument for online documentation.
Solving Impossible Puzzles
Identify the real (not imagined) constraints, and find a solution therein. Some constraints are absolute; others are merely preconceived notions. Absolute constraints must be honored, however distasteful or stupid they may appear to be.
The key to solving hard problems is both to recognize the constraints placed on you and to recognize the degrees of freedom you do have, for in those you'll find your solution.
Go for a walk, work on something different. Let your unconscious brain work on the problem in the background. However, to have those eureka! moments, your non-conscious brain needs to have plenty of raw material; prior experiences that can contribute to an answer. Or, explain the problem to someone, or even a rubber duck.
Ask questions. Why are you solving this problem? Do you really need to solve it? Has it been solved before? Is there a simpler problem you can solve, instead? Continuously get feedback on what works and what doesn't work as you do your daily job.
Were you handed a set of constraints when you signed on to your current project? Are they all still applicable, and is the interpretation of them still valid?
The Essence of Agile
- Work out where you are.
- Make the smallest meaningful step towards where you want to be.
- Evaluate where you end up, and fix anything you broke.
- Repeat until done.
Estimating
The first part of any estimation exercise is building an understanding and a mental model of what's being asked. Often, the process of building the model leads to discoveries of underlying patterns and processes that weren't apparent on the surface.
Ask someone who's already done it. Before you get too committed to model building, cast around for someone who's been in a similar situation in the past. See how their problem got solved. It's unlikely you'll ever find an exact match, but you'd be surprised how many times you can successfully draw on others' experiences.
Record your estimates so you can see how close you were. When an estimate turns out wrong, don't just shrug and walk away---find out why. Instead of giving the complete estimate upfront, iterate the Schedule with the Code. By refining the schedule as part of each iteration, you'll be giving them the most accurate scheduling estimates you can.
What to say when asked to give an estimate? You say "I'll get back to you." You almost always get better results if you slow the process down and spend some time thinking.
Context Matters
Have you or your team fallen into this trap? Ask yourself, why are you even using that particular development method? Or that framework? Or that testing technique? Is it actually well-suited for the job at hand? Does it work well for you? Or was it adopted just because it was being used by the latest internet-fueled success story?
Do What Works, Not What's Cool or Fashionable
There's a current trend to adopt the policies and processes of successful companies such as Spotify, Netflix, Stripe, GitLab, and others. Each has its unique take on software development and management. But consider the context: are you in the same market, with the same constraints and opportunities, similar expertise and organization size, similar management, and similar culture? Similar user base and requirements?
The Real Goal
The goal of course isn't to "do Scrum," "do agile," "do Lean," or what-have-you. The goal is to be in a position to deliver working software that provides value to your users by giving them more capability.
Civilization advances by extending the number of important operations we can perform without thinking.
Ruthless and Continuous Testing
Many developers test gently, subconsciously knowing where the code will break and avoiding the weak spots. Pragmatic Programmers are different. We are driven to find our bugs now, so we don't have to endure the shame of others finding our bugs later. Test Early, Test Often, Test Automatically.
Testing Thoroughly
How do you know if you have tested the code base thoroughly enough? The short answer is "you don't,'' and you never will.
Find Bugs Once, Fix them twice
Once a human tester finds a bug, it should be the last time that bug occurs, no matter how rare you think it is. Because it will happen again. And we just don't have the time to go chasing after bugs that the automated tests could have found for us. We have to spend our time writing new code---and new bugs.
So fix the bug as soon as you or QA find it, and immediately put a system in place so that that bug never happens again.
Delight Your Users
Our goal as developers is to delight users, not just delivering working software on time, but to actually make our users happy when they use our software.
Users have a problem that needs solving within the context of their objectives and budget. It's these expectations of business value that really count---not just the software project itself. The software is only a means to these ends.
Make sure you know about your users' expectations before you start working on a project. Continue to think about them as you progress, and try to not only meet them but exceed them when you finish.
Talk to other departments
As our knowledge of the domain increases, we're better able to make suggestions on other things that could be done to address the underlying business issues. Developers, who are exposed to many different aspects of an organization, can often see ways of weaving different parts of the business together that aren't always obvious to individual departments.
Sign Your Work
Take pride in your work. "I wrote this, and I stand behind my work." Your signature should come to be recognized as an indicator of quality. People should see your name on a piece of code and expect it to be solid, well written, tested, and documented. A professional job. Written by a professional. A Pragmatic Programmer.
Thank you for reading. If you thought these notes were helpful, you might enjoy my notes on more books on my blog.
Posted on January 12, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.