The term software refactoring can be found as far back as the 1990s and refers to the act of changing software implementations with the goal of making it easier to understand as well as cheaper to maintain and evolve while still preserving the original intended behavior and exposed interfaces [1, 2]. However, the concept of software refactoring has matured significantly over the last 30-40 years due to the contributions of many thought leaders like Martin Fowler, Kent Beck, Robert Martin and Joshua Kerievsky to name just a few [1-3].
Software refactoring is an often used tool for paying down technical debt to reduce the cost of maintaining and modifying software. Here technical debt refers to the extra burden a development team experiences when introducing changes to a codebase due to prior prioritization tradeoffs favoring time-to-market over investments in modular, cohesive, reusable software design. In practice this often looks like kludgy quick fixes, workarounds, and one off patches over full-scale solutions.
I’ll give a few justifications for why I feel software refactoring is important, ranging from more philosophical (2nd law of thermodynamics) towards being backed by commonly accepted management principles (Lean management’s 5S). However, justifications for software refactoring, and more broadly addressing tech debt, have been fraught with discouragement and skepticisms. I see this largely due to scoping issues and insufficient clarity of intention, process, and opportunity costs of performing refactoring. In many cases refactoring efforts have left bitter tastes in the mouths of business leaders managing engineering investments who have previously been persuaded to bite off more than engineering resources can chew, which of course is a common source of most software failures. Any change in software whether enhancement, bug fix or refactoring, should always be small, well defined in scope, and introduced iteratively so it's no wonder when refactoring is proposed and undertaken in such big bang approaches the result is a big bang outcome in all the wrong ways. No matter the justification you settle on, be sure to limit scope and remember that practice is required to gain mastery. Practice is iterating until you get it right and this is what I refer to as the Practice of Software Engineering.
I’ll get the more idiosyncratic philosophical justification out of the way first which leans on the 2nd Law of Thermodynamics, perhaps with some liberties taken. The 2nd Law of Thermodynamics tells us energy must be expended to avoid the natural tendency of a system to decay towards disorder (aka, increased entropic randomness) overtime [4]. Essentially the scientific law states that without application of energy to impose order to the elements of a system it will decay overtime to disorder. I like to think of a software codebase as such a system. This is because my experience has shown that a codebase withheld from refactoring, which is an application of energy, will decay towards disorder. Refactoring, my friends, is all about imposing order on a codebase to reduce or avoid decay.
Signs and Symptoms of Software Decay
Causes of Software Decay
My second justification is centered on improving the developer experience by optimizing code for cognitive ease through refactoring which in turn has been shown to increase developer productivity, software quality, and reduce developer attrition [5-7]. The premise here is that given code is read many more times than its written then improving readability will naturally benefit the developer experience while also improving the code. This is a win win.
My final justification is centered around a Lean Management method known as 5S which aims to optimize the workspace for productivity by making things easier to find, easier to access and easier to identify non-value adding items or movements by following a simple 5 step process [8]. If you consider the codebase to be the workspace of Software Engineers then these are powerful concepts to apply to the Practice of Software Engineering. In fact, I’ve found the 5S method to be so useful I’ve incorporated it into a methodological approach or framework of thought for reading code and identifying what I like to call refactoring candidates.
My approach and advice to where refactoring fits into the planning and execution of software delivery is simple, I advise refactoring with purpose and refactoring continuously. This means every time you’re browsing code to implement a bug fix or new feature that should be an opportunity to identify potential code refactoring candidates. Any time when you have a reason to be reading code is an opportunity to identify refactoring candidates so, think of things like a PR review, code walk through, or pairing session as all great opportunities to start the refactoring dialog, internally or externally with other developers.
When I’m reading code I often tag refactoring candidate code blocks I observe with comments to keep track of them. Then when I have enough of an understanding of the changes I need to make to implement a bug or feature I take into account the potential refactorings I’ve identified as part of the design. Which refactoring candidates are chosen to invest time and energy on depend on the following set of guidelines.
The “refactoring candidate” term I’ve been using is my preferred verbiage for the more common synonym of “code smell”. While I do acknowledge that code smell is a clear descriptor for an area of code that indicates understandability challenges are present I’ve found the term refactoring candidate better facilitates team discussions especially where the author of said code small is likely to be present. In all my human experiences I’ve repeatedly observed that coachability and learning rate tend to track personal confidence which seems imminent to sink when one's intellectual work is being compared to a foul odor. Therefore, in the spirit of promoting a confidence building growth oriented culture I prefer speaking in terms of refactoring candidates over code smells. Readers can be comforted to find they can consult the catalog of refactorings for remediating many such code smells maintained by Martin Fowler representing the collective work of the earlier mentioned software thought amplifiers [10].
Engineering is primarily concerned with applying analytical methods to design solutions that increase productivity, or otherwise optimize processes and systems to be more efficient (9). Lean management similarly puts a focus on continuous improvement by applying analytical methods to eliminate waste from processes and systems thus it nicely aligns with Engineering. Having drawn this correlation between Engineering and Lean concepts I’ve learned to find ways to incorporate them symbiotically into my work habits. I’ve found that 5S can serve as a useful thought framework for both reading code and incorporating continuous refactoring into that process.