Zen of Defensive Programming
This is the beginning of a series of posts on the subject of Defensive Programming. It will take a look at coding practices to explore what steps software engineers and programmers can take to improve the quality of their code. This is achieved by maximizing their programming logic, utilizing tools and mechanisms that are already built into their compilers and interpreters, and by adopting a particular mindset that creates good coding habits.
Improved quality of the resulting software products will automatically follow suit.
What is Defensive Programming?
Even though it has been a generally accepted term for well over two decades now, it remains a bubblegum expression with countless interpretations. Depending on who you ask, you will get different answers. Allow me to explain how I define Defensive Programming in my mind so that you can get a better sense of the aspects I will cover throughout this series.
When talking to software engineers, the term Defensive Programming is often confused with Secure Programming. While this is not entirely wrong, the answer is incomplete. Ultimately, Secure Programming makes up only a comparably small subset of Defensive Programming in its entirety. Defensive Programming is so much more! Even Wikipedia scratches only the surface of its scope, making it a clear indicator of how misunderstood it truly is.
Most discussions of defensive coding practices start and end with assertions and guard clauses. While they are certainly integral to the toolbox we should be drawing from, there is a whole lot more that is often overlooked or willfully ignored.
For this series, Defensive Programming means writing code that has the following attributes:
As you can see, there’s a lot more going on already than just assertions and guard clauses. You may also find that a lot of what we will discuss is boiling down to simple cosmetics and formal semantics—but to great effect. You will see that few things about Defensive Programming are actually downright technical. Frequently they are not even tied to any particular programming language either.
How does it help?
The idea behind Defensive Programming is to prevent problems and errors automatically. To have mechanisms in place that detect potential errors at the earliest possible time. Ideally, while you are writing or compiling your code, before tracking down problems becomes a time-intensive and costly debugging session. As a result, your code will become eminently safer and better, which will instantly lead to more reliable code.
It helps root out errors sooner which cuts down on the time needed to test and debug your code.
Altogether, it will lead to you writing better code faster!
The thing about habits
A key reason why you do not see a lot of discussion of Defensive Programming practices in the public has to do with people’s habits. The funny thing about defensive coding practices is that they regularly bump up against long-established patterns. Things we’ve been taught since we wrote our first “Hello world!” programs, including some really bad practices and habits that have been perpetuated through the ages.
The nasty thing about habits is that we don’t want to break them. I fully understand that it’s not easy to break habits and that you won’t agree with everything I will propose. I will promise you this, however: As you slowly employ defensive coding practices, you will gradually appreciate the kind of benefits you can reap. Eventually, you will not be able to look at code the same way again. All it takes is an open mind and the intention to become a better programmer.
You will see your code get better!
Becoming a Defensive Programmer
Two things are crucial to setting you on the right path, awareness, and consistency.
You will need to increase your awareness of coding issues so you can recognize problematic situations and patterns. More importantly, you will need to raise your awareness so you can learn from your past mistakes and take proactive steps to prevent them in the future.
All too often, programmers will fix a bug and move on, without spending a lot of time considering what led to the bug in the first place and if there are, perhaps, ways how they could prevent a similar bug in the future. Many times they won’t even ask themselves if there’s a chance they made the same bug in other places of their code as well, something a quick project search could typically reveal. Raised awareness will ring alarm bells in your head that tell you to check other instances of similar problematic idioms, patterns, or code snippets to make sure their implementation is correct and, going forward, to avoid the problem altogether.
Consistency is also extremely important. It will help you develop good habits so that they become second nature. They may feel odd at first but that is fine. Consistency will also allow you to trust your code and identify errors quicker. If you use a certain bracketing style every time you write code, a sudden break in style will stand out. You should take this as an immediate indicator that, perhaps, there is something off with your code in that place, and investigate. Perhaps, you accidentally hit the Delete key at some point. Maybe someone else added a line of code that you should review. Or rather, you were distracted and it is time to make sure the distraction did not cause you to mangle your implementation.
As I mentioned, you may not agree with all of the principles I will lay out for you, in which case pick just one you can get behind. Make it a habit. It is much better to pick up one good habit and use it consistently than never even to consider alternatives and their advantages or disadvantages.
Becoming a Defensive Programmer is an evolution that you can easily adopt over time. As you grow, so will your realization of why some coding patterns are better than others. You will more readily appreciate other, perhaps more controversial, suggestions.
Life with Defensive Programming
I took to Defensive Programming out of necessity a long time ago. I worked with a small team that needed to be agile, long before Agile or SCRUM was even an expression. To coordinate between us, we all needed to adopt the same coding standards. It allowed every team member to be instantly able to read and work on somebody else’s code.
During my mobile development days, it became even more important because I had to cover a wide variety of hardware platforms from a single source code base. It made it necessary to develop and explore practices that worked effortlessly across different compilers, processors, specifications, and even languages.
I consider myself to be a Defensive Programmer, but I don’t pretend to write solid code all the time or to be an exceptionally good programmer. However, I do like to think of myself as a very reliable and productive programmer. To get there, we have to recognize that we all make mistakes and create bugs—even the best of us. We all overlook side-effects and miss implementation limitations on occasion. That doesn’t make us bad programmers. It makes us human.
Good software engineers, however, will adopt a mindset that forces them to try and learn from these shortcomings and do better next time! The key is that when we discover a bug or an issue, we can quickly locate it, safely fix it and avoid a trickling down of unwanted side effects.
Next time, let’s examine why axioms such as maintainability, readability, etc. are so important to defensive programming. You can read the next installment here.
Zen of Defensive Programming
Part I • Part II • Part III • Part IV • Part V • Part VI • Part VII • Part VIII • Part IX
Thanks for stopping by. Preparing content such as the one you have just read takes time and effort to prepare. If you enjoyed it and you are using a Brave browser, please feel free to leave a small tip as a sign of your support by clicking on the small BAT icon at the top of your browser window. Your tip is much appreciated and it encourages me to continue providing more content such as this.