Yes You Are Making Changes, But That Doesn't Make It Refactoring!
Posted by pramatr on September 26th, 2008
There are some words in software development that overtime lose all meaning. The more these words are used, and importantly, the more they are used out of context, the more the original meaning is lost. It becomes just one of those words that is fitted into a conversation without even thinking about it. One word that often suffers from this problem is refactoring.
The term Refactoring is widely used throughout software development. Martin Flower is one of the primary documenters of refactoring, and popularised it in his seminal book, Refactoring: Improving the Design of Existing Code. Many people who use the word refactoring however, have never heard of the book and more importantly don’t have a clear understanding of what refactoring actually is.
Refactoring is described as; a disciplined approach for modifying code without changing it’s externally observable behavior. This approach is focused around applying small changes to the code, each of which maintains the existing behaviour. By incrementally applying a number of refactorings, the code can be modified in a measured and controlled manner. Extreme programming embraces this approach with a rule named refactor mercilessly.
Alistair Cockburn wrote; “What we want to express sits in a crack between all the words we possess”, it just so happens that for many people (including myself), one word that is readily available is refactoring.
Team leader: So what are you currently working on?
Developer: I’m just refactoring some code.
Team leader: Are there any particular refactorings that you’ve found useful?
Developer: Yes, I’m refactoring the code.
Team leader: No, I mean specific refactorings e.g. rename method, extract method, etc……
Developer: Yes I’ve been doing all that sort of thing.
Team leader: Have you any idea when you might be finished?
Developer: I’m just trying to get the code compiling again, this might take a few hours.
Team leader: Hmmmm ok, I’m presuming you’ve been reviewing, improving and running the unit tests frequently?
Developer: The code doesn’t have any unit tests, so there’s nothing to run.
Team leader: Do you think it might be a good idea that you write some before you start refactoring? How do you know that your code will work in the same way as it did?
Developer: Errrrr……
If changes are informal or ad-hoc, this might be acceptable, but this isn’t refactoring. If changes will take days or weeks, or the code is simply being rewritten this isn’t refactoring. If the code is just being hacked, this really isn’t refactoring. Changes made in a controlled way are much more likely to be successful, but again this doesn’t necessarily mean refactoring.
Refactoring is in many ways a victim of it’s own success. Many teams have found refactoring to be a successful approach to making code changes in the past, leading to many people discussing all code changes as refactoring. Sometimes this is simply due to a lack of understanding, other times it’s a lack of care and attention for the words being used. Sometimes however people use the word refactoring to give the illusion of making disciplined changes, whilst reverting to plain old hacking.
There is a common perception amongst some teams, that every code change is refactoring, “if you aren’t refactoring how else do you make code changes?” The truth however, is that not every code change is a refactoring, nor does it make sense it to be. Even if the code isn’t truely being refactored, it is still possible to adopt many of the activities associated with refactoring.
Changes made in a structured and disciplined manner, offer far more control and are therefore often far more successful. Important questions therefore need to be asked when changes are being proposed. Are the changes being made with the benefit of a suite of automated unit tests? Is each code change being kept as small as possible? Are the code changes being incrementally applied? Are the changes being continuously integrated? Are the IDE’s tools being fully leveraged to make changes easier? Do other developers understand the approach being used to change the code?
When making changes to code, it’s very difficult to understand the associated risks without a solid understanding of the approach being proposed. If a project is deemed to be too risky it might be postponed and rescheduled for a more appropriate time. To aid understanding within a team, instead of simply using the word refactoring to describe changes, developers need to fully understand the approach they are using. Are they answering yes to the important questions (outlined above), and more importantly, if they aren’t, is that acceptable?
If the actual approach is refactoring, that’s great! It gives other developers some idea about the way potential changes will be made, and the style of approach is well understood. It integrates very nicely with many other best-practices and structured development techniques. This can significantly reduce the potential risks associated with changes, thus helping prevent the introduction of new bugs. But it is also acceptable to make changes that aren’t refactoring, whilst performing many of the same activities. It is therefore vitally important that developers talk about changes in context, and make them in a structured and disciplined manner, regardless of the name being applied to the approach.
If you are refactoring great, if you aren’t don’t be afraid to use a more appropriate word instead!
Motivation behind the post:
Following a few comments regarding this post, I want to clarify the motivation behind it. I’ve known about refactoring for a good number of years, and I’ve also often claimed to be refactoring. Last week I found myself talking about refactoring completely out of context and I was basically playing the role of the developer in the mock conversation. I was claiming to refactor some code, but actually this wasn’t the case at all. Some of the code was rewritten, other changes were unstructured, all without the benefit of unit tests. By telling people I was refactoring, I was giving an impression of control where non-existed, I personally don’t see this as a good thing! In this situation, I believe it’s much better to come clean and admit you are making unstructured changes, and if possible rectify the situation.
Testing without refactoring:
Another point that was raised, was that I had suggested if you don’t have unit tests you aren’t refactoring. I don’t think I did suggest this, but I thought it was worth clarif
ying the point. It is completely possible to refactor without tests, but as many other people have commented, it’s dangerous, it’s scary, difficult and time consuming. This is obviously dependent on the nature of the refactoring.
If the refactoring is a simple rename method, it is typically assumed to be fairly safe. I’ve made this mistake before and broken code when making changes, simply because I wasn’t aware something was called by reflection. I’ve also broken Spring configuration because the AOP used method name matching. Simple changes can still break code, no matter how simple they are!
Refactoring and testing typically go hand-in-hand, verifying the changes that have been made. It is possible to verify this other ways, but if this is a manual activity it can be extremely time consuming.
Related Links:
After writing this entry, I discovered Marten Fowler documented this phenomenon in a post entitled, RefactoringMalapropism. For anyone that’s a fan of the semantic diffusion that Martin describes, I’d just like to add that this was written using an agile blogging technique
.
