Refactoring – III

32
Refactoring – III Measured Smells

description

Refactoring – III. Measured Smells. Smells Covered. 1. Comments 2. Long method 3. Large Class. 1. Comments. Symptoms: symbols (// or /*) appear on code. Some IDEs color them. Causes: Present for many reasons; Author realizes that something isn’t as clear and adds a comment. - PowerPoint PPT Presentation

Transcript of Refactoring – III

Page 1: Refactoring – III

Refactoring – III

Measured Smells

Page 2: Refactoring – III

Smells Covered

• 1. Comments• 2. Long method• 3. Large Class

46 2

Page 3: Refactoring – III

1. Comments

• Symptoms: symbols (// or /*) appear on code. Some IDEs color them.

• Causes: Present for many reasons; • Author realizes that something isn’t as clear and

adds a comment.– Some comments may be helpful

• Tell why something is done a particular way (or not)• Cite an algorithm not obvious (when a simpler algorithm

won’t do)• Other times: comment not necessary; goal of a routine may

be communicated via its name

46 3

Page 4: Refactoring – III

Comments• What to do:

– Extract Method: When comment explains block of code, can often use this one to pull the block into a separate method.

– Comment will often suggest a name for the new method– Rename Method: When comment explains what a method

does better than the method’s name use comment as basis of the new name

– Introduce Assertion: When comment explains preconditions, consider this one to replace the comment with code.

• Payoff:– Improves communication. May expose duplication

• Contraindications– Don’t delete comments pulling their own weight.

46 4

Page 5: Refactoring – III

Comments – Extract MethodVoid printOwing (double amount){

printBanner();// print detailsSystem.out.println (“name:” + name);System.out.println (“amount:” + amount);

Change to:void printOwing (double amount){

printBanner();printDetails (amount);

}// end printOwning()

void printDetails(double amount) {System.out.println (“name:” + name);System.out.println (“amount:” + amount);

}// end printDetails()

46 5

Page 6: Refactoring – III

Comments – Extract MethodMotivation• Extract Method is a very common refactoring. • Look at long method or code that needs a comment to understand its purpose.• Turn fragment of code into its own method.

• Prefer short, well-named methods; several reasons. • First, it increases the chances that other methods can use a method when the method is finely grained.• Second, it allows the higher-level methods to read more like a series of comments. – Overriding also is easier when the methods finely grained.

46 6

Page 7: Refactoring – III

Mechanics of Extract Method• 1. Create new method

• Name after the intention of the method – (name it by what it does, not by how it does it).

• If code you want to extract is very simple, such as a single message or function call, can extract if name of new method will reveal intention of the code in a better way.

• If you can’t come up with a more meaningful name, don’t extract the code.

• Copy the extracted code from the source method into the new target method.46 7

Page 8: Refactoring – III

Mechanics (continued)

• 2. Scan the extracted code for references to any variables that are local in scope to the source method.

• These are local variables and parameters to the method.

• See whether any temporary variables are used only within this extracted code.

• If so, declare them in the target method as temporary variables.

46 8

Page 9: Refactoring – III

Mechanics (continued)

• Scope of Variables: Look to see whether any of these local-scope variables are modified by the extracted code. – If one variable is modified, see whether you can treat extracted

code as a query and assign result to 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.

46 9

Page 10: Refactoring – III

Mechanics• Pass Variables- Pass variables to target method as

parameters local-scope variables read from extracted code.

• Compile after dealing with all locally-scoped variables.

• Replace extracted code in source with call to target method.

• If you moved temporary variables over to target method, look to see whether they were declared outside of the extracted code. If so, you can now remove the declaration.

• Compile and test.46 10

Page 11: Refactoring – III

Comments – Rename Method

• The name of a method does not reveal its purpose.

• 02Change the name of the method.

46 11

Page 12: Refactoring – III

Comments – Rename Method• Author advocates small methods to

factor complex processes. • Done badly, can lead to merry dance to

find out what all the little methods do. • Key: name methods that communicate

their intention. – Good way: Think what comment for

method would be.– Turn comment into name of method– If you see a badly named method,

CHANGE IT!

46 12

Page 13: Refactoring – III

Comments – Rename MethodMotivation

• Remember your code is for a human first and a computer second. – Humans need good names.

• Good naming is a skill and is key to being a truly skillful programmer.

• Same applies to other aspects of the signature.

• If reordering parameters clarifies matters, do it. (see Add Parameter and Remove Parameter).

46 13

Page 14: Refactoring – III

Comments – Rename MethodMechanics

• Check to see whether the method signature is implemented by a superclass or subclass.

• If so, perform these steps for each implementation.– Declare a new method with the new name. – Copy old body of code to new name; make alterations.– Compile.– Change body of old method so it calls new one.– Compile and test.– Find all references to old method name and change them

to refer to the new one. – Compile and test after each change.– Remove the old method.

• If the old method is part of the interface and you cannot remove it, leave it in place and mark it as deprecated.

– Compile and test.

46 14

Page 15: Refactoring – III

Comments – Rename MethodExample

• Have a method to get a person’s telephone number:• public String getTelephoneNumber() { return ("(" + _officeAreaCode + ") "

+ _officeNumber); }

• Want to rename method to getOfficeTelephoneNumber. • Create new method and copy body to new method. • Change Old method to call the new one:• class Person...

public String getTelephoneNumber(){ return getOfficeTelephoneNumber(); } public String getOfficeTelephoneNumber() { return ("(" + _officeAreaCode + ") " + _officeNumber); }

• Find callers of old method, Switch them to call the new one.

• After switching, can remove the old method.46 15

Page 16: Refactoring – III

Comments – Introduce Assertion• A section of code assumes something about the state of the program.

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();}// end getExpenseLimit()

double getExpenseLimit() { Assert.isTrue (expenseLimit != NULL_EXPENSE || primaryProject != null); return (expenseLimit != NULL_EXPENSE) ? expenseLimit:

primaryProject.getMemberExpenseLimit();}// end getExpenseLimit()

46 16

Page 17: Refactoring – III

II. Refactoring – Long Method

• Symptoms– Large number of lines. Be immediately suspicious of

any method with more than 5 to 10 lines)

• Causes:– A method starts down a path and, rather than break

the flow or identify the helper classes, the author adds “one more thing”.

– Code is often easier to write than it is to read– So there’s a temptation to write blocks that are too

big.

46 17

Page 18: Refactoring – III

Refactoring – Long Method (cont.)

• What to do:– Use Extract Method to break method into smaller pieces.

– Look for comments or white space delineating

interesting blocks. – Extract methods semantically meaningful, not just

introduce a function call every seven lines.• Payoff:– Improves communications. – May expose duplication. – Often helps new classes and abstractions emerge.

46 18

Page 19: Refactoring – III

Refactoring – Long Method (cont.)

• Discussion: – Performance issues due to number of calls?• Most of the time, this is a nonissue.

– By getting code as clean as possible before worrying about performance, may gain big insights to restructure systems and algorithms in a way that dramatically increases performance.

• Contraindications:– Sometimes longer method is best way to express something. – Like almost all smells, length is a warning sign – not a guarantee- of problem.

46 19

Page 20: Refactoring – III

III. Refactoring – Large Class• Symptoms:

– Large number of instance variables– Large number of methods– Large number of lines

• Causes:– Large classes get bit a little bit at a time.

– Author keeps adding just one more capability to a class until eventually it grows too big.

– Sometimes the problem is a lack of insight into the parts that make up the whole class.

– In any case, the class represents too many responsibilities folded together.

46 20

Page 21: Refactoring – III

Refactoring – Large Class• What to do: – In general, trying to break up the class. – If class has Long Methods, address that smell first. – To break up the class, three approaches are most common:

• Extract Class – If you can identify a new class that has part of this class’s responsibilities

• Extract Subclass, if you can divide responsibilities between the class and a new subclass

• Extract Interface, if you can identify subsets of features that clients use.

– Sometimes class is big because it’s a GUI class, and it represents not only the display component, but model as well.

• Payoff:– Improves communication. May expose duplication

46 21

Page 22: Refactoring – III

IIIa. Refactoring – Extract Class

• Here you have one class doing work of two.• Create a new class and • Move relevant fields and methods from old class into

new class.

46 22

Page 23: Refactoring – III

Refactoring – Extract Class

Motivation• Have heard a class should be a crisp abstraction,

handle a few clear responsibilities, or similar.

• In practice, classes grow. • Often we add a responsibility to a class feeling it’s

not worth a separate class, but as that responsibility grows and breeds, class becomes too complicated.

• Soon, class is as crisp as a micro-waved duck.

46 23

Page 24: Refactoring – III

Refactoring – Extract ClassMotivation

• Such a class is – one with many methods and quite a lot of data. – A class that is too big to understand easily.

• Consider where it can be split, and you split it.

46 24

Page 25: Refactoring – III

Where to Split – Good Signs:• A subset of the data and a subset of the methods

seem to go together.

• Subsets of data that usually change together or are particularly dependent on each other.

• Useful test: – What would happen if you removed a piece of data or a

method. – What other fields and methods would become nonsense?

Page 26: Refactoring – III

Refactoring – Extract ClassMechanics

• Decide how to split the responsibilities of the class.

• Create a new class to express the split-off responsibilities.

• If the responsibilities of the old class no longer match its name, rename the old class.

• Make a link from the old to the new class.

• You may need a two-way link. But don’t make the back link until you find you need it.

• More:

46 26

Page 27: Refactoring – III

Refactoring – Extract ClassMechanics

• Use Move Field on each field you wish to move.

• Compile and test after each move.

• Use Move Method to move methods over from old to new. Start with lower-level methods (called rather than calling) and build to the higher level.

• Compile and test after each move.

• Review and reduce the interfaces of each class.

• Decide whether to expose the new class.

• If you do expose the class, decide whether to expose it as a reference object or as an immutable value object.

46 27

Page 28: Refactoring – III

Refactoring – Extract ClassExample

• class Person...• public String getName() { return name; } public String getTelephoneNumber() {

return ("(" + officeAreaCode + ") " + officeNumber); }

public String getOfficeAreaCode() { return officeAreaCode; } public void setOfficeAreaCode(String arg) {officeAreaCode = arg; }

public String getOfficeNumber() { return officeNumber; }

public void setOfficeNumber(String arg) { officeNumber = arg; } private String name;

private String officeAreaCode; private String officeNumber;

• In this case I can separate the telephone number behavior into its own class. I start by defining a telephone number class:

46 28

Page 29: Refactoring – III

In this case I can separate the telephone number behavior into its own class. I start by defining a telephone number class:

• class TelephoneNumber { }// end class• That was easy! • No problems.

• I next make a link from the person to the telephone number:• class Person private TelephoneNumber officeTelephone = new TelephoneNumber();

That too was easy.Note all the while your program still runs!

46 29

Page 30: Refactoring – III

• Now I use Move Field on one of the fields:

class TelephoneNumber • { String getAreaCode() • return areaCode;• }// end TelephoneNumber()

• void setAreaCode (String arg) {• areaCode = arg;• }// end setAreaCode()

• private String areaCode;• }// end class TelephoneNumber

• class Person...• public String getTelephoneNumber() {• return ("(" + getOfficeAreaCode() + ") " + officeNumber);• }// end getTelephoneNumber()

• String getOfficeAreaCode() {• return officeTelephone.getAreaCode();• }// end getOffice AreaCode()

• void setOfficeAreaCode(String arg) {• officeTelephone.setAreaCode(arg);• }// end setOFficeAreaCode()46 30

Page 31: Refactoring – III

• I can then move the other field and use Move Method on the telephone number:• class Person...• public String getName() {• return name; }• public String getTelephoneNumber(){• return officeTelephone.getTelephoneNumber(); }• • TelephoneNumber getOfficeTelephone() {• return officeTelephone; }• private String name;• private TelephoneNumber officeTelephone = new TelephoneNumber();

• class TelephoneNumber...• public String getTelephoneNumber() {• return ("(" + _areaCode + ") " + number); }• String getAreaCode() {• return areaCode; }• void setAreaCode(String arg) {• areaCode = arg; }• String getNumber() {• return number; }• void setNumber(String arg) {• number = arg; }• private String number;• private String areaCode; 46 31

Page 32: Refactoring – III

V. Conclusion• The smells in this set of slides are the easiest to identify. • They’re not necessarily the easiest to fix.

• There are other metrics that have been applied to software. • Many of them are simply refinements of code length. • Pay attention when things feel like they’re getting too big.

• There is not a one-to-one relationship between refactorings and smells; we’ll run into the same refactorings again. – For example, Extract Method is a tool that can fix many problems.

• Finally, remember a smell is an indication of a potential problem, not a guarantee of an actual problem.

• You will occasionally find false positives – things that smell to you, but are actually better than the alternatives.

• But most code has plenty of real smells that can keep you busy.

46 32