Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 6: Code Refactoring Omar Meqdadi SE 3860 Lecture 6 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.

Similar presentations


Presentation on theme: "Chapter 6: Code Refactoring Omar Meqdadi SE 3860 Lecture 6 Department of Computer Science and Software Engineering University of Wisconsin-Platteville."— Presentation transcript:

1 Chapter 6: Code Refactoring Omar Meqdadi SE 3860 Lecture 6 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

2 2 Topic Covered Refactoring Refactoring Categories Refactoring Limitations Refactoring Tools

3 3 Refactoring Process of changing a software system in such a way that it  Does not alter the external behavior of the code  Improves its internal structure A program restructuring operation to support  Design evolution  Reuse of object oriented frameworks  Preserve the behavioral aspects of the program

4 Refactoring Specifies Source to source transformation Remain inside the same language, e.g., C++ to C++ Does not change the programs behavior – according to a test suite Originally designed for object-oriented languages, but can also be applied to non-object oriented language features, (i.e., functions)

5 Refactoring: Why? Design Preservation  Design Evolution Problems Code changes often lead to a loss of the original design Loss of design is cumulative:  Difficulties in design comprehension  Difficulties in preserving design  More rapid decay of design  Solution: Refactoring improves the design of existing code

6 Refactoring: Why? Comprehension  Developer's are most concerned with getting the program to work, not about future developers  Refactoring makes existing code more readable  Increases comprehension of existing code, leading higher levels of code comprehension  Often applied in stages

7 Refactoring: Why? Debugging  Improved program comprehension leads to easier debugging  Increased readability leads to the discovery of possible errors  Understanding gained during debugging can be put back into the code

8 Refactoring: Why? Faster Programming  Counterintuitive argument made by Fowler  Good design is essential for rapid development  Poor design allows for quick progress, but soon slows the process down Spend time debugging Changes take longer as you understand the system and find duplicate code

9 Refactoring: When? Adding Functionality  Comprehension of existing program  Preparation for addition Debugging  Comprehension of existing program Code Review  Preparation for suggestions to other programmers  Stimulates other ideas  Remove bad code smells

10 Refactoring Catalog Refactoring entry composed of:  Name  Summary  Motivation  Mechanics  Examples

11 Refactoring: Categories Composing Methods  Creating methods out of inlined code Moving Features Between Objects  Changing of decisions regarding where to put responsibilities Organizing Data  Make working with data easier

12 Refactoring: Categories Simplifying Conditional Expressions Making Method Calls Simpler  Creating more straightforward interfaces Dealing with Generalization  Moving methods around within hierarchies Big Refactoring  Refactoring for larger purposes

13 Composing Methods Extract Method Inline Method Inline Temp Replace Temp with Query Introduce Explaining Variables Split Temporary Variable Remove Assignments to Parameters Replace Method with Method Object Substitute Algorithm

14 Remove Assignments to Parameters Example: Remove Assignments to Parameters

15 Extract Methods Create a new method, and name it after the intention of the method (name it by what it does, not by how it does it) Copy the extracted code from the source method into the new target method Scan the extracted code for references to any variables that are local in scope to the source method See whether any temporary variables are used only within this extracted code. If so, declare them in the target method as temporary variables

16 Extract Methods (cont.) Look to see whether any local-scope variable are modified by the existing code Pass into the target method as parameters local scope variables that are read from the extracted code Compile when you have dealt with all the locally- scoped variables Replace the extracted code in the source method with a call to the target method Compile and test

17 Extract Methods void compAndPrint() { // compute X // compute Y... // print X // print Y... // store X // store Y } void compute () { // compute X // compute Y print(X, Y); // store X // store Y } void print(X,Y) { // print X // print Y }

18 Inline Methods void compute () { X = next(X); Y = next(Y); } int next(N) { return N++; } void compAndPrint() {... X++; Y++;... }

19 Inline Temp Example: double basePrice = anOrder.basePrice(); return (basePrice > 1000)return (anOrder.basePrice > 1000 )

20 Replace Temp with Query When: using a temporary variable to hold the result of an expression. double rectarea = length * width; if (rectarea > 1000) return rectarea * 0.95; else return rectarea * 0.98; If ( RectArea( ) > 1000 ) return RectArea( ) * 0.95; else return RectArea( ) * 0.98; } double RectArea( ) { return length * width; }

21 Split Temp Variable When: using a temporary variable to hold several expressions. double temp = 2 * (_height * _widgth); cout << “Perimeter is “ << temp << endl; temp = _height * _width; cout << “Area is “ << temp << endl; double perimeter = 2 * (_height * _widgth); cout << “Perimeter is “ << perimeter << endl; double area = _height * _width; Cout << “Area is “ << area << endl;

22 Introduce Explaining Variable When: You have a complicated expression. Then, Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose. // return = baseprice – quantitydiscount + shipping return (quantity*price)-((quantity-50)*discount) +price * 0.05 double baseprice = quantity * price; double quantitydiscount = (quantity-50)*discount; double shipping =price * 0.05; return baseprice – quantitydiscount + shipping;

23 Moving Object Features Move Method Move Field Extract Class Inline Class Hide Delegate Remove Middle Man Introduce Foreign Method Introduce Local Extension

24 Move Method When: if a method is used by another class more than the class on which its defined, move it to the other class class Student { bool IsEnroll(Course course) { return (course.getStudents().contains(this)); } class Course { Student students[size]; Student * getStudents() { return students; } class Student { } public class Course { Student students[size]; bool isEnroll(Student student) { return students.contains(student); }

25 Extract Class class Student { private: string name; string street; string city; string state; } class Student { private: string name; Address address; } class Address { private: string street; string city; string state; }

26 Inline Class When: a class that isn’t doing too much and shouldn’t be around any more. Then, move all its features to another class. So inline class is the reverse of Extract Class

27 Hide Delegate When: a client calls a delegate class of an object Refactoring: create methods on the server to hide the delegate Client must know about Person and Department Person must know about department Client only calls Person Person calls department

28 Hide Delegate Class Person { Department _department; public Department getDepartment() { return _department;} public void setDepartment (Department arg) { _department = arg;} } // end person Class Department { private String _chargeCode; private Person _manager; public Department (Person manager) { _manager = manager; } public Person getManager() { return _manager; }// end Dept Client Class: joe.getDepartment().getManager(); Person Class: public Person getManager () { return _department.getManager(); } // end getManager Client Class: manager = joe.getManager();

29 Remove Middle Man When: after several “Hide delegate”, the server becomes just a middle man for all the delegate methods. Refactoring:  Change the client to call the delegate directly Client only calls Person Person calls department Client must know about Person and Department Person must know about department

30 Introduce Foreign Method When: a server class needs an additional methods, but you can’t modify it Refactoring:  Create the method in the client class  Set one of the argument of the method to the instance of the server class StrDate newStart = new Date (previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate()+ 1); Date newStart = nextDat(previousEnd); private static Date nextDay (Date arg) { return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1); } // end nextDay

31 Introduce Local Extension When: a class needs several additional methods, but you can’t modify it ( such as server class) Refactoring:  Create a new class that contains these additional methods  Make the new class a subclass of the original one (inheritance) or use wrapper approach (delegation)

32 Organizing Data Self Encapsulate Field Replace Data Value with Object Change Value to Reference Change Reference to Value Replace Array with Object Duplicate Observed Data Change Unidirectional Association to Bidirectional Change Bidirectional Association to Unidirectional

33 Organizing Data (cont.) Replace Magic Number with Symbolic Constant Encapsulate Field Encapsulate Collection Replace Record with Data Class Replace Type Code with Class Replace Type Code with Subclasses Replace Type Code with State/Strategy Replace Subclass with Fields

34 Change Reference to Value void swap ( int * x, int * y) { int temp = *x; *x = *y; *y = temp; } void main () { int a = 5; int b = 7; swap (&a, &b); } void swap ( int &x, int &y) { int temp = x; x = y; y = temp; } void main () { int a = 5; int b = 7; swap (a, b); }

35 Replace Array with Object String[] row = new String[3]; row[0] = “Platteville”; row[1] = “15”; Performance row = new Performance(); row.setName(“Platteville”); row.setWins(“15”);

36 Encapsulate Field

37 Replace Magic Number with Constant Example: double Energy (double m, double h) { return m * 9.81 * h; } static Final double GRAVITATIONAL_CONSTANT * 9.81; double Energy (double m, double h) { return m * GRAVITATIONAL_CONSTANT * h; }

38 Simplifying Conditional Decompose Conditional Consolidate Conditional Expression Consolidate Duplicate Conditional Fragments Remove Control Flag Replace Nested Conditional with Guard Clauses Replace Conditional with Polymorphism Introduce Null Object Introduce Assertion

39 Decompose Conditional Example: Decompose Conditional

40 Consolidate Conditional double disabilityAmount() { if (_seniority < 2) return 0; if (_monthsDisabled > 12) return 0; if (_isPartTime) return 0; // do smoething else } double disabilityAmount() { { if (isNotEligableForDisability()) return 0; // do something else } bool isNotEligableForDisability() { if (_seniority < 2 || _monthsDisabled > 12 || _isPartTime() ) return false; else return true; }

41 Consolidate Duplicate Conditional Fragments if (isSpecial()) { total = price * 0.95; send(); } else{ total = price * 0.98; send(); } if (isSpecial()) { total = price * 0.95; } else{ total = price * 0.98; } Send();

42 Introduce Null Objects When: for null or default behavior, use inheritance class Animal { Voice MakeSound() { return voice; } Animal obj = new Animal; if (obj == null) voice = Voice.basic(); else voice = obj.MakeSound(); class Animal { Voice MakeSound() { return voice; } class NullAnimal : public Animal { Voice MakeSound() { return Voice.basic(); }

43 Replace Nested Conditional with Guard When: A method has unclear conditional behavior. Then, use Guard Clauses for all the special cases double getAmount() { double result; if (isDead ()) result = deadAmount(); else { if (isSeparated( ) ) result = separatedAmount(); else { if (isRetired ( ) ) result = retiredAmount(); else result = normalPayAmount(); } return result; } double getAmount() { if (isDead ( ) ) return deadAmount(); if (isSeparated ( ) ) return separatedAmount(); if (isRetired ( ) ) return retiredAmount(); return normalPayAmount(); }

44 Replace Conditional with Polymorphism class Bird { …… double getSpeed() { switch (_type) { case EUROPEAN: return getBaseX(); case AFRICAN: return getBaseX() – _number; } …..

45 Introduce Assertion When: the code assumes something. Then, make the assumption explicit with an assertion. double getExpenseLimit() { // should have either expense limit or // a primary // project return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); } double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }

46 Remove Control Flag When: remove a control flag and use break or return void checkSecurity( ) { bool found = false; for (int i = 0; i <length; i++) { if (! found) { if(people[i].equals("Don")){ sendAlert(); found = true; } if(people[i].equals ("John")){ sendAlert(); found = true; } } void checkSecurity( ) { for (int i = 0; i <length; i++) { if(people[i].equals("Don")){ sendAlert(); break; } if(people[i].equals ("John")){ sendAlert(); break; } }

47 Simplifying Method Calls Rename Method Add Parameter Remove Parameter Separate Query from Modifier Parameterize Method Replace Parameter with Explicit Methods Preserve Whole Object Replace Parameter with Method

48 Simplifying Method Calls(cont.) Introduce Parameter Object Remove Setting Method Hide Method Replace Constructor with Factory Method Encapsulate Downcast Replace Error Code with Exception Replace Exception with Test

49 Remove Setting Method When: A field should be set at creation time and never altered. Then, remove any setting method for that field. class Account { private String _id; Account (String id) { setId(id); } void setId (String arg) { _id = arg; } } class Account { private String _id; Account (String id) { _id = arg; } }

50 Hide Method When:  A method is not used by any other class Refactoring:  Make the method private

51 Parameterize Method When: Several methods do similar things but with different values contained in the method body. Then, Create one method that uses a parameter for the different values. class Employee { void tenPercentRaise () { salary *= 1.1; } void fivePercentRaise () { salary *= 1.05;} } class Employee { void Raise (double factor) { salary *= (1+ factor); } }

52 Replace Parameter with Explicit Method When: a method that runs different cases depending on the values of a parameter. Then, create a separate method for each value of the parameter void setValue (string name, int value) { if (name.equals("height")) height = value; if (name.equals("width")) width = value; } void setHeight(int value) { height = value; } void setWidth (int value) { width = value; }

53 Introduce Parameter Object When: a group of parameters that naturally go together. Then, replace them with an object

54 Preserve Whole Object When: You are getting several values from an object and passing these values as parameters in a method call. Then, send the whole object instead. int low = daysTempRange.getLow(); int high = daysTempRange.getHigh(); withinPlan = plan.withinRange(low, high); withinPlan = plan.withinRange(daysTempRange);

55 Replace Error Code with Exception When: A method returns something to indicate an error is better performed with an Exception bool withdraw(int amount) { if (amount > balance) return false; else { balance -= amount; return true; } void withdraw(int amount) throws BalanceException { if (amount > balance) { throw new BalanceException(); } balance -= amount; }

56 Replace Exception with Test When: if you are catching an exception that could be handled by an if- statement, use that instead int getValuebyIndex (int index) { try { return values[index]; } catch (ArrayIndexOutOfBoundsException e) { return 0; } int getValuebyIndex (int index) { if (index >= values.length) return 0; return values[index]; }

57 Replace Constructor with Factory Method Factory Class:  A utility class that creates an instance of a class from a family of derived classes  Useful in a situation that requires the creation of many different types of objects, all derived from a common base type

58 Replace Constructor with Factory Method Class Computer { ……… }; class Laptop: public Computer { ……… }; class Desktop: public Computer {...... }; class ComputerFactory { public: static Computer *NewComputer(const std::string &description) { if(description == "laptop") return new Laptop; if(description == "desktop") return new Desktop; return NULL; } }; Client Side: Computer * lapobj = ComputerFactory::NewComputer(“laptop”); Computer * deskobj = ComputerFactory::NewComputer(“desktop”);

59 Dealing with Generalization Pull Up Field Pull Up Method Pull Up Constructor Body Push Down Method Push Down Field Extract Subclass Extract Superclass Extract Interface

60 Dealing with Generalization Collapse Hierarchy Form Template Method Replace Inheritance with Delegation Replace Delegation with Inheritance

61 Method/Field Movement Pull Up Method/Field  When: Two subclasses have the same method/field  Refactoring: Move the method/field to the superclass Push Down Method/Field  When: A method/field is only used in subclass  Refactoring: move the method/field to the subclass

62 Method/Field Movement Example: Push Down Method

63 Pull Up Constructor Body When:  constructors on subclasses with mostly identical bodies. Refactoring:  Create a superclass constructor; call this from the subclass methods

64 Pull Up Constructor Body class Employee{ private: string name; string id; } class Manager : public Employee{ private: int grade; public: Manager (string n, string i, int g) { name = n; id = i; grade = g; } class Employee{ private: string name; string id; public: Employee(string n, string I ){ name = n; id = I; } class Manager : public Employee{ private: int grade; public: Manager (string n, string i, int g) { Employee (n, i); grade = g; }

65 Extract Subclass When: A class has features that are used only in some instances. Then, create a subclass for that subset of features

66 Extract Subclass class JobItem... public JobItem (int unitPrice, int quantity, boolean isLabor, Employee employee) { _unitPrice = unitPrice; _quantity = quantity; _isLabor = isLabor; _employee = employee; } public int getTotalPrice() { return getUnitPrice() * _quantity; } public int getUnitPrice(){ return (_isLabor) ? _employee.getRate() : _unitPrice; } public int getQuantity(){ return _quantity; } public Employee getEmployee() { return _employee; } private int _unitPrice; private int _quantity; private Employee _employee; private boolean _isLabor; class Employee... public Employee (int rate) { _rate = rate; } public int getRate() { return _rate; } private int _rate; class JobItem... protected JobItem (int unitPrice, int quantity, boolean isLabor) { _unitPrice = unitPrice; _quantity = quantity; protected boolean isLabor() { return false; } public int getUnitPrice(){ return _unitPrice; } class LaborItem extends JobItem public LaborItem (int quantity, Employee employee) { super (0, quantity, true); _employee = employee; } protected boolean isLabor() { return true; } public int getUnitPrice(){ return _employee.getRate(); }

67 Extract Superclass When: several classes with similar features class Employee { private: string name; string jobTitle; public: string GetName(); } class Student { private: string name; Course course; public: string GetName(); } class Person { private: string name; public: string GetName(); } class Employee : public Person { private: string jobTitle; } class Student : public Person { private: Course course; }

68 Extract Interface When: several classes have part of their interface in common Interface: is an empty shell, there are only the signatures (name / params / return type) of the methods. The methods do not contain anything. The interface can't do anything. It's just a pattern.

69 Extract Interface double charge(Employee emp, int days) { int base = emp.getRate() * days; if (emp.hasSpecialSkill()) return base * 1.05; else return base; } interface Billable { public int getRate(); public boolean hasSpecialSkill(); } class Employee implements Billable... double charge(Billable emp, int days) { int base = emp.getRate() * days; if (emp.hasSpecialSkill()) return base * 1.05; else return base; }

70 Collapse Hierarchy When:  A superclass and subclass are not very different Refactoring Solution:  Merge them together

71 Replace Inheritance with Delegation When:  A subclass uses only part of a superclasses interface or does not want to inherit data. Refactoring Solution:  C r eate a field for the superclass, change methods to delegate to the superclass, and remove the subclassing

72 Replace Inheritance with Delegation Example: class MyStack extends Vector { public void push(Object element) { insertElementAt(element,0); } public Object pop() { Object result = firstElement(); removeElementAt(0); return result; } class MyStack { private Vector _vector = new Vector(); public boolean isEmpty() { return _vector.isEmpty(); } public void push(Object element) { _vector.insertElementAt(element,0); } public Object pop() { Object result = _vector.firstElement(); _vector.removeElementAt(0); return result; }}

73 Big Refactoring Tease Apart Inheritance  Split an inheritance hierarchy that is doing two jobs at once Convert Procedural Design to Objects Separate Domain from Presentation  GUI classes that contain domain logic Extract Hierarchy  Create a hierarchy of classes from a single class where the single class contains many conditional statements

74 Convert Procedural Design Take each record type and turn it into a dumb data object with accessors Take all procedural code and put it into a single class Take each long method and apply Extract Method and the related factorings to break it down. As you break down the procedures use Move Method to move each one to the appropriate dumb data class Continue until all behavior is removed from the original class

75 Convert Procedural Design Example:

76 Refactoring: Limitations Tentative list due to lack of experience Database  Database schema must be isolated, or schema evolution must be allowed Changing Published Interfaces  Interfaces where you do not control all of the source code that uses the interface  Must support both old and new interfaces  Don't publish interfaces unless you have to

77 Refactoring: Tools Smalltalk Refactoring Browser  Development environment written in Smalltalk  Allows for Smalltalk source code to transform Smalltalk source code  Comments as a first-class part of the language XRefactory  Allows standard refactorings for C++


Download ppt "Chapter 6: Code Refactoring Omar Meqdadi SE 3860 Lecture 6 Department of Computer Science and Software Engineering University of Wisconsin-Platteville."

Similar presentations


Ads by Google