Continuous Code Improvement Using Ratcheting
I read a great article over the weekend dealing with the concept of (sorry, this website has been shut down) a legacy codebase in order to achieve the ultimate goal of quality code using incremental improvements over time.
I must admit that reading this article was a bit of a revelation for me. On the surface, the concept of ratcheting in and of itself is nothing new. After all, We were taught from a very young age that the best way to handle a complex problem is to break it down into composite pieces and attack the problem on a smaller scale (i.e. How do you eat a whale? One bite at a time.) However, the idea of implementing ratcheting in a code base was something that I had never thought of before and it seems to be a great way to help cultivate a culture of quality within a software project, especially a large software project.
At its core, ratcheting is nothing more than a check-in script that developers will run locally before being allowed to push to the central repository. This script will create a gated check-in that will ensure each push meets a minimum set of code cleanliness requirements. In order to do this, we can leverage different types of static code analysis tools to create a good baseline to measure against.
It is important to point out that ratcheting is not intended to replace unit testing. Ratcheting serves a different purpose altogether and can be used in conjunction with tried-and-true development practices that have allowed our software projects to succeed for so long.
Why do we need ratcheting?
The main problem with any code base is entropy. Simply put, entropy means that your code will inevitably trend towards chaos (or complexity) over time by default. This effect is magnified exponentially as you add more developers to the project. As a result, what ends up happening is, our once-tidy code base gets transformed into a cave of despair that is full of defects and takes incrementally longer to add new features release after release.
We've all seen it. Maybe Joe the Programmer has a tight deadline and ends up tacking a few extra lines on a method in a class that he's familiar with that "gets the job done ". Now, Joe's excuse for committing this crime will be; "hey bro, it's only five lines, who cares?" The problem with Joe's attitude is that over the course of three years and a few hundred commits on the file, our once innocent class will have morphed into a monster filled with defects and high complexity.
This common scenario is where ratcheting can really show its value. Joe wouldn't be able to check in his five-line-hack as-is because he likely would have violated one of the quality metrics the build script will be checking for (in this case, it would likely be something along the lines of cyclomatic complexity or a method that is too long).
Finally, ratcheting protects us from ourselves. Even in an ideal development situation with teams full of really smart programmers who truly care about quality code, ratcheting can help protect us from the simple little mistakes we all are guilty of committing from time to time.
What metrics should we be ratcheting against?
To be completely honest, I'm not 100% sure. What is important for my project now might not be what is important for your project which also won't be what is important to my project in a year or two.
For my project I am going to start with code coverage and likely move on to cyclomatic complexity, dead code, and duplicate code.
Ratcheting scales up well
Ratcheting also seems to be a natural remedy to the exponentially increasing overhead costs incurred by adding more developers to a project. The more developers you have incrementally improving a code base, the faster the code base becomes the awesomeness it was intended to be.
Since ratcheting is fair and unbiased, it will work especially well with teams that span across multiple continents with different levels of training, motivation, and professionalism.
The two simple rules of ratcheting
- Your commit must not make the existing code base worse on aggregate - Sorry Joe, but your five-line-hack from earlier won't cut it anymore and you'll have to find a cleaner solution before you are allowed to check in.
- Your commit must improve the code base in one or more areas - Oh, and by the way, I hope you added some test coverage to the code you just fixed.
The first rule is absolutely vital to ensure the code base does not get any worse. The second rule is the only way to ensure that the code actually improves over time.
Putting ratcheting into action
Over the next few months, I'm going to start implementing ratcheting in my pod at work and will document my findings on this blog.
One important question I aim to answer is What shape will ratcheting take? Ratcheting can only enforce improvement along the lines of static metrics and is unable to determine whether or not a change or refactoring is good. This being said, will ratcheting merely result in a tidy codebase with the same underlying issues? Or, will ratcheting help empower developers to fearlessly make the kind of improvements that will benefit the system a long time in the future? Hopefully, we'll be able to answer this question and many more as we delve deeper into the practice of ratcheting.