CSC/ECE 517 Fall 2012/ch1b 1w45 is

From Expertiza_Wiki
Revision as of 22:34, 3 October 2012 by Smbuch (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Automated Refactoring

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.<ref name="refone"> Refactoring Home Page http://refactoring.com/ </ref> 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. <ref name="reftwo"> Why should you Refactor http://sourcemaking.com/refactoring/why-should-you-refactor </ref>

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. <ref name="refthree"> Refactoring for everyone http://www.ibm.com/developerworks/library/os-ecref/ </ref> 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<ref name="reffour"> refactoring for everyone http://www.ibm.com/developerworks/library/os-ecref/ </ref>

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. <ref name="reffive"> Refactorings-Inline Method: http://www.skorkin.com/2011/02/refactorings-inline-method/</ref>

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<ref name="refsix">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</ref> include:

  • Rename refactoring
    This refactoring technique allows renaming symbols. There are several rename refactoring available. These are rename package, rename class, rename method, rename variable etc.
    Before refactoring
    class abc() {
    puts “hello”
    }
    def message() {
    a= new abc()
    }
    In order to rename the class ‘abc’ select it, choose rename option from the tool and give a new name.
    After refactoring
    class xyz() {
    puts “hello”
    }
    def message() {
    a= new xyz()
    }
  • Extract Module
    This refactoring technique creates a module from the methods of a ruby class.
    Before refactoring
    class abc() {
    def total_cost(item1, item2) {
    return(item1 +item2)
    }
    }

    After refactoring: in the abc.rb file we will have
    class abc()
    include total_cost
    end
    in total_cost.rb file we will have
    module total_cost
    def total_cost(item1, item2) {
    return(item1 +item2)
    }
  • Extract Superclass
    It extract certain methods from a class in a superclass. For example if a class B contains two methods abc and xyz. We can do refactoring and move method xyz into superclass A.
    Before refactoring
    class B
    def abc
    //some code
    end
    def xyz
    //some code
    end
    end

    After refactoring
    class B<A
    def abc
    //some code
    end
    A.rb file
    def xyz
    //some code
    end
  • Introduce Variable
    This is when an expression is replaced by a variable and the variable is used in place of the expression each time. A change to the expression will mean a change only at one place. Eg.
    puts “My favorite team is #{get_team()}”
    But if, ::myTeam = get_team();
    Then, :puts “My favorite team is #{myTeam}”
  • Introduce Constant
    This is when a new constant is defined and initialized and that constant is used instead of a value. Eg. :a = b +3; CONSTANT = 3; a = b + CONSTANT;
  • Introduce Field
    This is when a new field is defined and initialized and then that field is used instead of the value. Eg. :a = b + 3; @field = 3; a = b + @field;
  • Introduce Parameter
    This type simply adds a new parameter to a function and updates the method calls according to that. Eg.
    Method signature changes from def function1() to def function1(pass)
    Method call will change from a=function1() to a=funtion1(something)
  • Inline Variable
    This works similar to Inline refactoring explained above. Eg. Instead of writing a variable’s value to console, we will write a constant to the console, which is basically hard coding the value written to the console.
  • Pull Up Members
    Refers to moving a field x from a class A to its superclass. Thus, x will be moved out of all of A’s siblings and will have just one copy in A’s superclass. Eg. If ‘type’ is an attribute of class Leopard and class Cheetah, then moving ‘type’ to super class of Leopard and Cheetah, that is, class Cat will result into one copy of ‘type’ being in class Cat and ‘type’ will get removed from both Cheetah and Leopard.
  • Push Down Members
    These work opposite of pull up members: If ‘type’ is part of class Cat then it will be moved individually to class Cheetah and class Leopard and now no existence of ‘type’ will be found in class Cat.
  • Override Method

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<ref name="borlandrefactorings>Leveraging What You Have: 10 Top Things Added to Delphi Since Delphi 7 http://edn.embarcadero.com/article/37416</ref> Yes 17 Declare Variable<ref name="borlanddecvar">Increased Productivity with Refactoring, Unit Testing, Help Insight, Error Insight, and Sync Edit in Borland Delphi 2005 http://edn.embarcadero.com/article/33278</ref>
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 <ref name='refeclipse'>Eclipse Refactoring Actions http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Freference%2Fref-menu-refactor.htm </ref> 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<ref name="kdeveloprefactorings">Kdevelop4: Now with refactoring! http://zwabel.wordpress.com/2008/11/05/kdevelop4-now-with-refactoring/</ref>. Project wide search/replace and local search/replace. Yes but very limited. 2 Rename Class Right click on class name and select Rename
NetBeans <ref name="refnetbeans">Refactoring in NetBeans 4.1 http://java.sun.com/developer/technicalArticles/tools/refactoring/</ref> 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<ref name="padrerefactorings" >How to do it in Padre http://padre.perlide.org/howto.html</ref> 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 <ref name="refvstudio">7 Refactoring Methods in Visual Studio 2010 http://p2p.wrox.com/content/articles/7-refactoring-methods-visual-studio-2010 </ref> 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

<references/>