Refactoring III Measured Smells Smells Covered 1 Comments

  • Slides: 32
Download presentation
Refactoring – III Measured Smells

Refactoring – III Measured Smells

Smells Covered • 1. Comments • 2. Long method • 3. Large Class 46

Smells Covered • 1. Comments • 2. Long method • 3. Large Class 46 2

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

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

Comments • What to do: – Extract Method: When comment explains block of code,

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

Comments – Extract Method Void print. Owing (double amount){ print. Banner(); // print details

Comments – Extract Method Void print. Owing (double amount){ print. Banner(); // print details System. out. println (“name: ” + name); System. out. println (“amount: ” + amount); Change to: void print. Owing (double amount){ print. Banner(); print. Details (amount); }// end print. Owning() void print. Details(double amount) { System. out. println (“name: ” + name); System. out. println (“amount: ” + amount); }// end print. Details() 46 5

Comments – Extract Method Motivation • Extract Method is a very common refactoring. •

Comments – Extract Method Motivation • 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. 46 – Overriding also is easier when the methods finely grained. 6

Mechanics of Extract Method • 1. Create new method • Name after the intention

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 46 7 new target method.

Mechanics (continued) • 2. Scan the extracted code for references to any variables that

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

Mechanics (continued) • Scope of Variables: Look to see whether any of these local-scope

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

Mechanics • Pass Variables- Pass variables to target method as parameters local-scope variables read

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

Comments – Rename Method • The name of a method does not reveal its

Comments – Rename Method • The name of a method does not reveal its purpose. • 02 Change the name of the method. 46 11

Comments – Rename Method • Author advocates small methods to factor complex processes. •

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

Comments – Rename Method Motivation • Remember your code is for a human first

Comments – Rename Method Motivation • 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

Comments – Rename Method Mechanics • Check to see whether the method signature is

Comments – Rename Method Mechanics • 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

Comments – Rename Method Example • Have a method to get a person’s telephone

Comments – Rename Method Example • Have a method to get a person’s telephone number: • public String get. Telephone. Number() { return ("(" + _office. Area. Code + ") " + _office. Number); } • • Want to rename method to get. Office. Telephone. Number. Create new method and copy body to new method. Change Old method to call the new one: class Person. . . public String get. Telephone. Number(){ return get. Office. Telephone. Number(); } public String get. Office. Telephone. Number() { return ("(" + _office. Area. Code + ") " + _office. Number); } • Find callers of old method, Switch them to call the new one. • After switching, can remove the old method. 46 15

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

Comments – Introduce Assertion • A section of code assumes something about the state of the program. Make the assumption explicit with an assertion. double get. Expense. Limit() { // should have either expense limit or a primary project return (_expense. Limit != NULL_EXPENSE) ? expense. Limit: primary. Project. get. Member. Expense. Limit(); }// end get. Expense. Limit() double get. Expense. Limit() { Assert. is. True (expense. Limit != NULL_EXPENSE || primary. Project != null); return (expense. Limit != NULL_EXPENSE) ? expense. Limit: primary. Project. get. Member. Expense. Limit(); }// end get. Expense. Limit() 46 16

II. Refactoring – Long Method • Symptoms – Large number of lines. Be immediately

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

Refactoring – Long Method (cont. ) • What to do: – Use Extract Method

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

Refactoring – Long Method (cont. ) • Discussion: – Performance issues due to number

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

III. Refactoring – Large Class • Symptoms: – Large number of instance variables –

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

Refactoring – Large Class • What to do: – In general, trying to break

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: 46 – Improves communication. May expose duplication 21

IIIa. Refactoring – Extract Class • Here you have one class doing work of

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

Refactoring – Extract Class Motivation • Have heard a class should be a crisp

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

Refactoring – Extract Class • Such a class is Motivation – one with many

Refactoring – Extract Class • Such a class is Motivation – 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

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

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?

Refactoring – Extract Class Mechanics • Decide how to split the responsibilities of the

Refactoring – Extract Class Mechanics • 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

Refactoring – Extract Class Mechanics • Use Move Field on each field you wish

Refactoring – Extract Class Mechanics • 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

Refactoring – Extract Class Example • class Person. . . • public String get.

Refactoring – Extract Class Example • class Person. . . • public String get. Name() { return name; } public String get. Telephone. Number() { return ("(" + office. Area. Code + ") " + office. Number); } public String get. Office. Area. Code() { return office. Area. Code; } public void set. Office. Area. Code(String arg) {office. Area. Code = arg; } public String get. Office. Number() { return office. Number; } public void set. Office. Number(String arg) { office. Number = arg; } private String name; private String office. Area. Code; private String office. Number; • In this case I can separate the telephone number behavior into its own class. I start by defining a telephone number class: 46 28

In this case I can separate the telephone number behavior into its own class.

In this case I can separate the telephone number behavior into its own class. I start by defining a telephone number class: • class Telephone. Number { • That was easy! • No problems. }// end class • I next make a link from the person to the telephone number: • class Person private Telephone. Number office. Telephone = new Telephone. Number(); That too was easy. Note all the while your program still runs! 46 29

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

• Now I use Move Field on one of the fields: class Telephone. Number • • • { String get. Area. Code() return area. Code; }// end Telephone. Number() void set. Area. Code (String arg) { area. Code = arg; }// end set. Area. Code() private String area. Code; }// end class Telephone. Number class Person. . . • • • public String get. Telephone. Number() { return ("(" + get. Office. Area. Code() + ") " + office. Number); }// end get. Telephone. Number() • • • String get. Office. Area. Code() { return office. Telephone. get. Area. Code(); }// end get. Office Area. Code() • • • 46 void set. Office. Area. Code(String arg) { office. Telephone. set. Area. Code(arg); }// end set. OFfice. Area. Code() 30

 • • • • • • 46 • I can then move the

• • • • • • 46 • I can then move the other field and use Move Method on the telephone number: class Person. . . public String get. Name() { return name; } public String get. Telephone. Number(){ return office. Telephone. get. Telephone. Number(); } Telephone. Number get. Office. Telephone() { return office. Telephone; } private String name; private Telephone. Number office. Telephone = new Telephone. Number(); class Telephone. Number. . . public String get. Telephone. Number() { return ("(" + _area. Code + ") " + number); String get. Area. Code() { return area. Code; } void set. Area. Code(String arg) { area. Code = arg; } String get. Number() { return number; } void set. Number(String arg) { number = arg; } private String number; private String area. Code; } 31

V. Conclusion • The smells in this set of slides are the easiest to

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