Discover more from Engineering Ideas
The Pragmatic Programmer by David Thomas & Andrew Hunt – notes on the book (part 1)
Try things, ask questions, think critically, programmer's mindfulness, generalist vs. specialist, realism, responsibility, pair programming, no broken windows, tech debt
The Pragmatic Programmer, 20th Anniversary Edition by David Thomas and Andrew Hunt is a practical book that encompasses almost all aspects of professional software engineering: from basic skills such as working in the console and text editing to writing code, software design, testing, deployment, requirements, management, and communications in teams.
The authors aim to distil some principles, rules of thumb, and habits that make programmers more effective in their work.
I wish I’ve read this book when I was just starting my programming career. Now as I’m a more experienced programmer, reading “The Pragmatic Programmer” was still a good overview that reminded me of the areas that fell out of my attention.
Below I highlight a few ideas from the book that I found interesting (though I don’t agree with them all). This post doesn’t cover the full book contents, of course, more posts to follow.
Try things out
Programmers should be early adopters, fast adapters. They should have an instinct for technology and techniques. They should love to try things out.
There is obviously some truth to this idea. Trying things out is a way to learn. However, the idea appears underdeveloped to me. Will Larson’s Magnitudes of exploration is a more better-thought take on it, in my opinion.
Be curious, ask questions
Programmers should be inquisitive and ask lots of questions. This creates a space where innovative solutions in the intersection of fields can appear.
Sidney Dekker. Drift into Failure:
[Leonardo da Vinci] embraced the profound interconnectedness of ideas from multiple fields. His goal was to combine, advance, investigate, and understand processes in the natural world through the interdisciplinary view.
Programmers should rarely take things as given without making them their own.
Per Mortimer Adler, teachability (note difference from trainability) means exercising your independent judgement, criticality. People should make their own mind after fully hearing and understanding the other party. (How to Read a Book)
Seneca. On the Futility of Learning Maxims:
“Thus said Zeno, thus said Cleanthes, indeed!” Let there be a difference between yourself and your book! How long shall you be a learner? From now on be a teacher as well!
What then? Shall I not follow in the footsteps of my predecessors? I shall indeed use the old road, but if I find one that makes a shorter cut and is smoother to travel, I shall open the new road. Men who have made these discoveries before us are not our masters, but our guides. Truth lies open for all; it has not yet been monopolized.
Constantly think about what you are doing
In addition to thinking critically, programmers should try to understand the underlying nature of each problem you face.
Programmers should reflect on their work, every decision they make, every project. They should never run on autopilot. They should critique their work in real-time. Mantra: “Think”.
For example, articulate why you are repaying technical debt.
Ryan Holiday agrees in The Daily Stoic: “Never do anything out of habit”.
This is a specific application of the more general idea of mindfulness to engineering.
In the context of programming, however, there is some tension between this idea and that we should achieve the state of flow, or “enter the zone”. Joel Spolsky writes:
We all know that knowledge workers work best by getting into “flow”, also known as being “in the zone”, where they are fully concentrated on their work and fully tuned out of their environment.
Programmers in the “Agile camp”, where Thomas and Hunt belong, usually argue that the flow state is not desirable, for example, Robert Martin in The Clean Coder:
Here’s a little hint from someone whose been there and back: Avoid the Zone. This state of consciousness is not really hyper-productive and is certainly not infallible. It’s really just a mild meditative state in which certain rational faculties are diminished in favor of a sense of speed.
Keep an eye on the big picture
Get into the habit of really looking and noticing your surroundings.
Solve users’ problems, not technology problems
Be a full-stack craftsman
Programmers should care about the craft. They should be “jacks of all trades” and try hard to be familiar with a broad range of technologies.
The software craftsmanship movement has sprung up from this idea since the first edition of The Pragmatic Programmer was published.
Eric Schmidt and Jonathan Rosenberg. How Google Works:
Favoring specialization over intelligence is exactly wrong, especially in high tech. The world is changing so fast across every industry and endeavor that it's a given the role for which you're hiring is going to change. Yesterday's widget will be obsolete tomorrow, and hiring a specialist in such a dynamic environment can backfire. A specialist brings an inherent bias to solving problems that spawns from the very expertise that is his putative advantage, and may be threatened by a new type of solution that requires new expertise. A smart generalist doesn't have bias, so is free to survey the wide range of solutions and gravitate to the best one.
Of course, generalist vs. specialization is a vast topic. Opinions depend on whether the programmer’s individual perspective or the organizational perspective is taken (however, in this case, the principal-agent problem may be at least as a serious concern, at least for the company), the type of the company (product vs. service), what development process is used in the team, the nature of the system being developed, etc. I don’t believe there could exist a one-size-fits-all answer to this question.
Deeply understanding that the process will be difficult and will take time gives programmers the stamina to persevere.
Programmers should realise that in many situations, even ideal decisions, planning, management, and design won’t save them from doing hard and unpleasant work, sometimes a lot of it. There may be just no way around.
Compare with the Stockdale paradox:
You must never confuse faith that you will prevail in the end—which you can never afford to lose—with the discipline to confront the most brutal facts of your current reality, whatever they might be.
Be responsible and proactive
Programmers should take responsibility and do their best and analyze risks for things out of their control and make accurate estimations.
Being responsible means being dependable, which is one of the most important dynamics of effective teams.
Programmers should say “I’ll find out” instead of “I don’t know”.
Programmers should admit their ignorance. They should ask or to admit that they need help: resources, context, learning. These all are ways to share vulnerability.
Admit mistakes and offer options
When an engineer makes a mistake or an error in judgement, they should admit it honestly and try to offer options. They shouldn’t blame someone or something else (if they didn’t envision the risk, it’s their risk analysis mistake) or make up an excuse. Engineer’s job is to provide solutions, not excuses.
Be honest and direct
Thomas and Hunt say that professionals should be honest and direct. “The greatest of all weaknesses is the fear of appearing weak.”
Benefits of pair programming
Generally, in line with @Arne Bultman's big idea to work more as a team
Reduces the total number of work-in-progress tasks on the project
Accelerates the rate of task completion, with all Agile-ish benefits of that. However, this increase doesn’t fully compensate for the reduction of the total number of work-in-progress tasks, so the team throughput may be lower than if everybody on the team were programming solo. In mid- and long-term, however, shorter feedback loops (see “the smaller chance that people go in the wrong direction” below) and the learning effects make pair programming “faster” than solo programming.
Shared code ownership, bus factor = 2 (with no separate Code Review process required)
Mutual learning, knowledge sharing: ways of working, thinking process, tips & tricks, useful programs, etc.
People in the pair counteract each other’s weaknesses and blind spots.
Accountability, maintaining focus on the task
Forces to plan the day, organize and break down tasks, thus the participants learn to do it better
The smaller chance that people go in the wrong direction: a person working alone doesn’t have as immediate feedback to their decisions
When facing challenges, the participants support each other to boost morale and persevere
Vast opportunity for mutual feedback and sharing vulnerability
Something else? Please share!
Maintain bus factor >=2 for any part of the system
Set up quick feedback loops for the work
Birgitta Böckeler and Nina Siessegger. On Pair Programming:
We talked a lot about the benefits of pair programming, but even more about its challenges. Pairing requires a lot of different skills to get it right, and might even influence other processes in the team. So why bother? Is it really worth the hassle?
For a team to be comfortable with and successful at pair programming, they will have to work on all the skills helpful to overcome its challenges: Concentration and focus, task organisation, time management, communication, giving and receiving feedback, empathy, vulnerability - and these are actually all skills that help immensely to become a well-functioning, collaborative and effective team. Pairing gives everybody on the team a chance to work on these skills together.
Maintain the quality bar rigorously
Programmers shouldn’t leave “broken windows”: bad designs, wrong decisions, poor code. If there is no time to fix them immediately, board them up: turn off functionality. Neglect accelerates software rot faster than anything else.
The quality bar doesn’t need to be very high though. It should be chosen consciously based on the demands of the project. But whatever the bar is, programmers should stick to it without exceptions.
Team strengthening tip: choose 2-3 broken windows and discuss how to fix them.
Related: avoid the second mistake in the habit streak.
Never take unfocused, short-term technical debt
Programmers shouldn’t cause collateral damage: unmanaged, unaccounted technical debt in times of deadlines or firefighting.
Steve McConnell. Managing Technical Debt:
… debt accumulates from taking hundreds or thousands of small shortcuts—generic variable names, sparse comments, creating one class in a case where you should create two, not following coding conventions, and so on. This kind of debt is like credit card debt. It’s easy to incur unintentionally, it adds up faster than companies think, and it’s harder to track and manage after it has been incurred. We’ll call this “Unfocused Short-Term Debt.” […] this kind of debt doesn’t pay off even in the short term of an initial development cycle and should be avoided.
Ron Jeffries. Technical Debt:
Unfortunately, today, “technical debt” has often come to mean something like “judiciously skimp on design today, so that we can go faster; we’ll clean it up later”.
In my view, there is no useful meaning for “judiciously skimp on design today”. Every design flaw we leave in the system today will slow us down tomorrow.
To go fast, we have to go clean. Dirty code isn’t technical debt. The surgeon can’t usefully save time by only sterilizing some instruments. We can’t usefully save time by writing sloppy code. That’s not technical debt. That’s sabotage.