This book is about a philosophy of being pragmatic in our craft. It’s aimed at people who want to become more effective and productive programmers.
Craftsmanship
Programming is a craft and it’s a difficult job. No doubt about it. Every day, we try to transform vague user requirements into a language that computers can understand.
It’s not enough to learn one language and stick with it throughout our entire career. We should aspire to be polyglots that can adapt to the current situation by utilizing the best possible tools to solve the problem.
Be responsible and don’t complain
Pragmatic programmers aren’t afraid to admit ignorance or error. We are humans. A lot of things can go wrong even if we do our best with testing, documentation, or automation.
The best we can do then is to acknowledge the problem, take responsibility for it, and try to offer options to fix it.
Don’t accept any broken window
One broken window, left unrepaired for any substantial length of time, instills in the inhabitants of the building a sense of abandonment—a sense that the powers don’t care about the building.
In my opinion, this analogy suits software quite well. I’m sure we’ve all seen codebases that were doing just fine only to find later that they are slowly descending to a ruin.
Your growth is your responsibility
We all know we should stay on top of technologies and the latest trends and constantly keep learning. I think no one has to be convinced about this anymore.
Learn at least one new language every year. You’ll learn several different approaches to solving various problems. It’ll broaden your thinking.
Read a technical book each month. A book will give you the depth that you won’t find in podcasts, blog posts, or online videos
Take classes or workshops. Look for occasions to expand your knowledge.
Participate in local user groups or meetups. Don’t just go and listen. Participate actively.
Experiment with different environments. For example, if you’ve only worked with IDE, consider spending some time with a text editor, and vice versa.
Stay current. Follow interesting people in your field, read blogs, make side-projects.
Easier To Change
Programmers often like to argue and discuss which framework, language, or design pattern is the best. Authors argue that at the end of the day, what really matters is that the system we are working on is Easier To Change (ETC).
ETC is a value, not a rule, that should help you make decisions. By asking whether the approach I’m taking will make it relatively easy to change it later when needed, you will usually know which path to choose.
Prototypes and Tracer Bullets
To prove that your idea is doable, you could start with a more forgiving language like Python. At this point, you don’t need any user interface, specific architecture, or design. None of the code will end up in the codebase anyway.
Prototypes are not necessarily end to end, they are mostly used as a learning tool and are focused on the area you are unsure about and want to explore before implementing all supporting logic.
Imagine building a mobile application where users fill out a form. That submission hits our server to be processed later. A finished app requires a pleasant user interface with animations, validation on both the client and server-side, well-formatted responses, etc.
Tracers are about building an end to end, minimal value-able thin but real implementation of a use case, that is used for a quick feedback loop, i.e. whether or not you are building the right thing (hit the target) and based on feedback you can adjust your aim and fire a new tracer bullet.
Estimating time
Estimating time is extremely difficult, especially when people expect us to provide a single number
When we finish a project or an iteration, we can see how close we were. If the gap was significant, we should stop and think about a reason. With time and practice, we will give more accurate estimations.
Be fluent with your tools
If we don’t have to think about all the keyboard shortcuts and options while programming, our minds will have more capacity to think about the problem at hand.
Debug with confidence
Debugging and finding errors is not always fun. There is no point in making it more problematic than it has to be.
First, before you start debugging, you should adopt the right mindset. Turn off all defensive mechanisms that protect your ego. Then, always begin with making a bug reproducible. If you can’t do it, you will never know if it’s fixed.
Always assume that the bug exists in your code and start from there. Because even if it does lie in the library, you would still have to trace the problem in your code before submitting the bug report to the maintainers.
Engineering daybook
It’s a kind of journal in which you record what you do, things you learned, sketches of ideas, notes from meetings, variable values when debugging
Dead programs don’t lie
Programmers tend to take a defensive approach when programming. We try to catch or rescue all possible exceptions, check for nullability before using variables, verify that the lists passed as arguments are not empty, etc. We avoid crashes at all costs.
The problem with this approach is that the app or system we are working on might stop working silently on production without us having any way of detecting it.
If our app gets in a weird state, it would be nice to know it. That’s why unhandled exceptions are not always such a bad thing. They are collected by your crash reporting tool and will help you find the root of the problem.
Take small steps
It’s usually better to take small and deliberate steps. You then check for feedback and adjust before proceeding.
We should avoid steps that are too big. They require an attempt to predict the future. No one can do that.
Decoupling
We want our code to be as flexible as possible. Coupled code is hard to change. Modifications in one place can have secondary effects in other locations.
We shouldn’t ask about an object’s internal state and then modify it based on the information we receive. We should tell it to do what we need.
Fear of the blank page
We start working on a new feature or a completely new project. The cursor is blinking. The screen is empty and ready to be filled with code. For some reason, the experience is very intimidating. We put off making the initial commitment of starting.
Pretend that you are prototyping. Remember that prototypes get thrown away, even if they don’t fail. If your mind knows this, you are less likely to feel anxious.
Don’t program by coincidence
When you use a technology you don’t understand, you program by coincidence. If you’re unsure why something works, you won’t know why it fails. Programming by coincidence is the opposite of programming deliberately.
Code is a garden
Code is not static. It constantly evolves. Inaccurately, some people associate software development with building construction. The software doesn’t quite work that way. It’s more like a garden when things change all the time.
The gardening metaphor is much closer to the realities of software development. Laws of physics don’t constrain code as they do with buildings. This philosophy led to a discipline called Refactoring.
Tests aren’t only about finding errors
The sole act of thinking about tests while coding is the main benefit of tests. When we think about writing tests for the code we are working on, we imagine ourselves as clients of the code, not its authors.
Be proud of your work
Pragmatic programmers should be proud to sign their work just like artisans of an earlier age. When we are accountable for a piece of code, we aspire to do a job we can be proud of.
Systems and devices that we build can shape the lives of millions. How often do we stop and think about this? We should do our best to protect the users from any potential harm. If we are involved in a project that requires us to do something against our beliefs or values, we shouldn’t be afraid to say “no”.