Programming Tools: Refactoring
Refactoring is the process of modifying code without affecting either its input or output; that is, the code's interface remains the same. How do we know that refactoring works? The only objective way to find the answer is by testing the code before and after refactoring occurs. The results should match exactly. This makes testing an integral part of any refactoring effort--you cannot successfully separate the two.
Some confusion exists between what it means to refactor code as opposed to reworking it. Refactoring is a subset of reworking. If you are making no changes to the interface of a program, you are refactoring. If you add or change the interface, you are rewriting the code. Strictly speaking, when you do both together, you are rewriting. However, for political reasons, you still might want to call it refactoring.
When it comes to methodology, refactoring usually is done in small steps. After each step, you run those unit tests originally written for the existing code. Repeat these two steps as needed. Also, a number of refactoring patterns can be followed. Martin Fowler's book (see Resources) contains some basic ones, and Joshua Kerievsky's more recent text (see Resources) contains some more advanced ones. As a side issue, it is interesting to note that most books and products dealing with refactoring use Java as the language of choice. Is that because Java is the most appropriate language, or does Java code need more refactoring?
All the refactoring tools I have seen so far require heavy human intervention. They don't do pattern recognition, so they aren't able to see commonality in code or design.
As noted above, a lot of refactoring tools are out there, especially for Java. Open-source tools are available, some of which are listed in Resources. Commercial refactoring products can be found in the usual way. In this article, I discuss two open-source tools, Eclipse and Bicycle Repair Man. Eclipse is designed for use with Java, while Bicycle Repair Man is designed to be used with Python.
Let's start with Eclipse and Java. Eclipse offers an impressive set of refactoring facilities, including support for:
Copying and moving Java elements
Extracting a method
Extracting a local variable
Extracting a constant
Renaming a package
Renaming a compilation unit
Renaming a class or interface
Renaming a method
Renaming a field
Renaming a local variable
Renaming method parameters
Changing method signature
Inlining a local variable
Inlining a method
Inlining a constant
Self encapsulating a field
Replacing a local variable with a query
Pulling members up to superclass
Pushing members down to subclasses
Moving static members between types
Moving an instance method to a component
Converting a local variable to a field
Converting an anonymous inner class to a nested class
Converting a nested type to a top level type
Extracting an interface from a type
Replacing references to a type with references to one of its subtypes
To give you some idea of what Eclipse's refactoring can do, I chose at random the Java program shown in Listing 1. It outputs an About dialog box.
Listing 1. Random Java Program
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
Label label1= new Label("JUnit");
label1.setFont(new Font("dialog", Font.PLAIN, 36));
Label label2= new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma");
label2.setFont(new Font("dialog", Font.PLAIN, 14));
Logo logo= new Logo();
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = 3; constraintsLabel1.gridy = 0;
constraintsLabel1.gridwidth = 1; constraintsLabel1.gridheight = 1;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(label1, constraintsLabel1);
GridBagConstraints constraintsLabel2= new GridBagConstraints();
constraintsLabel2.gridx = 2; constraintsLabel2.gridy = 1;
constraintsLabel2.gridwidth = 2; constraintsLabel2.gridheight = 1;
constraintsLabel2.anchor = GridBagConstraints.CENTER;
add(label2, constraintsLabel2);
GridBagConstraints constraintsButton1= new GridBagConstraints();
constraintsButton1.gridx = 2; constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2; constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2; constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1; constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
}
First, I scanned the code and saw that two similar fragments of code dealt with labels. Second, I manually brought together all the code to do with labels. Using similar logic, I brought together the code dealing with the button and the logo. This step is shown in Listing 2.
Listing 2. Rearranging the Code
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
Label label1= new Label("JUnit");
label1.setFont(new Font("dialog", Font.PLAIN, 36));
Label label2= new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma");
label2.setFont(new Font("dialog", Font.PLAIN, 14));
Logo logo= new Logo();
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = 3;
constraintsLabel1.gridy = 0;
constraintsLabel1.gridwidth = 1;
constraintsLabel1.gridheight = 1;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(label1, constraintsLabel1);
GridBagConstraints constraintsLabel2= new GridBagConstraints();
constraintsLabel2.gridx = 2;
constraintsLabel2.gridy = 1;
constraintsLabel2.gridwidth = 2;
constraintsLabel2.gridheight = 1;
constraintsLabel2.anchor = GridBagConstraints.CENTER;
add(label2, constraintsLabel2);
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
GridBagConstraints constraintsButton1=new GridBagConstraints();
constraintsButton1.gridx = 2;
constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2;
constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2;
constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1;
constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
}
Next, I extracted each method by first highlighting each method and then selecting Refactor | Extract Method. The dialog box is shown below.

The resulting code is shown in Listing 3.
Listing 3. Refactored Code
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
gbLabel1();
gbLabel2();
gbButton();
gbLogo();
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
/**
*
*/
private void gbLogo() {
Logo logo= new Logo();
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2;
constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1;
constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
}
/**
*
*/
private void gbButton() {
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
GridBagConstraints constraintsButton1= new GridBagConstraints();
constraintsButton1.gridx = 2;
constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2;
constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
}
/**
*
*/
private void gbLabel2() {
Label label2= new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma");
label2.setFont(new Font("dialog", Font.PLAIN, 14));
GridBagConstraints constraintsLabel2= new GridBagConstraints();
constraintsLabel2.gridx = 2;
constraintsLabel2.gridy = 1;
constraintsLabel2.gridwidth = 2;
constraintsLabel2.gridheight = 1;
constraintsLabel2.anchor = GridBagConstraints.CENTER;
add(label2, constraintsLabel2);
}
/**
*
*/
private void gbLabel1() {
Label label1= new Label("JUnit");
label1.setFont(new Font("dialog", Font.PLAIN, 36));
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = 3;
constraintsLabel1.gridy = 0;
constraintsLabel1.gridwidth = 1;
constraintsLabel1.gridheight = 1;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(label1, constraintsLabel1);
}
}
Looking at the code again, it seems that gbLabel1 and gbLabel2 share the same logic, but the values of some of the variables differ slightly. Manually comparing the two, I tried to create a new method based on gbLabel1 that had parameters on those variable values that differed between gbLabel1 and gbLabel2. I did this by using the Introduce Parameter refactoring wizard. Listing 4 shows the result of using this wizard to replace the label's text and font values with method parameters.
Listing 4. Replacing Values with Parameters
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
gbLabel1(new Label("JUnit"),new Font("dialog",Font.PLAIN, 36));
gbLabel2();
gbButton();
gbLogo();
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
/**
*
*/
private void gbLogo() {
Logo logo= new Logo();
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2;
constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1;
constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
}
/**
*
*/
private void gbButton() {
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
GridBagConstraints constraintsButton1= new GridBagConstraints();
constraintsButton1.gridx = 2;
constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2;
constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
}
/**
*
*/
private void gbLabel2() {
Label label2= new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma");
label2.setFont(new Font("dialog", Font.PLAIN, 14));
GridBagConstraints constraintsLabel2= new GridBagConstraints();
constraintsLabel2.gridx = 2;
constraintsLabel2.gridy = 1;
constraintsLabel2.gridwidth = 2;
constraintsLabel2.gridheight = 1;
constraintsLabel2.anchor = GridBagConstraints.CENTER;
add(label2, constraintsLabel2);
}
/**
* @param lblText TODO
* @param lblFont TODO
*
*/
private void gbLabel1(Label lblText, Font lblFont) {
Label label1= lblText;
label1.setFont(lblFont);
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = 3;
constraintsLabel1.gridy = 0;
constraintsLabel1.gridwidth = 1;
constraintsLabel1.gridheight = 1;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(label1, constraintsLabel1);
}
}
Two things in Listing 4 are worth noting. First, in the comments before the newly modified method, TODOs remind you to comment on the meaning of the parameters. Second, in both gbLabel1 and gbLabel2 the placement of the label is specified using a rectangle with its upper-left corner and height and width values. Eclipse cannot recognize these as attributes of a rectangle; it must be done manually. I used the Change Method Signature wizard to introduce the Rectangle parameter.
Besides changing the method signature, I also needed to change manually the code where gbLabel1 is invoked. Listing 5 shows the results with some minor formatting changes being added.
Listing 5. Changing gbLabel1 Invocation Code
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
gbLabel1(new Label("JUnit"),
new Font("dialog", Font.PLAIN, 36),
new Rectangle(3,0,1,1));
gbLabel2();
gbButton();
gbLogo();
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
/**
*
*/
private void gbLogo() {
Logo logo= new Logo();
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2;
constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1;
constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
}
/**
*
*/
private void gbButton() {
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
GridBagConstraints constraintsButton1= new GridBagConstraints();
constraintsButton1.gridx = 2;
constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2;
constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
}
/**
*
*/
private void gbLabel2() {
Label label2= new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma");
label2.setFont(new Font("dialog", Font.PLAIN, 14));
GridBagConstraints constraintsLabel2= new GridBagConstraints();
constraintsLabel2.gridx = 2;
constraintsLabel2.gridy = 1;
constraintsLabel2.gridwidth = 2;
constraintsLabel2.gridheight = 1;
constraintsLabel2.anchor = GridBagConstraints.CENTER;
add(label2, constraintsLabel2);
}
/**
* @param lblText Text to appear in label
* @param lblFont Font to use in showing text
* @param lblRect the size and position of the label
*
*/
private void gbLabel1(Label lblText, Font lblFont, Rectangle lblRect) {
Label label1= lblText;
label1.setFont(lblFont);
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = lblRect.x;
constraintsLabel1.gridy = lblRect.y;
constraintsLabel1.gridwidth = lblRect.width;
constraintsLabel1.gridheight = lblRect.height;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(label1, constraintsLabel1);
}
}
Next, I noticed that the variable label1 could be replaced by label, because only one variable of this type is in this method. To do this, I used the Rename... wizard. I highlighted the name to be changed and invoked the wizard, as shown below.

Because the gbLabel1 method now has become quite generic, we also can change its name simply to gbLabel. We start by highlighting an instance of its name and invoking the Rename... wizard. Next, we replace the call to gbLabel2 with an equivalent call to gbLabel. Again, this must be done manually. Also, because gbLabel2 is no longer needed, we should delete it. Listing 6 shows the result of all this.
Listing 6. Cleaning Up the Code
package junit.awtui;
import java.awt.*;
import java.awt.event.*;
import junit.runner.Version;
class AboutDialog extends Dialog {
public AboutDialog(Frame parent) {
super(parent);
setResizable(false);
setLayout(new GridBagLayout());
setSize(330, 138);
setTitle("About");
gbLabel(new Label("JUnit"),
new Font("dialog", Font.PLAIN, 36),
new Rectangle(3,0,1,1));
gbLabel(new Label("JUnit "+
Version.id()+
" by Kent Beck and Erich Gamma"),
new Font("dialog", Font.PLAIN, 14),
new Rectangle(2,1,2,1));
gbButton();
gbLogo();
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dispose();
}
}
);
}
/**
*
*/
private void gbLogo() {
Logo logo= new Logo();
GridBagConstraints constraintsLogo1= new GridBagConstraints();
constraintsLogo1.gridx = 2;
constraintsLogo1.gridy = 0;
constraintsLogo1.gridwidth = 1;
constraintsLogo1.gridheight = 1;
constraintsLogo1.anchor = GridBagConstraints.CENTER;
add(logo, constraintsLogo1);
}
/**
*
*/
private void gbButton() {
Button button= new Button("Close");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
}
);
GridBagConstraints constraintsButton1= new GridBagConstraints();
constraintsButton1.gridx = 2;
constraintsButton1.gridy = 2;
constraintsButton1.gridwidth = 2;
constraintsButton1.gridheight = 1;
constraintsButton1.anchor = GridBagConstraints.CENTER;
constraintsButton1.insets= new Insets(8, 0, 8, 0);
add(button, constraintsButton1);
}
/**
* @param lblText Text to appear in label
* @param lblFont Font to use in showing text
* @param lblRect the size and position of the label
*
*/
private void gbLabel(Label lblText, Font lblFont, Rectangle lblRect) {
Label lbl= lblText;
lbl.setFont(lblFont);
GridBagConstraints constraintsLabel1= new GridBagConstraints();
constraintsLabel1.gridx = lblRect.x;
constraintsLabel1.gridy = lblRect.y;
constraintsLabel1.gridwidth = lblRect.width;
constraintsLabel1.gridheight = lblRect.height;
constraintsLabel1.anchor = GridBagConstraints.CENTER;
add(lbl, constraintsLabel1);
}
}
If you wish, you can continue on the same track with both the button and logo related methods. However, it is more of the same, so I won't bore you further on using refactoring with Eclipse and Java.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- RSS Feeds
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Download the Free Red Hat White Paper "Using an Open Source Framework to Catch the Bad Guy"
- Tech Tip: Really Simple HTTP Server with Python
- Home, My Backup Data Center
- Please correct the URL for Salt Stack's web site
1 hour 48 min ago - Android is Linux -- why no better inter-operation
4 hours 3 min ago - Connecting Android device to desktop Linux via USB
4 hours 32 min ago - Find new cell phone and tablet pc
5 hours 30 min ago - Epistle
6 hours 59 min ago - Automatically updating Guest Additions
8 hours 7 min ago - I like your topic on android
8 hours 54 min ago - This is the easiest tutorial
15 hours 29 min ago - Ahh, the Koolaid.
21 hours 8 min ago - git-annex assistant
1 day 3 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




Comments
Bicycle Repair Man and Eclipse
It is also worth mentioning that Bicycle Repair Man is integrated into Eclipse through the excellent PyDev plug-in: http://pydev.sourceforge.net/
PyDev tries to offer all the great relevant tools available when working in Java to Python developers.
I also agree with the author that while the definition of refactoring can be abstracted to a very high architecture level most programmers use the term "refactor" to mean removing all of the hacks and shortcuts in code that were inserted because of a short timeline for a software demonstration, release, or for testing with components created by other developers on a team.
Bicycle Repair Man and Eclipse
It is also worth mentioning that Bicycle Repair Man is integrated into Eclipse through the excellent PyDev plug-in: http://pydev.sourceforge.net/
PyDev tries to offer all the great relevant tools available when working in Java to Python developers.
I also agree with the author that while the definition of refactoring can be abstracted to a very high architecture level most programmers use the term "refactor" to mean removing all of the hacks and shortcuts in code that were inserted because of a short timeline for a software demonstration, release, or for testing with components created by other developers on a team.
Definition of refactoring
Here is another instance where I think computer science is at risk of being obscured instead of aided by technology.
The article addresses refactoring as if it were concerned exclusively with code. It's not. Refactoring is primarily about architecture and only secondarily about code. In other words, the focus is on design more than implementation.
Peter Deutsch says, and I agree, that:
Interface design and functional factoring constitute the key intellectual content of software and are far more difficult to create or re-create than code.
Most of the work of refactoring a system consists of revising the relationships between its functional components, indeed adding and eliminating components as well. These are changes to structure, not details of implementation.
It needn't be a software system. It would be perfectly reasonable to refactor an automobile engine, for example, so that the timing chain might be driven off the clutch assembly rather than the generator assembly, or in a more extreme case the cylinder layout may change from inline to vee. In a broad sense, the engine is functionally unchanged. That is, it still meets its original design requirements. However, its structure may have changed radically.
When you refactor a system, you're taking a fresh look at its design tradeoffs. It's really a "big picture" exercise in which basic assumptions of modularity, flow of control, and data abstraction are reexamined. This may answer the author's misgivings about how we're supposed to "know that the refactored code is 'better'." It wouldn't be the code that's better but the design, and of course that is a matter best debated at the design level.
What then is the benefit of "refactoring" tools, since indeed many only pertain to code and not to design? Well, to belabor the engine analogy, a boring machine would be in a comparable sense an "engine refactoring" tool. It doesn't actually do any refactoring itself, but it allows you a way to implement the design changes which are the result of your refactoring efforts.
Definition of refactoring
Your point is well taken. However, this column is about programming tools. My inclination is to be as concrete as I can. Since the title of this column is programming as opposed to design, and tools as in software that I can use to improve my programming experience, I chose to use the much narrower definition.
That said, if you are aware of any refactoring tools for the design portion of a system's life cycle, please let me know. I would be really interested.
Reg. Charney
Definition of refactoring
I think your best bet for that approach would be to look at UML refactoring tools. A good overview can be found in Martin Fowler, Refactoring: Improving the Design of Existing Code.
This is not an endorsement of UML as the basis of refactoring, by the way, because I believe that misses the point. Refactoring is substantially a conceptual exercise. Like optimization, the biggest gains require an understanding of the problem domain. On the other hand, if UML is already part of your process, or if you're willing to make it one, then refactoring at that level would be completely appropriate. It certainly gets you closer to understanding the design issues of a project than if you were to go straight to the code.
Again, you have a valid point
Again, you have a valid point. Do you or do any of our readers know of tools that would work on the UML description of a system?
Reg. Charney
M-x tags-query-replace
enough said :-)