Using automated refactorings allows us to make changes to our code without introducing behavioral changes. It is essential when working with code that does not have a test suite.
How many times have you made a typo in your code that introduced a bug which you didn’t discover before it was too late? It happens to all of us, me included. That is why we want to make sure that we always have a safety net from tests to make sure such errors get found instantly. But what do we do if there no tests in the code? And we have to refactor it to actually introduce tests?
When working with legacy codebases, usually, there are no built-in support for testing. So, you might easily end up in a situation where you need to change the code to actually introduce tests. But what if you made a typo while you were making the changes needed to add the tests?
You could risk that it would never get found, and be hidden until the code reaches a production system. But luckily, most modern IDEs have features to help us in this situation. They are built-in refractory tools that allow us to have the ideas to change it using a wizard.
Since the changes are controlled by a system, there is no danger of us making typos. Let’s for example say we have a huge method that we need to refactor because part of the method depends on a class that’s difficult to instantiate like a database object but have hard time create test for the method.
We can use the extract method feature in most IDEs to break the method into smaller pieces such them that we can test them individually. But please resist the temptation to mix automated refactorings with manual edits.
It’s important to have safe edits separated from manual edits. As soon you have tests in place, you can start to refactor the code into a better state. To showcase how to use automated refactoring tools, I used a code kata called the glided rose. It contains a convoluted method with complex logic.
It will be used as an example of how to use automated tools for refactoring. When looking at the code from the gilded rose, we see that we have one large method called updateQuality.
It contains a for loops that loop items and the purpose of this item is, of course, to update the quality of the items but also change the sell date, so it has actually multiple responsibilities, which is not good.
So, if you scroll to through the method, you can see it contains quite a lot of nested if statements. So, we would like to be able to test this method, but since it’s so huge, it is going to be difficult to reason about that, so we would like to break it up into smaller pieces to be able to test it individually.
But the danger of doing that manually is, of course, that since we don’t have a test harness, we have no way of knowing if we introduce errors while we do this refactoring so we would like to do the refactoring in a way that makes impossible for us to actually introduce errors.
One way to do this would be to use the extract method a feature of your IDE, because that makes the refactoring automated and lessens the ability to introduce errors in the process.
So to actually do the refactoring we can start by marking the first part of the if-else statement and this code deal with updating the quality of the items you can see here that it updates quality with -1, and we can we see further down it updates the quality to +1 and the same thing down here and still working with quality.
So, it seems this part of the code deals just with updating the quality. So, if we invoke the extract method refactoring, we can see that it gives us a dialogue where we can type in the method name, and we call that updateQuality.
So, when we do this refactoring and we see that we now have an updateQuality method which is down here. We also have a part of a code which deals with updating the sell-in date. So we can do the same thing, extract the method.
Now we have the last if statement in this method which deals with updating quality when the sell-in date is less than 0 and we will mark that as well. We invoke the refactoring so we can call that update quality when sell-in date is negative.
So now we have actually managed to extract the methods which a much smaller and much easier to test. So instead of testing this huge method, we can focus on testing this individual part.
Since we used the refactoring tool, we are 100 % sure that we didn’t introduce any change in behavior because that’s governed by the refactoring tool.
Right now, the methods set to private, and we need to change those to be public, so we have to access them from our test cases, and as soon as we have the tests in place, we can start refactoring them manually instead of relying on test tools to do it.
But it’s a good start to have the initial set up to make it much easier for us to test.