User talk:Sheng yi: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(34 intermediate revisions by the same user not shown)
Line 1: Line 1:
== What is refactering? ==
== What is code refactoring ==
[[Image:test.jpg]]
According to the famous book "Refactoring: Improving the Design of Existing Code " by Martin Fowler: Refactoring is the process of applying behavior-preserving transformations to a program with the objective of improving the program’s design. Intuitively people refer to code refactoring as "cleaning it up".
A callback is code that one wants to be called from within a method after that method has been called. That is, it is a method of the caller that is invoked by the callee. Give an example using a closure in Ruby, and show how this is more elegant than similar code in Smalltalk.


== Refactoring support for Current Ruby IDE ==
=== Motivation of refactoring ===
Refactoring is very useful for software engineer to maintain the quality of their code in different environment. In fact, no software can be guaranteed to be perfect when it is first developed. Usually when the source code is applied to different customer needs, we want to improve the inner-structure without modify the external behavior. The ability to refactor your code takes the pressure off the design phase of software development. Refactoring gives you the ability to change the design of the code at a later stage. This means that you don’t have to get the design absolutely right before you write any code. You can get a rough design worked out, code it up and then if (when) you spot a better design you can refactor your code towards the better design.


The question requires us to compare callback using a closure code constructed in RUBY with a similar code constructed in Smalltalk and then show how the RUBY code is more elegant.
===List of main refactoring===
In the following we list some popular refactoring to specify how refactoring transform the code. For more detail information, the reader please refer to the section 2.1.2 of the thesis of Thomas Corbat[1]. [1] provide Ruby example for each refactoring this list. 
 
{|
| 1. Merge Class Parts
|-
| 2. Convert Local Variable to Field
|-
| 3. Encapsulate Field
|-
| 4. Extract Method
|-
| 5. Inline Class
|-
| 6. Inline Method
|-
| 7. Move Field
|-
| 8. Move Method
|-
| 9. Rename Class
|-
| 10. Rename Field
|-
| 11. Rename Local Variable
|-
| 12. Rename Method
|-
| 13. Replace Temporary Variable with Query
|-
| 14. Split Temporary Variable
|}


== Ruby vs Java in terms of refactoring==
=== Some Ruby Example of refactoring ===
before rename:


A function passed as an argument is called a callback, since it is "called back" by the other function.[2] In general a callback is a piece of "your" code you ask "some other piece" of code to invoke in certain events, e.g. some code to be executed if a button is clicked on the screen.
def badRenameMethod
    puts("Hello World");
end


In most languages you specify a call back by passing the address of your subroutine to the system you're requesting the callback from.
after rename:


In RUBY callback is implemented using blocks. A nameless block of code may be passed as an argument to a method for implementation of callback.
def hello
put("Hello World");
end


=== Blocks and Closures ===
before encapsulation:
class SomeClass
    def initialize
        @field = 0;
    end
end


Blocks are basically nameless functions. You can pass a nameless function to another function, and then that function can invoke the passed-in nameless function. For example, a function could perform iteration by passing one item at a time to the nameless function. In Ruby, any method can be called with a block as an implicit argument. Inside the method, you can call the block using the yield keyword with a value. We can create a closure out of a block. A closure is a nameless function. You can pass around a nameless function object, the closure, to another method to customize the behavior of the method. As another example, if you have a sort method to sort an array or list, you can pass a block to define how to compare the elements. This is not iteration. This is not a loop. But it is using blocks. A closure object has code to run, the executable, and state around the code, the scope. So you capture the environment, namely the local variables, in the closure. As a result, you can refer to the local variables inside a closure. Even after the function has returned, and its local scope has been destroyed, the local variables remain in existence as part of the closure object. When no one refers to the closure anymore, it's garbage collected, and the local variables go away.[3]
after encapsulation:


===Example===
class SomeClass               
    def initialize
        @field = 0;
    end
   
    def field
        @field
    end
    private :field
   
    def field= field
        @field = field
    end
    private :field=
end


In RUBY any chunk of code between braces {} or between do ... end is a block. This can be associated with a function call also.
=== Some Java Example of refactoring ===
before rename:


Eg.{ puts "Hello" }  <- block
public class rename_method
{
    static void badRenameMethod()
    {
        System.out.println("Hello, world!");
    }
  }


def about_block
after rename:
  puts "In the function"
  yield
end
about_block {puts "This is the block"} <- Associated with a function call


Output:
public class rename_method
{
    static void hello()
    {
        System.out.println("Hello, world!");
    }
}


In the function<br>
This is the block


''"yield"'' is the keyword which invokes the block of code associated with the function call.
before encapsulation:


Detailed Explanation of the program : The function about_blocks is defined and called at the end. When it is called the control passes to the first ''"puts"'' in the function. When the next line is executed (''yield'') it refers to the block associated with the function call. So, it prints "This is the block"
public class encap_field
{
    public String field;
}


== Functor ==
after encapsulation:


A functor is nothing more than an object that behaves like a function (which is the case in RUBY - everything is an object).[2]
public class encap_field
{
    private int field;


== Approach to the Question ==
    public void setField(int field)
    {
        this.field = field;
    }


Suppose we need to associate actions to a particular button so that it does a required function.
    public int getField()
Eg. In a form if we press CLEAR, it should clear the form and SUBMIT should submit the form. Ruby’s blocks are a convenient way to do this.
    {
We assume that on pressing the button a callback method, button_pressed, will be invoked. The obvious way of adding functionality to these buttons is to create subclasses of Button(which is the class) and have each subclass implement its own button_pressed method.
         return field;
Eg.
     }
class FormButton < Button
  }
    def initialize
        super("Submit") # invoke Button's initialize
         end
     def button_pressed
    # do submit actions...
    end
end
submit_button = FormButton.new
This will lead to a large number of subclasses. We can fix this problem using blocks in RUBY.
pressbutton = PressButton.new
  class FormButton < Button
    def initialize(label, &action)
        super(label)
        @action = action
    end
    def button_pressed
      @action.call(self)
    end
  end
submit_button = FormButton.new("Submit") { pressbutton.submit }
  reset_button = FormButton.new("Clear") { pressbutton.reset }


The key to all this is the second parameter to FormButton#initialize. If the last parameter in a method definition is prefixed with an ampersand (such as &action), Ruby looks for a code block whenever that method is called. That code block is converted to an object of class Proc and assigned to the parameter. You can then treat the parameter as any other variable. When the callback method button_pressed is invoked, we use the Proc#call method on that object to invoke the block.
== Refactoring support for Current Ruby IDE ==
This the following table we summary the current ruby IDE and their refactoring support situation.  
{|
| Current Ruby IDE || Refactoring Support (Y/N)
|-
| ActiveState Komodo  || N
|-
| NetBeans || N
|-
| Arachno Ruby ||  N
|-
| FreeRIDE || N
|-
| Mondrian Ruby IDE || N
|-
| Ruby in Steel || N
|-
| RubyMine || Y
|-
| Eclipse (Aptana) || Y 
|}


== Comparisons of Smalltalk and Ruby code ==
=== Example of using Ruby refactoring tools in Eclipse ===
example of rename:


Smalltalk
{|
| [[Image:r00.jpg|thumb|upright|alt= rename step0]]
| [[Image:r01.jpg|thumb|upright|alt= rename step1]]
| [[Image:r02.jpg|thumb|upright|alt= rename step2]]
| [[Image:r03.jpg|thumb|upright|alt= rename step3]]
| [[Image:r04.jpg|thumb|upright|alt= rename step4]]
|}


foo
example of encapsulation:
    | xs |
{|
    xs := #(1 2 3 4).
| [[Image:r05.jpg|thumb|upright|alt= encapsulation step0]]
    xs do: [:x | ^x].
| [[Image:r06.jpg|thumb|upright|alt= encapsulation step1]]
    ^0
| [[Image:r07.jpg|thumb|upright|alt= encapsulation step2]]
  bar
| [[Image:r08.jpg|thumb|upright|alt= encapsulation step3]]
    Transcript show: (self foo) "prints 1"
| [[Image:r09.jpg|thumb|upright|alt= encapsulation step4]]
|}


In Smalltalk, ^ will return from method foo, and not just from the closure. do: is defined as a plain method, and there is nothing special about it.
=== Example of using Java refactoring tools in Eclipse ===
example of rename:  


foo
{|
    ^[ x: | ^x ]
| [[Image:j00.jpg|thumb|upright|alt= rename step0]]
  bar
| [[Image:j01.jpg|thumb|upright|alt= rename step1]]
    | f |
| [[Image:j02.jpg|thumb|upright|alt= rename step2]]
    f := self foo.
| [[Image:j03.jpg|thumb|upright|alt= rename step3]]
    f value: 123 "error!"
| [[Image:j04.jpg|thumb|upright|alt= rename step4]]
| [[Image:j05.jpg|thumb|upright|alt= rename step0]]
|}


When block returned by method foo is invoked, it attempts to return a value from foo. Since the call to foo has already completed, this operation results in an error.
example of encapsulation:
{|
| [[Image:j06.jpg|thumb|upright|alt= encapsulation step1]]
| [[Image:j07.jpg|thumb|upright|alt= encapsulation step2]]
| [[Image:j08.jpg|thumb|upright|alt= encapsulation step3]]
| [[Image:j09.jpg|thumb|upright|alt= encapsulation step4]]
|}


Ruby
== Ruby vs Java in terms of refactoring==


def foo
    f = Proc.new { return "return from foo from inside proc" }
    f.call # control leaves foo here
    return "return from foo"
  end
  def bar
    f = lambda { return "return from lambda" }
    f.call # control does not leave bar here
    return "return from bar"
  end
  puts foo # prints "return from foo from inside proc"
  puts bar # prints "return from bar"


It allows the programmer to choose the way he wants "return" to be captured.Both Proc.new and lambda in this example are ways to create a closure.[4]


== References ==
== References ==


1. http://mccammon.ucsd.edu/~oompaa/Oompaa/oompaa/global/doc/callback.html<br>
[1] Thomas Corbat, Lukas Felber, Mirko Stocker
2. http://forum.java.sun.com/thread.jspa?threadID=485166&messageID=2269118<br>
Refactoring Support for the Eclipse Ruby Development Tools, Diploma Thesis, HSR University of Applied Sciences Rapperswil Institute for Software
3. http://www.artima.com/intv/closures.html<br>
 
4. http://en.wikipedia.org/wiki/Closure_(computer_science)<br>
[2] code refactoring wiki, http://en.wikipedia.org/wiki/Code_refactoring
5. The Pragmatic Programmers - Programming Ruby
 
[3] the first workshop on refactoring, https://netfiles.uiuc.edu/dig/RefactoringWorkshop
 
[4] refactoring tutorial on ruby on rail, http://www.good-tutorials.com/tutorials/ruby-on-rails/refactoring

Latest revision as of 03:02, 6 September 2009

What is code refactoring

According to the famous book "Refactoring: Improving the Design of Existing Code " by Martin Fowler: Refactoring is the process of applying behavior-preserving transformations to a program with the objective of improving the program’s design. Intuitively people refer to code refactoring as "cleaning it up".

Motivation of refactoring

Refactoring is very useful for software engineer to maintain the quality of their code in different environment. In fact, no software can be guaranteed to be perfect when it is first developed. Usually when the source code is applied to different customer needs, we want to improve the inner-structure without modify the external behavior. The ability to refactor your code takes the pressure off the design phase of software development. Refactoring gives you the ability to change the design of the code at a later stage. This means that you don’t have to get the design absolutely right before you write any code. You can get a rough design worked out, code it up and then if (when) you spot a better design you can refactor your code towards the better design.

List of main refactoring

In the following we list some popular refactoring to specify how refactoring transform the code. For more detail information, the reader please refer to the section 2.1.2 of the thesis of Thomas Corbat[1]. [1] provide Ruby example for each refactoring this list.

1. Merge Class Parts
2. Convert Local Variable to Field
3. Encapsulate Field
4. Extract Method
5. Inline Class
6. Inline Method
7. Move Field
8. Move Method
9. Rename Class
10. Rename Field
11. Rename Local Variable
12. Rename Method
13. Replace Temporary Variable with Query
14. Split Temporary Variable

Some Ruby Example of refactoring

before rename:

def badRenameMethod
   puts("Hello World");
end

after rename:

def hello
put("Hello World");
end

before encapsulation:

class SomeClass
   def initialize
       @field = 0;
   end
end

after encapsulation:

class SomeClass                
   def initialize
       @field = 0;
   end
   
   def field
       @field
   end
   private :field
   
   def field= field
       @field = field
   end
   private :field=
end

Some Java Example of refactoring

before rename:

public class rename_method
{
   static void badRenameMethod()
   {
       System.out.println("Hello, world!");
   }
}

after rename:

public class rename_method
{
   static void hello()
   {
       System.out.println("Hello, world!");
   }
}


before encapsulation:

public class encap_field
{
   public String field;
}

after encapsulation:

public class encap_field
{
   private int field;
   public void setField(int field)
   {
       this.field = field;
   }
   public int getField()
   {
       return field;
   }
}

Refactoring support for Current Ruby IDE

This the following table we summary the current ruby IDE and their refactoring support situation.

Current Ruby IDE Refactoring Support (Y/N)
ActiveState Komodo N
NetBeans N
Arachno Ruby N
FreeRIDE N
Mondrian Ruby IDE N
Ruby in Steel N
RubyMine Y
Eclipse (Aptana) Y

Example of using Ruby refactoring tools in Eclipse

example of rename:

rename step0
rename step1
rename step2
rename step3
rename step4

example of encapsulation:

encapsulation step0
encapsulation step1
encapsulation step2
encapsulation step3
encapsulation step4

Example of using Java refactoring tools in Eclipse

example of rename:

rename step0
rename step1
rename step2
rename step3
rename step4
rename step0

example of encapsulation:

encapsulation step1
encapsulation step2
encapsulation step3
encapsulation step4

Ruby vs Java in terms of refactoring

References

[1] Thomas Corbat, Lukas Felber, Mirko Stocker Refactoring Support for the Eclipse Ruby Development Tools, Diploma Thesis, HSR University of Applied Sciences Rapperswil Institute for Software

[2] code refactoring wiki, http://en.wikipedia.org/wiki/Code_refactoring

[3] the first workshop on refactoring, https://netfiles.uiuc.edu/dig/RefactoringWorkshop

[4] refactoring tutorial on ruby on rail, http://www.good-tutorials.com/tutorials/ruby-on-rails/refactoring