CSC/ECE 517 Fall 2012/ch1b 1w45 is

From PG_Wiki
Jump to: navigation, search

Automated Refactoring

Contents


Introduction

Refactoring is a technique for restructuring existing code. It is defined as altering the code's internal structure without changing its external behavior. It is done as a series of small transformations which together produce significant restructuring. Since each transformation is small, it's less likely to go wrong. The system is also kept fully working after each small transformation, reducing the chances that a system can get seriously broken during the restructuring.[1] When people make small changes to the code without fully understanding its design, the code loses its structure, which eventually has a cumulative effect. If the developer cannot understand the code design, then it becomes more difficult for him to preserve it. Timely refactoring helps the code to retain its shape. [2]

Automated refactoring refers to refactoring which is under the developers control. What we mean by this is that, the system is not responsible for deciding what refactoring is required, rather this is the job of the developer. Automated refactoring is a feature of most widely used IDE's today, which helps expedite the task of refactoring for the developers. [3] In this article, we are aiming at describing the various techniques for automated refactoring. This article gives a clear understanding of these techniques which are illustrated with examples. We have also given a comparison of the refactoring functionality provided by various frequently used IDE's.

Common Refactoring Techniques

Extraction Refactoring

There are several refactoring techniques related to extraction: Extract method, Extract local variables, Extract constants. The first method "Extract method will create a new method from code you've selected. Extract Local Variable refactoring takes an expression that is being used repeatedly and assigns it to a local variable. Extract constant refactoring is to select a static, constant expression, which the refactoring will convert to a static final constant. This is useful for removing hard-coded numbers and strings from your code

1) Extract method:

Before refactoring

public void abc() {
int x= 9;
int y= 100;
int z=x+y;
int s=x +z;
}

After refactoring

public void abc() {
int x=9;
int y=50;
int z= add(x,y);
int s= add(x,z);
}
private int add(int x, int y) {
return x+y;
}

2) Extract local variable: This refactoring technique takes out an expression and then assigns it to a variable. This variable is then used in place of expression everywhere in the code where the expression is present. It has several advantages. First of all it gives meaningful name to an expression which helps in understanding what an expression does. It helps in debugging of code and it makes code efficient.

Before refactoring

void xyz() {
int i=12;
int j= 6;
int k=15;
int p=10;
p+=i+j+k;
}

In order to perform refactoring in eclipse or any other tool first we select the expression (here i+j+k) or any other tool, it asks for name of new variable name. Suppose we give it q.

After refactoring

void xyz() {
int i=12;
int j= 6;
int k=15;
int p=10;
p+=q;
}

3) Extract constant:

Before refactoring

void abc() {
int a=100;
int b=100;
int z= a+b;
}

Now if we want to extract the constant 100 we will select it and enter a name for it say for example ‘num’. Now instead of using 100 we will use the variable ’num’

After refactoring

void abc() {
int a=num;
int b=num;
int c=num+num;
}

Inline Refactoring

This type refactoring is the reverse of local variable extraction, in which we remove a local variable and use the value of the variable(typically an expression) in the place where the variable is used. This can be marginally more efficient than using a temporary variable and, by making the code terser, makes it either easier to read or more cryptic, depending on your point of view[4]

Put in easy words, Inline refactoring is doing what an external method call does but without making the actual call to an external method. This is as good as writing what a method does inline instead of calling a method defined outside. Let us illustrate this with an example.

Before Inline Refactoring

void funtion1(String msg) {
Console.write(msg);
}
void function2() {
function1(“someString”);
}

After Inline refactoring

void funtion2() {
Console.write(“someString”);
}

In this way we are shortening the code but can print statically only one value (in this case someString), each time. [5]

Encapsulating Fields

Generally its not a good practice to expose the class attributes through public interface. Thus, Encapsulating such fields will make such fields as private or protected as appropriate and generate getters and setters for the associated field.

Consider the following piece of code. This class has an attribute which is public and can be accessed by any object directly.

Before Encapsulating Fields

public class Class1 {
public String attr1;
}
public class Class2 {
public static void main(String [] args) {
Class1 obj = new Class1();
Obj.attr1 = “var”;
System.out.println(“Value of attr1 is” + obj.attr1);
}
}

On making attr1 private, we need to add getter and setter method to access it outside the class. This can be done using automated refactoring technique called Encapsulating a field technique. Now the object obj can access the attribute attr1 only through the defined getter and setter method.

After Encapsulating Fields

public class Class1 {
private String attr1;
public String getAttr1() {
return attr1;
}
public setAttr1(String newAttr1Value) {
attr1 = newAttr1Value;
}
}
public class Class2 {
public static void main (String [] args) {
Class1 obj = new Class1();
obj.setAttr1(“var”);
System.out .println(“Value of Attr1 is” + obj.getAttr1());
}
}

Changing Method Signature

Here we change the change the parameters, visibility, and return type of a method.
Before Refactoring Suppose our class Class1 is defined as below and it has a function funtion1 as shown:

public class Class1 {
public void funtion1(int a) {
//do something
}
}

The method call to function1 will be as follows:

public class Class2 {
public static void main(String [] args) {
Class1 obj = new Class1();
Obj.function1(5);
}
}


After Refactoring On change the number of arguments in function1 to 2 instead of 1 the function call should also change. This is done by a concept called Automated refactoring technique for changing method signature.

public class Class1 {
public void funtion1(int a, double b) {
//do something
}
}
public class Class2 {
public static void main(String [] args) {
Class1 obj = new Class1();
Obj.function1(5, 0.0);
}
}

When performing the refactoring a default value of 0.0 will be passed to the function as a parameter.

Other Refactorings

There are a multitude of refactorings. Those that are included with RubyMine[6] include:

Refactoring support in popular IDE(s)

IDE Language(s) Refactoring Support Automated Refactoring? Number of Refactoring support Support for Pattern Example
Borland Delphi Object Oriented Pascal Rename refactoring, Refactor driven “Find References”, Introduce Variable refactoring, Introduce Field refactoring, Inline Variable refactoring, Change Parameters refactoring, Safe Delete refactoring, Push Members Up / Down refactoring, Pull Members Up refactoring, Extract Superclass refactoring, Extract Interface refactoring, Move Members refactoring, Declare variable refactoring, Declare field refactoring, Extract method refactoring, Find unit/import namespace refactoring, Refactor driven “Find in Files”, Extract to resource string refactoring[7] Yes 17 Declare Variable[8]
Before Refactoring
procedure TWinForm1.btnOpen_Click(sender: System.Object;
  e: System.EventArgs);
begin
  if (OpenFileDialog1.ShowDialog =
      System.Windows.Forms.DialogResult.OK) then
  begin
    Assign(f,OpenFileDialog1.FileName);
    Reset(f);
    try
    finally
      CloseFile(f);
    end;
  end;
end;

After Refactoring
procedure TWinForm1.btnOpen_Click(sender: System.Object;
  e: System.EventArgs);
var
  f: TextFile;
begin
  if (OpenFileDialog1.ShowDialog =
      System.Windows.Forms.DialogResult.OK) then
  begin
    Assign(f,OpenFileDialog1.FileName);
    Reset(f);
    try
    finally
      CloseFile(f);
    end;
  end;
end;
Eclipse [9] C, C++, Java Rename selected Elements, Move selected elements, Change Method Signature, Extraction, Convert Anonymous Class to Nested, Convert Local Variable to Field, Extract Super class and Interface, push down, pull up, Introduce Indirection, Encapsulate Field, Migrate JAR File, Create & Apply Refatoring Scripts Yes 27 Introduce Factory
Before Refactoring

int x= p * 5; p.x;


After Refactoring

int x= getFoo(p); (Method Extraction) p.getX() (Encapsulate Field)

Kdevelop C, C++ Several[10]. Project wide search/replace and local search/replace. Yes but very limited. 2 Rename Class Right click on class name and select Rename
NetBeans [11] Java Renaming fields, methods, classes, or packages, Encapsulating fields, Changing method parameters, Moving classes, Yes but very limited 4 No
Before Refactoring
public class Foo{
  public int n;
  public int Compute(int val);
}

After Refactoring (Encapsulating field)
pubic class Foo{
  private int n;
  public int getN();
  public void setN(int val);
  public int Compute(int arg);
}
Padre Perl Lexically Rename Variable, Introduce Temporary Variable[12] Yes Unknown Right click on item to refactor and select refactoring choice from the context menu
RubyMine Ruby Safe Delete, Rename Refactorings, Push Members Down, Pull Members Up, Move Refactorings, Introduce Variable, Introduce Parameter, Introduce Field, Introduce Constant, Inline, Extract Superclass, Extract Module, Extract Partial, Extract Method, Copy / Clone. Yes 15 Introduce Temporary
Before Refactoring
c = a * b + 5
d = 2 * a * b

After Refactoring
t = a * b
c = t + 5
d = 2 * t
Visual Studio [13] C, C++, Java, C# Extract Method, Encapsulate Field, Extract Interface, Rename, Promote Variable to Parameter(Changing method signature), Generate Method Stub(Used for testing purposes) Yes 7 No Promoting Variable to Parameter
Before Refactoring

public void MethodA() {

   MethodB();

} public void MethodB() {

   string output = "Test String";
   MessageBox.Show( output);

}


After Refactoring

public void MethodA() {

   MethodB("Test String");

} public void MethodB(string output) {

   MessageBox.Show( output);

}

References

  1. Refactoring Home Page http://refactoring.com/
  2. Why should you Refactor http://sourcemaking.com/refactoring/why-should-you-refactor
  3. Refactoring for everyone http://www.ibm.com/developerworks/library/os-ecref/
  4. refactoring for everyone http://www.ibm.com/developerworks/library/os-ecref/
  5. Refactorings-Inline Method: http://www.skorkin.com/2011/02/refactorings-inline-method/
  6. RubyMine :: Ruby and Ruby on Rails IDE with smart code completion, syntax highlighting and refactoring http://www.jetbrains.com/ruby/features/ruby_ide.html#Refactorings
  7. Leveraging What You Have: 10 Top Things Added to Delphi Since Delphi 7 http://edn.embarcadero.com/article/37416
  8. Increased Productivity with Refactoring, Unit Testing, Help Insight, Error Insight, and Sync Edit in Borland Delphi 2005 http://edn.embarcadero.com/article/33278
  9. Eclipse Refactoring Actions http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Freference%2Fref-menu-refactor.htm
  10. Kdevelop4: Now with refactoring! http://zwabel.wordpress.com/2008/11/05/kdevelop4-now-with-refactoring/
  11. Refactoring in NetBeans 4.1 http://java.sun.com/developer/technicalArticles/tools/refactoring/
  12. How to do it in Padre http://padre.perlide.org/howto.html
  13. 7 Refactoring Methods in Visual Studio 2010 http://p2p.wrox.com/content/articles/7-refactoring-methods-visual-studio-2010
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox