Automated refactoring has come a long way. I remember, years ago, when I first saw John Brant and Don Robert’s Smalltalk Refactoring Browser at OOPSLA. I had a sinking feeling in my chest. It was great, it was powerful, and I couldn’t imagine Java tool vendors ever creating anything similar. After all, there wasn’t any demand – people didn’t even know what refactoring was. I thought that automated refactoring was going to be just another niche idea that started and ended in academia.
Well, I was wrong and I’m glad that I was wrong. Vendors took the leap. JetBrains (under the name Intellij) started to create a refactoring plug-in and then they decided to create Idea, a full IDE. Eclipse came along as well, adding refactoring support from the beginning. Now, automated refactoring tools are commonplace in the Java world but I think we can go further.
Here’s a little hit list of things I’d like to see in a refactoring tool; things I do all the time. I’m not sure that all of them can be automated easily, but I’d love to see an attempt.
Extract Class
Yes, Eclipse and Idea give us Extract Superclass, but why don’t they give us Extract Class? It seems like it would be relatively simple. An IDE could use roughly the same dialog that it uses for Extract Superclass, but instead of creating a superclass the IDE could create a new class, declare an instance of it in the old class, and then move all of the fields and methods that you’ve selected.
Introduce Instance Delegator
This is a minor one, but it’s handy. There are times when I want to create a delegating method for a static method. Unfortunately, Eclipse always makes the delegator static. It would be nice if there was a checkbox for this. I often make instance delegators when I’m trying to create a seam around a static method call.
Introduce Parameter Object
I’d like to be able to select a set of parameters to a method and have my IDE create a new class for them, fixing up the code as it does it so that all of the references to the parameters are now references to the class. Again, this is handy when moving away from overly long parameter lists. I don’t think this has to be limited to parameters either. You should be able to select any group of fields or local variables and ask the IDE to create a class for them.
Encapsulate Class/Package
Many API developers still don’t realize that when they make classes and methods final they often make it impossible to mock them without special support. Eclipse makes it easy to create delegate classes, but it’s still a little harder than it needs to be. It would be nice to have a feature which takes a set of classes or a package and generates an interface and wrapper for each class. I can’t imagine using it all the time, but it sure would come in handy when I'm working with some of the more paranoid frameworks and libraries.
Move Statement
This is the big one. I’d like to be able to select a statement and move it up above the statement above it or below the statement below it, but only if the IDE can be certain that behavior will be preserved. In general, this problem is intractable – you can’t always tell whether a move would preserve behavior, but there are computable cases. No one would want to have their IDE freeze for as long as it takes to compute the worst of them, but if a tool allowed moves in the simple cases, I’d be happy.
That’s my short list for today. What would you like to see?
I'd like all the power of the Refactoring browser at my fingertips when I *do* want to change code.
Why do we have these powerful, structure-aware editing tools and then only allow ourselves to use them for part of the time we're coding?
To quote Ralph Johnson: all software development is program transformation.
Posted by: Nat | March 14, 2007 at 01:50 AM
WRT Move, if you're only moving up or down a couple of lines, doesn't Eclipse's Alt+Up Arrow/Alt+Down Arrow hit the spot? It doesn't have the common sense to know that the code will break, but you've got that covered with your tests anyway.
Posted by: Brandon | March 15, 2007 at 03:12 PM
parameter object. Hmm...
I'm never sure if this is a pattern or an antipattern. I worry that it is actually pushing more requirements on the callers of a method. If you look at how some framework writers do it, it actually pollutes the users of the class. Now they have to not only give the values, they have to construct an object to hold them. If this is done it a constructor, it is no easier for the caller to construct the object to pass it than to call a difficult method. If it has to be done via setters, then it requires more code on the caller's side.
I know it's a tough game, and you make tradeoffs, but I consider a data object that holds parameters to be worse than a parameter list.
Calling a method should be as easy as possible, not just as small as possible. I shouldn't have to do setup to call the method. My principle is that a polite class has the absolute minimum burden on its callers. Having to create an object and fill it in is setup, and will occur (roughly repeated) in all of the callers (DRY). It will make the class less attractive to use, and will detract from the clarity of the caller.
If, on the other hand, the group of parameters recurs in calls to various methods of various classes (possibly out of order sometimes), then it's an easy guess that it ought to be a class with its own behavior and a defined lifetime.
I suppose you've already considered all of that, but you brought it up, and it's been bothering me a long time. And I'm in a ranting mood (not your fault).
Tim
Posted by: Tim | March 16, 2007 at 08:20 AM
Brandon wrote: "WRT Move, if you're only moving up or down a couple of lines, doesn't Eclipse's Alt+Up Arrow/Alt+Down Arrow hit the spot? It doesn't have the common sense to know that the code will break, but you've got that covered with your tests anyway."
I keep wishing for that but I spend a lot of time visiting people who aren't converted yet. :-). I think a tool which did some real analysis could help people recover when they don't have tests. It would help us too. It think it's nice that the better IDEs do some real analysis for things like Extract Method
Posted by: Michael Feathers | March 16, 2007 at 08:55 AM
Tim, yes, it's all judgment. The thing I notice though is that when you do notice values that hang around together in a couple of places and make a class, you often discover behavior that should go on that class over time so, the data object is just an intermediate state.
Posted by: Michael Feathers | March 16, 2007 at 08:59 AM