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.
I’m currently working on a project to write a Smalltalk implementation of a very involved communication specification. Part of the specification involves writing
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
writeBlock are instance variables of the class where this is defined, and that the
Node is represented by the
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.
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
I could do this manually, but VisualWorks provides the Extract Method to Component refactoring, so I’ll use that instead.
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
Extract Method to Component.
It asks me which variable I want to extract to. I choose
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
UAVariables 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
The refactoring is now done!
UAVariable now has a new
Note that it was smart enough to replace
aUANodeRole in the original code with
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.
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.