Experienced and even some inexperienced programmers may sneer at my attempt to define such a commonly known term, yet successful refactoring cannot be achieve without knowing precisely what it is. Before writing about the process of refactoring code, I will attempt to define it in a precise, clear manner. The definitional process will begin by outlying the process of defining a word in general. That general process will then be applied to task of defining of what refactoring is. Let us begin by defining a process for creating definitions.
Every word and concept has a synoptic meaning that serves as a bird’s view; the nuances and exceptions are stripped away and what is left is the simplest, most common meaning. This definition must be established first, as the more subtle aspects depend it. Then, nuances are added and exceptions are appended. For complex words and concepts, there may be many nuances and exception, as a word or concept may be quite varied; however, all nuances and exceptions are still dependent upon the original concept described in the synoptic definition. In short, the definitional process involves elucidating a synoptic definition, and then, laying out both the nuances and exceptions to that original concept.
How can the concept of refactoring fit onto the process described above? At its core, refactoring is a simple concept, the reorganization of code. Synoptically, refactoring is simply reordering. As daunting and dizzying as refactoring may be, reorganizing and reordering is all that it is. Nuances and exceptions exist that make the concept more complex, however.
What is the purpose of the reordering and reorganizing? The classical purpose of refactoring is to improve understandability without changing functionality. Understandability is a nebulous term that floats about without shape; what exactly does it mean? A developer, who is only vaguely familiar with a program and has not written any of the code, is tasked with understanding how it works; how easy will that process be for him? An understandable program, relative to its complexity, should make that process easy. Understandability, therefore, is the degree of ease, relative to a program’s complexity, to which its logic can be understood.
Refactoring attempts to improve understandability without changing the functionality of the program, but what does refactoring look like. An extract method is the most salient example. A block of code is “extracted” from a method to create another method, and this method is then called from the original. The reordered code should be more understandable, yet the functionality has not changed. This concept of changing the organization of code to improve understandability without changing functionality as demonstrated by the example of an extract method is the core nuance of refactoring.
There is an exception to that nuance in my mind. Refactoring is not technically supposed to modify functionality, yet modified functionality can often lead to improved understandability. If changing the functionality of a program allows the developer to refactor that application in a more understandable way, then that modification is more refactoring than redesign. If that modification is so radically different as to be unrecognizable to the original, however, then redesign has occurred and not refactoring. Yet, changes to functionality that are not as extreme but aid in understandability may be refactoring and not redesign. Admittedly, this exception is subjective and belies the precision of the definitional process that I have described. Unfortunately, there is not precision in this matter, but stating the exception is still important as redesigns can actually just be refactoring that bends the rules a little. The exception of redesign as refactoring adds a key exception to the concept of refactoring.
However, I would like to add an exception to the one described above. The functionality of a program cannot always be tweaked even if the tweak makes the program better in every aspect. Refactoring through small changes in functionality may not be allowed. If a change has been identified that would make the program much easier to understand, then change should be floated by the customer. Do not make change before discussing it with the customer, and do not make the change if the customer does not want it. If the customer likes your idea, then by all means implement it. This is a key exception to remember.
In summary, the core concept and even the core nuance of refactoring are straightforward, yet the subjective exception that I posited provides a bit of ambiguity. If change modifies the functionality of the program slightly but definitely makes the program easier to understand, then that change is probably refactoring, but determining the when refactoring becomes redesign is definitely not precise. That imprecision adds complexity to the process. Imprecision aside, refactoring is generally easy to understand, yet still more complex than it appears.