CSC/ECE 517 Fall 2009/wiki1a 7 sm

From Expertiza_Wiki
Revision as of 21:50, 8 September 2009 by Suryaramana (talk | contribs)
Jump to navigation Jump to search

Categorization of refactoring

The list of refactoring has become quite long. But people don't remember long lists very well. To promote learning the different patterns, they should be categorized in some way, or perhaps, along various dimensions. Take the list of refactoring available at refactoring.org (and/or elsewhere) and categorize them along as many different dimensions as makes sense. Write up a description of the refactoring landscape.

What is Refactoring?

Refactoring is the process of modifying/rewriting the code of a computer program to change its internal structure without changing its external (functional) behavior in order to improve its internal or external software quality attributes. In simple terms, it is used to improve its readability, reusability or structure without affecting its meaning or behavior.

Why is refactoring required?

If a program code is poorly designed it will be difficult to understand it and therefore maintain it. This fact is made worse for commercial programs which are huge and much more complex to write. These commercial programs are most of the times created and maintained by more than one programmer and have a much greater life span than smaller programs. So these codes should be easy to understand and as a result easy to modify when the need arises. But if the design of the code is not optimum then understanding the code and hence changing/adding new features can be very complex for someone who has not written the code. Moreover the changes may be detrimental to the code. For example if there is high coupling then changing the code at one place may adversely affect the code at some other place. If correct coding practices are not followed then that may lead to security concerns.The main reasons for refactoring are as follows:

  • Improving the design of the code
  • Makes the code easier to understand
  • Makes debugging easier (since the code is easier to understand)
  • Code runs faster


Categories of Refactoring

Each technique in refactoring can be categorized according to the broad goal that it intends to accomplish.


Simplifying Conditional Expressions

Conditional expressions form a major part of programming. It is inconceivable to come across any non trivial program that does not make use of conditional expressions. However, several times it so happens that the purpose of a conditional expression is unclear, the expression is either long or can be replaced altogether by another programming construct or technique. There are several refactoring methods whose aim is to simplify conditional expressions.

Example

Before

if(total>70){
award(“grade A”);
updateRecords();
}
else{
award(“grade B”);
updateRecords();
}

After

if(total>70){
award(“grade A”);
}
else{
award(“grade B”);
}
updateRecords();


Decompose Conditional

This refactoring method aims to simplify a complicated conditional expression. This is done by extracting the logic present in the conditional expression, then clause and else clause into different methods. For additional information regarding this topic click here.

Consolidate Conditional Expression

When there are several conditional tests executed sequentially with the same results then they can be consolidated into a single conditional expression and the logic in each of the tests can be extracted into a method.For additional information regarding this topic click here.

Consolidate duplicate conditional expressions

This is in case the same fragment of code is present in all branches of a conditional expression. In such cases this fragment of code can be brought outside the conditional constructs.For additional information regarding this topic click here.

Remove Control Flags

Often, when we have a conditional expression in a loop we have a control flag that checks to see how long the loop should continue. However, the logic and purpose of the loop and conditional expression become a lot clearer when we replace the control flag with break, return and continue statements. For additional information regarding this topic click here.

Replace Nested Conditional With Guard Clauses

It is often advisable to replace nested conditional statements with guard clauses since this would make it easier to follow the logic and purpose of the conditional expressions.For additional information regarding this topic click here.

Replacing Conditional with polymorphism

There are cases where in different actions need to be taken depending on the type of the object. In such cases it is advisable to replace conditional expressions with polymorphism. For additional information regarding this topic click here.



Making Method Calls Simpler

Any program written in the object oriented paradigm has several method calls. Simplifying method calls is an important part of refactoring.

Example

Before

int square(int base)
int cube(int base)

After

int raiseToPower(int base, int power)


Rename Method

It is very important that a method name give a clear idea of the purpose of the method. The method name should not be too long, but at the same time it should convey a clear idea as to what the method accomplishes. For additional information regarding this topic click here.

Add or Remove Parameters

When a method requires more parameters in order to perform its function we add a parameter to the method. Similar when a method no longer requires a parameter it should be removed. Without having all the required parameters the method cannot achieve its purpose. Having more methods than necessary can confuse the users about how the method actually works. For additional information regarding this topic click here or here.

Separate Query from Modifiers

We can sometimes have a method that both returns a value and changes the state of an object. In such cases we should have two methods. One, that returns a value and another that changes the state of the object. For additional information regarding this topic click here.

Parameterize Method

We might have methods that do essentially the same tasks that differ slightly based on the values used in the method body. In such cases we should consolidate such methods into a single method that takes the values as parameters. For additional information regarding this topic click here.

Replace Parameters with Explicit Methods

When we have a method that executes different blocks of code depending on the value of one of its parameters we should replace this method with a separate method for each value of the parameter. For additional information regarding this topic click here.

Preserve Whole Object

When we retrieve several values from an object and pass these values as parameters to a method call we should pass the object itself as a parameter to the method call. The necessary values are retrieved from the object in the body of the method. For additional information regarding this topic click here.

Replace Parameter with Method

We come across situations where an object invokes a method and passes the return value as a parameter to a different method. We should modify the code such that the receiver itself invokes the corresponding method instead of accepting its return value as a parameter. This results in the list of parameters of the receiver method becoming shorter. For additional information regarding this topic click here.

Introduce Parameter Object

We have a method that has a list of parameters that can be logically grouped into a single unit. In such cases we can replace the list of parameters with an object. For additional information regarding this topic click here.

Remove Setters for fields that are immutable

We should not have any setter methods for fields that are immutable. Such fields are initialized with a value and retain the value throughout. For additional information regarding this topic click here.

Hide Method

In case we feel that the visibility of a method is greater than required we need to reduce its visibility. We should always try to reduce the visibility of methods as much as possible. For additional information regarding this topic click here.

Replace Constructor with Factory Method

We do this when we want more than just simple construction when we create a method. An example is when different subclasses of the object need to be created based on different conditions. For additional information regarding this topic click here.

Replace Error Codes with Exceptions

Most of the modern programming languages offer support for exceptions. Thus, we should make use of this facility and replace error codes such as returning “-1” with the appropriate exceptions. For additional information regarding this topic click here.


Dealing with Generalization

Example

Before

Class Employee{
int empid;
}
Class Salesman extends Employee{
float salary;
// Other fields and methods
}
}
Class Manager extends Employee{
float salary;
// Other fields and methods
}

After

Class Employee{
int empid;
float salary;
}

Class Salesman extends Employee{
//Other fields and methods
}
Class Manager extends Employee{
//Other fields and methods
}



Collapse Hierarchy

A superclass and subclass that are not very different can be merger together. For additional information regarding this topic click here.

Pull Up Field

In case all the subclasses of a superclass have a common field, the field can be moved to the superclass. For additional information regarding this topic click here.

Pull Up Method

In case all the subclasses of a superclass have a common method, the method can be moved to the superclass. For additional information regarding this topic click here.

Pull up constructor body

In case we have subclass constructors with identical bodies, the body of the subclass constructors can be extracted to the constructor of the superclass. For additional information regarding this topic click here.

Push Down Method

In case certain aspects of the superclass behavior are relevant only for some of its subclasses, the behavior can be extracted into a method of the corresponding subclasses. For additional information regarding this topic click here.

Push Down Field

In case a field is used only by some subclasses of a superclass, the field can be moved to the subclasses that actually use it. For additional information regarding this topic click here.

Extract Subclass

In case a class has features that are used only in some instances then a subclass can be created for these features. For additional information regarding this topic click here.

Extract Superclass

In case two classes have common features a superclass can be created and common features can be moved to the superclass. For additional information regarding this topic click here.

Extract Interface

In case several clients use a common subset of a class’s interface then that subset can be extracted into a separate interface. For additional information regarding this topic click here.

Form Template Method

We have two or more methods in subclasses that perform similar steps in the same order but the steps are different. In this case we can extract these steps into methods of the same signature. Since these methods now have the same signature, the original method which contained the steps extracted into these methods and the newly formed methods can all be pulled up. For additional information regarding this topic click here.

Replace Inheritance with Delegation

In case a subclass uses only a subset of the super class’s interface we can create a field for the superclass and adjust methods in the subclass to delegate to the superclass where required. We can then remove the subclassing. For additional information regarding this topic click here.

Replace Delegation with Inheritance

In case we are using delegation and are adjusting a majority of the methods to delegate to a different class, we can make the delegating class a subclass of the delegate. For additional information regarding this topic click here.