Refactoring Browser

The Refactoring Browser is a tool that automates some Re Factorings for Smalltalk. See st-www.cs.uiuc.edu


This is absolutely the greatest piece of programming software to come out since the original Smalltalk browser. It completely changes the way you think about programming. All those niggling little "well, I should change this name but..." thoughts go away, because you just change the name because there is always a single menu item to just change the name.

When I started using it, I spent about two hours refactoring at my old pace. I would do a refactoring, then just kind of stare off into space for the five minutes it would have taken me to do the refactoring by hand, then do another, stare into space again. After a while, I caught myself and realized that I had to learn to think Bigger Refactoring Thoughts, and think them faster. Now I use probably half and half refactoring and entering new code, all at the same speed (I should instrument to measure this). -- Kent Beck


Discussion about using shell tools to rename symbols moved to Read Write Grep


Changing names is the least of its tricks. Some others are:

Extract Method -- make a submethod out of the selected text. If there is already an equivalent method, optionally invoke that instead.

Inline method -- put the invoked code in place of the invocation. This even works for methods in other classes.

Move to component -- move the code for a method to another class and invoke it

These three together are extremely powerful. For example, if I notice

area := aRectangle right - aRectangle left * (aRectangle bottom - aRectangle top). ....

I select the statement to the right of the assignment and "extract method", naming the new method areaOf:. Now I have:

area := self areaOf:
aRectangle.

...

areaOf:
aRectangle

^aRectangle right - aRectangle left * (aRectangle bottom - aRectangle top)

Now I notice that aRectangle cares a lot more about this message than I do, so I "move to component" and choose aRectangle (other possible choices are my instance variables). The type inference stuff generally does a great job of determining the class or classes of aRectangle, or I can type the classes in. I choose "Rectangle", and name the new method "area". Now I have:

area := self areaOf:
aRectangle.

...

areaOf:
aRectangle

^aRectangle area

Rectangle>>area ^self right - self left * (self bottom - self top)

Now, areaOf: isn't doing me much good, so I go to the original method, select "areaOf:" and "inline method". Now I have:

area := aRectangle area. ...

Rectangle>>area ^self right - self left * (self bottom - self top)

Now I can imagine extracting "self right - self left" into "width", etc.

The best thing about Refactory is how safe it is. As long as you don't manually edit the source code, you are nearly guaranteed (modulo things like choosing the wrong class for a "move to component") that you won't change the semantics of the program. The more I use it, the more aggressive I am slamming logic around until it makes sense.

Some other cool tricks:

Add parameter -- add a parameter to every implementor of a message, and to every invocation of the message (with a Default value)

Remove parameter -- if no implementor of the message uses the parameter, remove it from the methods and the invocations

Cross referencing from inside the source code -- select any program element in the text and you get a choice of several specialized browsers - senders/implementors of a message, readers/writers of a variable

Rename -- you can rename classes, variables (all types), and messages

Abstract/concrete instance variables -- make all references to an instance variable go through a message, or make all references direct

With unlimited undo, you can bravely try experiments that might not pan out.


Using search/replace to perform renaming refactorings ignores the fact that every place the name occurs shouldn't always be renamed (the syntax of the methods). This is especially true for badly named variables. For example, one person might have named a variable "i" instead of a more descriptive name such as "minimalElementIndex". Now if you were to replace "i" with "minimalElementIndex" using search/replace, your program would no longer work since you probably refer to some type such as "minimalElementIndexnt" instead of "int". -- John Brant

'' I found myself with a lot of longerfaces once when I did this.

... and if the "i" being replaced above were in a quoted string e.g

String name = String("Brat Simpson");

you'd get

Str''''''minimalElementIndexng name = Str''''''minimalElementIndexng("Brat S''''''minimalElementIndexntmpson");

You'd at least need to do lexical analysis to work out which lexemes need to be renamed (and apply the correct kind of substitution.)


My understanding with the refactoring browser is that, unlike any script you will write in an editor, it guarantees that the code won't change its meaning. I got this message from one of the browser authors when I was asking why it didn't let me tune the accessor code that it generates when changing from raw instance variables to accessors. His answer was, "well that changes the meaning of the code, so it is not refactoring, even if it is useful." Ahhh, I thought, and understood something about refactoring. -- Alistair Cockburn


Don Roberts, John Brant, and Ralph Johnson, A Refactoring Tool for Smalltalk, "The Theory and Practice of Object Systems", (3) 4, 1997.


How does the Refactoring Browser safely refactor without type information? For example, doesn't it need to know what objects are of a particular class in order to rename a method of that class? Does it just guess? -- Ka Ping Yee

It does not just guess. It looks for special cases. Almost always one of the special cases applies. But sometimes it will tell you that it cannot perform a refactoring.

We originally thought that the lack of static type-checking would make it hard to build a refactoring browser for Smalltalk. Lack of type information is a disadvantage, but the advantages of Smalltalk made it a lot easier to make a refactoring browser for Smalltalk than it would have have been for C++ or Java.


Has any work been done on generalizing this, or making a C/C++/Java Refactoring Browser? Naive optimism would lead me to think that this would not be an overwhelming effort. -- Pete Hardie

I think it would be doable for Java. A Refactoring Browser that would work for the whole C++ language, and not some sane subset, would probably be Ai Complete. Just think of all the possibilities for creative use of macros and templates. -- Stephan Houben

I use emacs and JDE quite a lot for writing Java code. Maybe it would be possible to use Emacs Lisp to write refactoring utilities. I might have a go at it when (if) I have the time. -- Bernard Michael Hurley

Actually, there are a few refactoring tools available for Java... see Refactoring Browser For Java. However, these tools support only a small portion of the refactorings available in the original Refactoring Browser for Smalltalk.


I've never used the Refactoring Browser (I don't know Small Talk). I am familiar with JRefactory. JRefactory integrates into various IDEs. Is the Refactoring Browser a stand-alone tool?

I'm quite new to Smalltalk myself (downloaded Visual Works just last week), but as I understand it, any implementation of Smalltalk includes a complete development environment in which all code is edited, and the Refactoring Browser runs inside this environment. There are some interesting technical reasons for this, but I'm afraid I don't understand them well enough to explain at all coherently - perhaps some more experienced Smalltalker could help?


Has there been any work in refactoring browsers for Functional Programming languages such as Common Lisp? It seems that the existence of closures would make operations like add/remove parameter quite difficult to perform safely in the general case, and difficult even to be sure of the safety of.




Speaking of which, how do the refactoring capabilities of Eclipse Ide and Intellij Idea compare to Refactoring Browser?


If the code-units (routines, methods, classes) were stored in a database, then renaming would be a simple query. Greencodds Tenth Rule Of Programming again. Something else to explore: if auto-generated unit ID's were used instead of names by the software-engine, perhaps propagation-based renaming would not be needed. Propagation renaming leans toward a Once And Only Once violation. If you change/rename your primary key often, auto-ID's may be the better approach. See Table Oriented Code Management. -- top



Prolog also has a Refactoring Browser, called ViPReSS, integrated with the VIM editor.


See original on c2.com