Perhaps more than any other holiday I can think of, New Year’s Day has specific traditions. With other holidays, they range all over the map. While Christmas has trees, presents, rotund old men, and songs, New Year’s concerns itself primarily with fresh starts.
If you doubt this, look around during the first week of the year. Armed with fresh resolutions, people swear off cigarettes and booze, flock to gyms, and find ways to spend less. Since you don’t come to this blog for self-help, I’ll forgo talking about that. Instead, I’ll speak to some resolutions that you should consider when it comes to code quality. As you come to the office this week, fresh off of singing “Auld Lang Syne” and having champagne at midnight, think of changing your ways with regards to your code base.
Before we get into specifics, though, let’s consider the context in which I talk about code quality. Because I don’t drink from mason jars and have a two-foot beard, I won’t counsel you to chase quality purely for the love of the craft. That can easily result in diminishing returns on effort. Instead, I refer to code quality in the business sense. High-quality code incurs a relatively low cost of change and generates few or no unexpected runtime behaviors.
So the question becomes, “What should I do in the new year to efficiently write predictable, maintainable code?” Let’s take a look.
Don’t Copy and Paste
First of all, resolve to stop with the copy-and-paste programming. More than any other resolution I’ll offer, this one truly resembles a resolution to quit smoking. Everyone knows that copy-and-paste programming murders maintainability, but many guiltily do it anyway. Make this the year you go cold turkey.
Everyone makes mistakes while programming. Copy and paste programming acts as a force multiplier for your mistakes. Instead of having a mistake in one page on your site, you now have it in dozens.
It gets worse. Sooner or later you find the mistake and you correct it. Then, maybe you remember to correct it in eight of the 10 places you’ve copied and pasted, but forget about two. You now have the beginnings of similar but divergent code everywhere. This means that when you want to do the right thing and abstract out the common bits, it won’t even be possible.
Best just to avoid the whole mess in the first place.
Reduce Cyclomatic Complexity
I would also recommend that you resolve to reduce cyclomatic complexity as you code. This means controlling the number of control flow statements (for, while, if, etc.) in a given method or type. Personally, I tend to limit this at one per method, whenever possible, but you might initially aim for a somewhat higher threshold.
More paths through your code mean more substantial spikes in the number of test cases required to verify it. As your code gets more and more complex, the likelihood grows that some paths have never been executed. As you might expect, this represents a potential maintenance nightmare.
I have a personal rule of thumb that I should be able to reason about any method I write at a glance without compiling or debugging. Stick to that and you’ll find yourself battling fewer maddening defects under a time crunch.
Stop Ignoring Warnings
Don’t ignore compiler and tooling warnings. Again, we have wisdom under the heading of, “We should all know better.” Yet, how many of you reading have codebases with dozens, hundreds, or thousands of compiler warnings? How many of your teams have simply given up?
Draw a line in the sand this year, and say, “No more.” Take some time, get the count to zero, and keep it there.
When you have many outstanding warnings, the signal to noise ratio makes a beeline for zero, and you ignore the tools. Do I really need to explicitly state that ignoring your compiler invites trouble? Create a culture where you take warnings seriously, and the decision will more than pay for itself with absolved technical debt.
No More Global State
Perhaps global state represents the most tantalizing vice of any of these. Programmers used to global state often have the attitude, “You’ll take it from my cold, dead hands.” Often, this comes in the form of the singleton design pattern, but sometimes, you find it in simple, public static variables or properties. Or, sometimes, you can find it in simple declarations with global scope.
Whatever the case may be, a mutable global state creates maintenance and runtime nightmares. You have variables that any piece of code from anywhere in the application can change at any time. Even as you’re working with a piece of code, someone in another department might commit some piece of code that dramatically changes what yours does.
I often explain global state to managers and executives by using the road system as a metaphor. Imagine that any driver could, at any time, change the state of any given traffic light. On a lonely single lane road, late at night, this might make sense for one car sitting for a long time at a red light. However, imagine how this scheme scales as traffic increases. The word you’re looking for is “gridlock” or perhaps “nightmare.”
In 2017, at least stop adding to the problem. If possible, look to chip away at it and reduce it as close to zero as possible.
For Goodness Sake, Start Writing Unit Tests
Last and certainly not least, I’ll mention the programming equivalent of a resolution to start flossing. I’m talking, of course, about unit tests. Every six months, someone wags a finger at you and tells you to do it. Every six months, you promise to do it, totally mean to do it, and then don’t. This time, start.
Unit tests do the obvious. They create a robust regression test suite for your application.
They do so much more, as well.
They create a safety net that allows you to refactor fearlessly. They communicate design intent better than code comments can (because comments invariably age poorly) and they promote good design by forcing you to write relatively decoupled, usable code.
I could go on, but I won’t. You get the idea. I’m not telling you anything you haven’t heard before — just hoping you’ll take the excuse of the new year to get started.
Measure Your New Year’s Resolutions
I’ll wrap by offering a final piece of advice. Whether you pick one of these to start or whether you tackle all of them, measure your progress. If you charge at an activity just for the sake of doing it, frustration comes easily and you may give up. If you quantify a goal, you may still become frustrated, but you’re much more likely to fight through the burn.
Day one, you can easily quantify any of the above within your codebase. Do so, and then set up a way to continue measuring it and quantifiable goals to reach. You’ll get there before you know it.
Have a happy new year. Hopefully, it's one filled with better quality code.