Thoughts on tools that help you refactor
published: Wed, 4-Feb-2004 | updated: Thu, 27-Oct-2005
I've just finished a small contract and thought it interesting enough to blog about my experiences with it. Neither the company nor the code are germane to this particular article (indeed I can't talk about them, obviously); instead, it's how I implemented the code that's of more importance.
The essence of the work was to implement a particular kind of priority queue. There was nothing like it in the literature that I could see, so I had to invent a new algorithm to satisfy the requirements. In bidding for the contract, I'd pretty much decided ahead of time how I was going to implement the algorithm, however, in my defense, considering what happened, I still had some doubts about efficiency and the like.
I started out in my usual manner these days, using Test-Driven Development. Write the test, see it fail, write the code, see the test pass, refactor the code for simplicity and efficiency and to remove code smells. Within a few hours, I started to notice that the algorithm I'd devised wouldn't work, or, rather, it would work but it was getting to be nastily complex in its implementation.
I stepped back an hour or so and though again about the problem. My tests and code so far were pointing in a different direction than I'd originally envisaged, and I was trying to force a change in the path my development was taking. No wonder things were getting complex. The interface to the priority queue algorithm was pretty simple: the usual Enqueue() and Dequeue(), plus a few knobs to twiddle to tune performance and to invoke the queue's special functionalities. My test cases so far had dealt with getting items in and out of the queue, I was stuck on the knob-twiddling part.
Then the answer dawned on me, I needed to do so and so instead. It was time for a major refactoring operation.
In olden days, making major structural changes to your code used to be a big pain in the proverbials. Nowadays, it's a lot easier, providing you have the tools.
The first tool is NUnit. I'd already written a small set of test cases to prove that enqueueing items worked and that dequeueing items produced the same items but in the correct order. These unit tests didn't concern themselves with the internal structure and flow of my code, just that what went in (properly) came out (correctly). Any changes I made to the implementation were tested within a couple of seconds.
The second tool is NUnit Addin. This is a nice Visual Studio add-in that enables you to run NUnit tests from within Visual Studio by right-clicking on the test case (or on the test fixture) and selecting Run Tests. No switching to the NUnit GUI application, everything is right there in Visual Studio. You can get a nice workflow going of writing tests and code and running them without leaving Visual Studio. The add-in also enables you to debug the code under test from the test case, should you need to.
The final tool is C# Refactory from Xtreme Simplicity. This is another add-in for Visual Studio, a commercial product this time, which does automatic refactorings. For example, you can select a section of code, right- click on it, select Refactory's Extract Method menu option, and, lo, the code is extracted to a new method (which you name) and a call to the new method replaces the selected code. It has the smarts to work out what parameters and return types the new method should have.
I can't begin to tell you how much a tool like C# Refactory makes to your coding experience. I don't want to convert this article into a marketing spiel, but C# Refactory enables you to extract a method, extract an interface, extract a super class, encapsulate a field member into a property, change a method signature (as well as all the calls to it), and to rename an identifier, amongst some other facilities (including calculating cyclomatic complexity). And it's fairly intelligent about it, patching up code elsewhere that has to be changed. The nest version of Visual Studio, code-named Whidbey, will have some of these types of refactorings available as well (in fact, I worked on some of them whilst working at Microsoft).
(Note to developers using other languages. For Java programmers, you're pretty well served. JBuilder from Borland does some refactorings, as does Eclipse with its Java Development Tools, but the king of the hill is definitely IntelliJ IDEA from JetBrains. Eclipse is possibly the best bet to try this stuff out since it's free. For Delphi programmers, tough, I know of nothing, nor does a Google search produce anything apart from pages on TDD. As far as I know, Visual Basic programmers will have to wait for Whidbey for some refactorings.)
How does it make your coding more pleasurable? Let's take my favorite
couple of examples. The first one is renaming an identifier. How many
times have you written code where you named a particular identifier X,
but then after a while it grates on you (maybe its not descriptive
enough, or it clashes with another identifier in your code, or you
made a silly spelling error) and you want to rename it to Y. Depending
on the name, this can be really simple with search-and-replace, or it
can be remarkably nasty (Rats, this variable
i should be
itemIndex; now to search for
i...). With a
"rename identifier" option, you can name your identifiers whatever you
like to begin with and easily rename them later on. (No kidding, but
this can be very liberating.)
The next one is extracting a method. Once you've used this you'll wonder how you coded without it. You can write code as you normally do, but as soon as you find yourself copy-and-pasting some code from one method to another, you extract that code to a method instead and code a call to that new method. Suddenly, it's much easier to keep code duplication out of your classes. Suddenly it's much easier to write simpler methods (enter cyclomatic complexity again) that are easier to understand and maintain.
Indeed, there have been times where — yes, I admit — I've cut corners in my code because I couldn't be bothered to refactor; it would take too long for a perceived small benefit. With a tool that refactors for you, you become a better programmer because you can write cleaner more understandable code.
Using these tools, I was able to restructure my code into a simpler and more efficient implementation in a short amount of time. All of the tools helped; none were dispensable. The tests showed that the restructured queue worked after the restructuring exactly as it had done (thanks to NUnit) and running them as I refactored was easy (thanks to NUnit Addin). Extracting out an interface and a super- class, extracting out various methods, and renaming identifiers all over the place was trivial.
I strongly recommend downloading NUnit and NUnit Addin (but, I'm sure you already have if you read this blog regularly). And I just as strongly recommend purchasing C# Refactory. I know that in a few months (6? 9? 12?) the new Visual Studio will be out and it will have refactoring in the box, as it were, but for $99 you can reap the benefits of automatic refactoring right now. The time it will save you will amply repay the small cost, and the benefits of better code will help you for much longer.
Update on tools for Delphi
Since this article was first published, I've had a couple of e-mails stating that I was wrong about there being no refactoring products for Delphi. The two that were mentioned to me were:
- Castalia: this is a little like CodeRush but also offers some refactorings. This product is new to me, but then again I haven't been fully active in the Delphi arena for a while.
- ModelMaker: this is essentially a UML design tool, which apparently also provides some refactorings.
My readers didn't mention the breadth of refactorings available, nor how well they worked so I decided to do a little investigation.
From the Castalia's web site I see that it covers the refactorings I use the most, and the refactorings work across the whole project. From my quick glance at the information, I think it works for Delphi 5, 6, and 7. The product is $99, so maybe I'll try it out on a project I have in Delphi.
I knew about ModelMaker before, but didn't realize it performed some refactorings. Unfortunately, I found the information and the presentation on their web site somewhat confusing. For instance the feature list for the main ModelMaker tool (which I presume is their two other products rolled up into one — but, hey, don't ask me, I'm guessing since it doesn't say) doesn't mention refactorings at all. The ModelMaker Code Explorer tool (the screenshot looks like it's a separate program from the Delphi IDE, but the text states that it is integrated; confused, moi?) mentions refactorings and includes the ones I like. ModelMaker Code Explorer is 99 euros (about $100).