This post is a collection of recounts of how The Pragmatic Programmer has positively affected the quality of products I deliver as well as my personal quality of life as a developer. In conjunction with that, it includes some arguably convincing evidence as to why or why not a specific practice should be adhered to. If you haven’t read the book, I strongly recommend it. While reading the book, I felt like I was teleported to a dimly lit castle with a wise wizard ready to give me all of his sage advice while he stroked his beard. Okay, maybe I took that a bit far, but reading this book felt like if a senior developer sat me down and explained all the things they wished they had known prior to starting their career. If you are looking to create higher quality products and make your life easier then you should definitely check it out here.
I decided to give Visual Studio Code a try and I can say I’m embarrassed I didn’t start using it sooner. I got into the habit of using the wrong tool and I got so good at using it that I didn’t consider anything else. Not only does Visual Studio Code provide ‘go to definition’ and great code completion via IntelliSense it also does a variety of other wonderful things that Atom does not do.
Using your tools well is important. Using the right tools well is more important. Have you ever seen your coworker use a specific tool to solve a problem and wonder why they do it that way? You probably should ask them about it. Two things might happen, you may learn about a more efficient tool you should be using or you can teach them about a more efficient tool they could be using.
You can’t write perfect software so you should refactor early and refactor often. I used to obsess over writing “perfect” software, whatever that means. If I found a more idiomatic pattern for something I was often doing in a codebase I would scrub the codebase of the nasty pattern and replace it with the more idiomatic pattern. I only did this on my personal projects and found that I spent more time fixing things and rearranging code rather than implementing anything new. I am still a perfectionist, what programmer isn’t, but you can’t fix everything. You won’t be able to, software entropy always wins.
I don’t fix everything. I fix the code I touch, I always try and leave the code I touch in a better state than when I left it. Without going overboard and sinking time into a problem you should not be afraid to refactor existing code. If you have good unit tests it should be easy to do. If there is no time to fix a bug or refactor a defect then take note of them at the very least. You can’t make your software perfect you won’t be able to fix every bug you find but you and your team should at least be aware that they exist at minimum.
When you learn a more idiomatic way to solve a problem that is great, you won’t be able to scrub the entire code base of the previous way of doing things, it is simply not worth it. Consider for a moment that you could be wrong. The best approach is to refactor the pervious implementation to the more idiomatic solution the next time you touch the code. This gives you some time to let what you consider to be idiomatic sink in. Maybe you won’t have the same standard in a week or a month.
Is a language or framework holding your team back? Maybe it is a specific part of the software development life cycle? Everywhere you work you should look for improvements your team could make to be more effective. Whether it is a development process change or the introduction of a new technology such as a framework or library, anything that can make an increase in the quality of the product your team produces may be worth making.
Early on in my career, I worked at a company that used git for version control which was great but most teams had no policy on what branching (or forking) model to use. Good version history is important, and at the time I felt like the “git flow” branching model would produce the highest quality version history for our teams. So I wrote up a formal policy that management could review and hold teams accountable to. In conjunction with that, I evangelized the usage of “git flow” to every developer I worked with. I feel as if this is an example of being a catalyst for positive change because it allowed us to have more valuable version history company wide.
npm so I recommend that we invest in infrastructure for that technology. In conjunction with that, I recommended that we build the user interface using React and Redux, I felt that the clear separation between the model and view layer would lead to a more testable application which would help result in a higher quality product since we could iterate on existing functionality easier. I feel as if this is an example of being a catalyst for positive change. Where ever you work, always consider what improvements you can make to allow you and your team to work more effectively and produce higher quality software.
At some point in your career you will be asked to give an estimate on how long it will take to complete a specific task or even a whole project. Getting better at estimation is tricky and it is something I am not sure I will ever master but we can get better over time. Something that I find that helps me is considering my past work as a frame of reference. Over time you will solve a variety of problems, that allows you to know what yours strengths and weaknesses are allowing you to better assess how long it will take me to complete a task. Even better, after having spent some time working on a code base you may find your estimations become more accurate. This is because of a couple of factors such as becoming more familiar with the code base as well as the problem domain. Your skills in estimation will increase as you your skills in coding and designing software increase.
Estimations for an entire team or a project are slightly different since they are less dependent on your skills. When I have to give an estimate for an entire team it is always based off of our past work respective to how much work every individual completed. If you know how much work every individual can complete in a given amount of time and you know every individuals time or resource commitment levels to the current project then you can form a pretty accurate estimate. Expect more on calculating precise estimates in another post soon.
When giving an estimate consider that 6 weeks and a month and a half are equal but imply different levels of precision. If someone gives an estimate of 6 weeks it is expected to be completed within a couple days relative to the 6 week estimation. Although, when someone gives an estimate of a month and a half it is expected that is completed within a couple of weeks relative to the month and a half estimation. This is similar to when someone says they will pick you up in 5 minutes compared to 7 minutes, the latter feels much more precise.
As a general rule, The Pragmatic Programmer gives a great reference for what units you should give estimates in. If an estimate is 1 to 15 days consider quoting in terms of days. If an estimate is 3 to 8 weeks consider quoting in weeks. If an estimate is 8 to 30 weeks consider quoting in terms of months. If an estimate is greater than 30 weeks think harder before giving an estimate.
Tracer bullets are used to find the target. Every fifth round a phosphorous coated round hurls towards its target allowing you to see how close to the target you are. I approach problems in a very similar manner as this. On a daily basis I might not know exactly how to solve the problem I am working on. Utilizing tracer bullets I can try a few approaches out and see how well they work (if at all). In a very similar manner, I also find value in approaching whole projects this way. Sometimes it may not be clear if a given tech stack will give you exactly what you need. In this case, it may be worth investigating if it will work by utilizing tracer bullets.
In the case of my day to day work, I might have a set of steps for what I need to complete, either written or in my head. These steps might be decomposed sub-problems of my original problem essentially making an algorithm I can use to complete my task. If I am unsure if a certain piece of that algorithm will work, I will write the minimum set of code that I can, to see if my given approach is going to work for that specific sub-problem. I will do this repeatedly until I know without a doubt my solution will work correctly. This gives me a chance to back out and try something else before I spend too much time trying to solve a problem before I even know if a critical part of it will work correctly or not. I find working this way, when I have some doubts allows me to save myself from wasting time.
Tracer bullets can be utilized to determine if a given set of tools such as libraries, frameworks or other applications, can correctly be used to complete a project. Perhaps, you do not know if it will work at all or you don’t know if you will have the desired performance. You do not want to waste time on a project where you decided to use library Y and framework Z to help you complete the project only to realize after having started the project already that library Y and framework Z will not correctly work together at all. This is not so bad if it is a couple days after the project starts but imagine if it is weeks or months after you started the project. Consider how unhappy your manager or customer will be when you inform them of the delay.
If you have any doubts about whether a given set of technologies will allow you to solve a problem you should investigate them. A good investigation would include a minimal integration of all the technologies together that provides a single thread all the way through the system. Whether that single thread is from the front end to the back end or a high level service layer to a hardware access layer, it is important to know that everything will work together. This allows you to start a project with confidence knowing the technologies you have chosen to complete the project will actually work.
In this post we discussed a bit about what practices a pragmatic programmer might employ. Always ensure you are using the right tools and that you practice them. It is important that every developer understands that they can’t write perfect software. Although, they don’t need to be lazy about making improvements to their codebase while working. You should be consistently thinking about what improvements your organization can make to increase product value; be the developer who is a catalyst for positive change not the one who notices potential improvements and does nothing. When giving estimates consider whether your estimate should be terms of days, weeks, or months. The units matter, they imply a level or precision. Lastly, utilize tracer bullets to find the target.
As always, I’d love to hear your thoughts about this post. What other pragmatic approaches to development do you take? If you are interested in more of my thoughts on being a pragmatic programmer stay tuned for the second iteration of this series.