Catalog of Refactoring (1) Composing Methods. Code Smells Long methods Dubious temporary variables Dubious methods.

Slides:



Advertisements
Similar presentations
Module 7. Simplifying Conditional Expressions Course: Refactoring.
Advertisements

Clean code. Motivation Total cost = the cost of developing + maintenance cost Maintenance cost = cost of understanding + cost of changes + cost of testing.
A practical guide John E. Boal TestDrivenDeveloper.com.
1 Software Maintenance and Evolution CSSE 575: Session 2, Part 2 Composing Methods Steve Chenoweth Office Phone: (812) Cell: (937)
Refactoring Overview  What is refactoring?  What are four good reasons to refactor?  When should you refactor?  What is a bad smell (relative to refactoring.
Week 9: Methods 1.  We have written lots of code so far  It has all been inside of the main() method  What about a big program?  The main() method.
Software Engineering Key Refactorings
1 Software Maintenance and Evolution CSSE 575: Session 2, Part 3 Moving Features Between Objects Steve Chenoweth Office Phone: (812) Cell: (937)
Introduction to Refactoring Excerpted from ‘What is Refactoring?’ by William C. Wake and Refactoring: Improving the Design of Existing Code by Martin Fowler.
George Blank University Lecturer. REFACTORING Improving the Design of Existing Code Supplement to Ian Sommerville, Software Engineering, Chapter 20 Prepared.
25-Jun-15 Refactoring III. General philosophy A refactoring is just a way of rearranging code Refactorings are used to solve problems If there’s no problem,
REFACTORING Improving the Design of Existing Code Atakan Şimşek e
COMP 14: Primitive Data and Objects May 24, 2000 Nick Vallidis.
Day 4 Objectives Constructors Wrapper Classes Operators Java Control Statements Practice the language.
CSM-Java Programming-I Spring,2005 Introduction to Objects and Classes Lesson - 1.
Fruitful functions. Return values The built-in functions we have used, such as abs, pow, int, max, and range, have produced results. Calling each of these.
REFACTORING Lecture 4. Definition Refactoring is a process of changing the internal structure of the program, not affecting its external behavior and.
Style It's still hard to give rules, but we can give some examples. Remember: this is to some extent a matter of taste.
Methods and You. Up to this point, I have covered many different data types with you. Variables can be considered the nouns of an English sentence. If.
Refactoring – III Measured Smells. Smells Covered 1. Comments 2. Long method 3. Large Class 462.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
By Nicholas Policelli An Introduction to Java. Basic Program Structure public class ClassName { public static void main(String[] args) { program statements.
Refactoring. Mathematics: Factor ● fac·tor – One of two or more quantities that divides a given quantity without a remainder, e.g., 2 and 3 are factors.
Refactoring Improving the structure of existing code Refactoring1.
Copyright © 2002, Systems and Computer Engineering, Carleton University a-JavaReview.ppt * Object-Oriented Software Development Unit.
Small changes to code to improve it. Refactoring Defined A change made to the internal structure of software to make it easier to understand and cheaper.
SWE 316: Software Design and Architecture Objectives Lecture # 20 Improving the existing design: Refactoring SWE 316: Software Design and Architecture.
Improving the Quality of Existing Code Svetlin Nakov Telerik Corporation
1 Software Maintenance and Evolution CSSE 575: Session 3, Part 1 Simplifying Conditionals Steve Chenoweth Office Phone: (812) Cell: (937)
Refactoring1 Improving the structure of existing code.
Refactoring Deciding what to make a superclass or interface is difficult. Some of these refactorings are helpful. Some research items include Inheritance.
Introduction to Refactoring Jim Cooper Falafel Software.
Software Engineering CS3003 Lecture 4 Code bad smells and refactoring.
Refactoring. Refactoring Overview  What is refactoring?  What are four good reasons to refactor?  When should you refactor?  What is a bad smell (relative.
Refactoring 2. Admin Blackboard Quiz Acknowledgements Material in this presentation was drawn from Martin Fowler, Refactoring: Improving the Design of.
REFACTORINGREFACTORING. Realities Code evolves substantially during development Requirements changes 1%-4% per month on a project Current methodologies.
Software Construction and Evolution - CSSE 375 Making Method Calls Simpler Shawn and Steve Below – “Be the character!” The late acting teacher Lee Strasberg.
1 Software Maintenance and Evolution CSSE 575: Session 3, Part 3 Dealing with Generalization Steve Chenoweth Office Phone: (812) Cell: (937)
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
Session 6 Comments on Lab 3 & Implications of Inheritance.
SEG 4110 – Advanced Software Design and Reengineering Topic T Introduction to Refactoring.
Refactoring. Mathematics: Factor ● fac·tor – One of two or more quantities that divides a given quantity without a remainder, e.g., 2 and 3 are factors.
Refactoring1 Improving the structure of existing code.
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Written by: Dr. JJ Shepherd
Software Construction and Evolution - CSSE 375 Simplifying Conditionals Shawn & Steve.
Refactoring Constants and Variables Lesson Three: Constants and Variables.
CSSE 375 Organizing Data – Part 1 Shawn and Steve Q1.
Refactoring. DCS – SWC 2 Refactoring ”A change made to the internal structure of software to make it easier to understand and cheaper to modify without.
Code Refactoring Milan Vukoje Soprex SkfOffice2 SkfOffice3 Big5 Quality oriented We are hiring…
CS100Lecture 61 Announcements Homework P1 due on Thursday Homework P2 handed out.
ICONFINDER ICONFINDER Founded Django based web application -PostgreSQL -Elasticsearch -Amazon Elastic Compute.
Catalog of Refactoring (6) Making Method Calls Simpler.
Refactoring (1). Software Evolution Cope with change Feature bloat Design decay Code duplications “Pattern time is refactoring time” Make future changes.
A (Very) Simple Example Consolidate duplicate conditional fragments if (isSpecialDeal()) { total = price * 0.95; send (); } else { total = price * 0.98;
Principles and examples
Catalog of Refactoring
Catalog of Refactoring
Introduction to Refactoring
Refactorings Luke Marsh.
CS139 – Fall 2010 How far we have come
Refactoring with inline temp, method, and class
Software Construction and Evolution - CSSE 375 Composing Methods
Refactoring III 27-Nov-18.
Introduction to Refactoring
Improving the structure of existing code
Refactoring III 25-Dec-18.
Refactoring Types Blake Duncan.
References Revisted (Ch 5)
Refactoring.
Presentation transcript:

Catalog of Refactoring (1) Composing Methods

Code Smells Long methods Dubious temporary variables Dubious methods

Catalog Extract Method Inline Method Inline Temp Replace Temp with Query Introduce Explaining Variable Split Temporary Variable Remove Assignments to Parameters Replace Method with Method Object

Extract Method When you have a code fragment that can be logically grouped together. Turn the fragment into a method whose name explains the purpose of the method.

Simple Example void printOwing(double amount) { printBanner(); //print details System.out.println ("name:" + _name); System.out.println ("amount:" + amount); }

Simple Example void printOwing(double amount) { printBanner(); //print details System.out.println ("name:" + _name); System.out.println ("amount" + amount); } Smell: “What” comment void printDetails (double amount) { System.out.println ("name:" + _name); System.out.println ("amount" + amount); }

Motivation Short, well named methods Fine grained methods have increased chances of reuse Allows higher-level methods to read more like a series of comments NOTE: key criteria is not length of the code, but semantic distance

Mechanics 1.Create a new method, and name it after the intention (what) of the method If you can't come up with a meaningful name, don't do it 2.Extract code and insert to target method 3.Pass into the target method as parameters local-scope variables that are read from the extracted code (I.e. not changed) E.g. amount in printDetails method 4.Deal with changed local-scope variables 5.Replace old code with the target method 6.Compile and test

Deal with Changed Local Variables See if it can be replaced by a query and assign the result to the variable concerned If this is awkward, or if there is more than one such variable, you can't extract the method as it stands. You may need to use Split Temporary Variable and try again You can eliminate temporary variables with Replace Temp with Query

Local Variables Changed and Later Used void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }

void printOwing() { printBanner(); printDetails(getOutstanding()); } double getOutstanding() { Enumeration e = _orders.elements(); double result = 0.0; while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result += each.getAmount(); } return result; } Method Extracted and Temp Variable Removed

Inline Method The opposite of Extract Method When a method's body is just as clear as its name. Put the method's body into the body of its callers and remove the method.

Example int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; } boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; }

Example int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; } boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; } int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1; }

Motivation Remove needless indirection When you have a group of methods that seem badly factored. You can inline them all into one big method and then re-extract the methods

Mechanism 1.Check that the method is not polymorphic. Don't inline if subclasses override the method; they cannot override a method that isn't there. 2.Find all calls to the method. 3.Replace each call with the method body. 4.Compile and test. 5.Remove the method definition.

Inline Temp You have a temp that is assigned to once with a simple expression, and the temp is getting in the way of other refactorings. Replace all references to that temp with the expression.

Example double basePrice = anOrder.basePrice(); return (basePrice > 1000) return (anOrder.basePrice() > 1000)

Mechanism 1.Declare the temp as final if it isn't already, and compile. This checks that the temp is really only assigned to once. 2.Find all references to the temp and replace them with the right-hand side of the assignment. 3.Compile and test after each change. 4.Remove the declaration and the assignment of the temp. 5.Compile and test.

Replace Temp with Query You are using a temporary variable to hold the result of an expression. Extract the expression into a method. Replace all references to the temp with the expression. The new method can then be used in other methods.

Motivation Temps tend to encourage longer methods –Because that's the only way you can reach the temps. This refactoring is often vital step before Extract Method –Local variables make code difficult to extract, so replace as many variables as you can with queries.

Mechanism 1.Look for a temporary variable that is assigned to once. –If a temp is set more than once consider Split Temporary Variable. 2.Declare the temp as final and compile. –This will ensure that the temp is only assigned to once. 3.Extract the right-hand side of the assignment into a method. –Initially mark the method as private. –Ensure the extracted method is free of side effects, that is, it does not modify any object. If it is not free of side effects, use Separate Query from Modifier. 4.Compile and test. 5.Use Replace Temp with Query on the temp.

Example double getPrice() { int basePrice = _quantity * _itemPrice; double discountFactor; if (basePrice > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice * discountFactor; }

Example double getPrice() { int basePrice = _quantity * _itemPrice; double discountFactor; if (basePrice > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice * discountFactor; } double getPrice() { final int basePrice = _quantity * _itemPrice; final double discountFactor; if (basePrice > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice * discountFactor; }

double getPrice() { final int basePrice = basePrice(); final double discountFactor; if (basePrice > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice * discountFactor; } private int basePrice() { return _quantity * _itemPrice; }

double getPrice() { final double discountFactor; if (basePrice() > 1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice() * discountFactor; } double getPrice() { return basePrice() * discountFactor(); }

Introduce Explaining Variable You have a complicated expression. Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose.

Motivation Expressions can become very complex and hard to read. In such situations temporary variables can be helpful to break down the expression into something more manageable. –It is particularly valuable with conditional logic in which it is useful to take each clause of a condition and explain what the condition means with a well- named temp. –Another case is a long algorithm, in which each step in the computation can be explained with a temp. If possible, Extract Method is preferred

Mechanism 1.Declare a final temporary variable, and set it to the result of part of the complex expression. 2.Replace the result part of the expression with the value of the temp. –If the result part of the expression is repeated, you can replace the repeats one at a time. 3.Compile and test. 4.Repeat for other parts of the expression.

Example double price() { // price is base price - quantity discount + shipping return _quantity * _itemPrice - Math.max(0, _quantity - 500) * _itemPrice * Math.min(_quantity * _itemPrice * 0.1, 100.0); }

double price() { // price is base price - quantity discount + shipping final double basePrice = _quantity * _itemPrice; return basePrice - Math.max(0, _quantity - 500) * _itemPrice * Math.min(basePrice * 0.1, 100.0); } double price() { final double basePrice = _quantity * _itemPrice; final double quantityDiscount = Math.max(0, _quantity - 500) *_itemPrice * 0.05; final double shipping = Math.min(basePrice * 0.1, 100.0); return basePrice - quantityDiscount + shipping; }

Split Temporary Variable You have a temporary variable assigned to more than once, but is not a loop variable nor a collecting temporary variable. Make a separate temporary variable for each assignment. Any variable with more than one responsibility should be replaced with a temp for each responsibility.

Mechanism 1.Change the name of a temp at its declaration and its first assignment. If the later assignments are of the form i = i + some expression, that indicates that it is a collecting temporary variable, so don't split it. The operator for a collecting temporary variable usually is addition, string concatenation, writing to a stream, or adding to a collection. 2.Declare the new temp as final. 3.Change all references of the temp up to its second assignment. 4.Declare the temp at its second assignment. 5.Compile and test. 6.Repeat in stages, each stage renaming at the declaration, and changing references until the next assignment.

Example Compute the distance traveled by a haggis. From a standing start, a haggis experiences an initial force. After a delayed period a secondary force kicks in to further accelerate the haggis. double getDistanceTravelled (int time) { double result; double acc = _primaryForce / _mass; int primaryTime = Math.min(time, _delay); result = 0.5 * acc * primaryTime * primaryTime; int secondaryTime = time - _delay; if (secondaryTime > 0) { double primaryVel = acc * _delay; acc = (_primaryForce + _secondaryForce) / _mass; result += primaryVel * secondaryTime * acc * secondaryTime * secondaryTime; } return result; }

double getDistanceTravelled (int time) { double result; final double primaryAcc = _primaryForce / _mass; int primaryTime = Math.min(time, _delay); result = 0.5 * primaryAcc * primaryTime * primaryTime; int secondaryTime = time - _delay; if (secondaryTime > 0) { double primaryVel = primaryAcc * _delay; double acc = (_primaryForce + _secondaryForce) / _mass; result += primaryVel * secondaryTime * acc * secondaryTime * secondaryTime; } return result; }

double getDistanceTravelled (int time) { double result; final double primaryAcc = _primaryForce / _mass; int primaryTime = Math.min(time, _delay); result = 0.5 * primaryAcc * primaryTime * primaryTime; int secondaryTime = time - _delay; if (secondaryTime > 0) { double primaryVel = primaryAcc * _delay; final double secondaryAcc = (_primaryForce + _secondaryForce) / _mass; result += primaryVel * secondaryTime * secondaryAcc * secondaryTime * secondaryTime; } return result; }

Remove Assignments to Parameters The code assigns to a parameter. Use a temporary variable instead. int discount(int inputVal, int quantity, int yearToDate) { if (inputVal > 50) inputVal -= 2; int discount (int inputVal, int quantity, int yearToDate) { int result = inputVal; if (inputVal > 50) result -= 2;

Motivation Better clarity, less confusion –Java is Pass by Value only –Even for languages that can pass by reference, it is better to minimize assignment to parameters

Mechanism 1.Create a temporary variable for the parameter. 2.Replace all references to the parameter, made after the assignment, to the temporary variable. 3.Change the assignment to assign to the temporary variable. 4.Compile and test. If the semantics are call by reference, look in the calling method to see whether the parameter is used again afterward. Also see how many call by reference parameters are assigned to and used afterward in this method. Try to pass a single value back as the return value. If there is more than one, see whether you can turn the data clump into an object, or create separate methods.

Replace Method with Method Object You have a long method that uses local variables in such a way that you cannot apply Extract Method. Turn the method into its own object so that all the local variables become fields on that object. You can then decompose the method into other methods on the same object.

Mechanics 1.Create a new class, name it after the method. 2.Give the new class a final field for the object that hosted the original method (the source object) and a field for each temporary variable and each parameter in the method. 3.Give the new class a constructor that takes the source object and each parameter. 4.Give the new class a method named "compute." 5.Copy the body of the original method into compute. Use the source object field for any invocations of methods on the original object. 6.Compile. 7.Replace the old method with one that creates the new object and calls compute.

Simple Example Class Account int gamma (int inputVal, int quantity, int yearToDate) { int importantValue1 = (inputVal * quantity) + delta(); int importantValue2 = (inputVal * yearToDate) + 100; if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; int importantValue3 = importantValue2 * 7; // and so on. return importantValue3 - 2 * importantValue1; }

class Gamma... private final Account _account; private int inputVal; private int quantity; private int yearToDate; private int importantValue1; private int importantValue2; private int importantValue3; Gamma (Account source, int inputValArg, int quantityArg, int yearToDateArg) { account = source; inputVal = inputValArg; quantity = quantityArg; yearToDate = yearToDateArg; }

int compute () { importantValue1 = (inputVal * quantity) + _account.delta(); importantValue2 = (inputVal * yearToDate) + 100; if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; int importantValue3 = importantValue2 * 7; // and so on. return importantValue3 - 2 * importantValue1; } Class Account... int gamma (int inputVal, int quantity, int yearToDate) { return new Gamma(this, inputVal, quantity,yearToDate).compute(); }

Benefit int compute () { importantValue1 = (inputVal * quantity) + _account.delta(); importantValue2 = (inputVal * yearToDate) + 100; importantThing(); int importantValue3 = importantValue2 * 7; // and so on. return importantValue3 - 2 * importantValue1; } void importantThing() { if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; } We can now easily use Extract Method on the compute method without ever worrying about the argument's passing: