My Favorite Refactoring
Many IDEs provide automated refactorings that can speed up development. Features like smart renaming and inlining or extracting variables and methods are really nice. There’s one refactoring that very few IDEs provide directly, but that I find particularly useful: Extract Method to Component.
So far, the only place where I’ve seen this refactoring is in VisualWorks Smalltalk. It’s really a combination of ExtractMethod and MoveMethod, but performing those in a single operation is really handy.
I’ll walk through an example of how it works, and maybe it’ll become your favorite refactoring too.
Before
I’m currently working on a project to write a Smalltalk implementation of a very involved communication specification. Part of the specification involves writing DataValue
s to Nodes
. We started out only supporting scalar values, but recently needed to add support for arrays.
Before writing a value, there are a number of checks that need to be performed, including a check that the type of the DataValue
is appropriate for the Node
being written.
Here’s the basic write
method I started with (note that attribute
and writeBlock
are instance variables of the class where this is defined, and that the Node
is represented by the aUANodeRole
parameter):
As you can see, this method is already quite involved. In order to support arrays, I need to expand on the isKindOf:
check in the middle of the method.
The Node
knows what type of values it accepts, including whether or not it’s expecting an array. It makes more sense for the Node
to decide whether or not the DataValue
’s value is appropriate or not.
I’d like to move that isKindOf:
test over to the Node
.
I could do this manually, but VisualWorks provides the Extract Method to Component refactoring, so I’ll use that instead.
The Process
Note that I’m using a fairly old version of VisualWorks Smalltalk here (7.10.1). In newer versions, there have been a lot of improvements to the development tools, so they look and feel a lot more modern than what you see here.
I start by highlighting the code I want to extract.
I right-click and choose Refactor
-> Extract Method to Component
.
It asks me which variable I want to extract to. I choose aUANodeRole
.
It then tries to figure out which class the variable is an instance of. Because Smalltalk is a dynamically-typed language, there can be a lot of options in the list, as there is here.
In my case, I know that only UAVariable
s can have array values, so I choose that class. Note that I can extract to either the instance side or the class side; in this case, I want the instance side.
If the code I am extracting needs to refer back to the object I’m extracting from, it will ask me what I want to call the back reference. In this case, I don’t have a back reference, so I don’t see that step.
Next, I need to provide the name of my new method. I call it canAccept:
.
The refactoring is now done!
The Result
UAVariable
now has a new canAccept:
method:
Note that it was smart enough to replace aUANodeRole
in the original code with self
.
The original write:with:
now looks like this:
As you can see, the isKindOf:
check has been replaced with a call to the new method: aUANodeRole canAccept: aDataValue
.
Conclusion
Extract Method to Component is a powerful refactoring, especially when you find a case of Feature Envy in your code.
The VisualWorks implementation can handle the case where the new method needs to refer back to the original object.
If the code being extracted has any instance variable references, it will offer to create getter methods so that the extracted code can still access those variables from the new location.
There are complicated cases that this refactoring can’t handle, but it works quite often.
It’s one of my favorite tools to use when working in Smalltalk. I wish that other language IDEs supported it more directly.