22
Jun 18, 2 022 Refactoring III

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,

  • View
    217

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 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,

Apr 18, 2023

Refactoring III

Page 2: 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,

General philosophy

A refactoring is just a way of rearranging code Refactorings are used to solve problems If there’s no problem, you shouldn’t refactor

The notion of “bad smells” is a way of helping us recognize when we have a problem

Familiarity with bad smells also helps us avoid them in the first place

Refactorings are mostly pretty obvious Most of the value in discussing them is just to bring them into our

“conscious toolbox” Refactorings have names in order to crystallize the idea and help us

remember it

Page 3: 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,

Duplicated code

Martin Fowler refers to duplicated code as “Number one in the stink parade” The usual solution is to apply Extract Method: Create a single

method from the repeated code, and use it wherever needed We’ve discussed some of the details of this (adding a

parameter list, etc.) This adds the overhead of method calls, thus the code

gets a bit slower Is this a problem?

Page 4: 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,

Making code faster “We should forget about small efficiencies, say about 97% of the time: premature

optimization is the root of all evil.” -- Tony Hoare

Rules of Optimization: Rule 1: Don't do it. Rule 2 (for experts only): Don't do it yet. -- M.A. Jackson

“More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason--including blind stupidity.” -- W.A. Wulf

Very few programs actually need to be faster The only two examples I can think of are game graphics and Blackboard

Donald E. Knuth pointed out (in 1970) that it is essentially impossible to predict where the bottlenecks are in a program--you need to use a profiler to actually measure what the code is doing

Page 5: 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,

Long methods

Another “bad smell” is the overly long method Almost always, you can fix long methods by applying

Extract Method Find parts of the method that seem to perform a single task,

and make them into a new method Potential problem: You may end up with lots of

parameters and temporary variables Temporaries: Consider Replace Temp With Query Parameters: Try Introduce Parameter Object and Preserve

Whole Object If all else fails, use Replace Method With Method Object

Page 6: 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,

Temporary variables

According to Fowler, temporary variables “tend to encourage longer methods, because that’s the only way you can get at the temp.”

If the code fragment you want to extract into a method contains references to temporary variables whose scope overlaps the fragment, you have to somehow provide access to that temporary variable

Solution: Use the Replace Temp With Query refactoring

Page 7: 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,

Replace Temp With Query Create a method to compute or access the temporary variable

Example (from Fowler):

Replace: double basePrice = quantity * itemPrice; if (basePrice > 1000) return basePrice * 0.95; else return basePrice * 0.98;

with: if (basePrice() > 1000) return basePrice() * 0.95; else return basePrice() * 0.98; ... double basePrice() { return quantity * itemPrice; }

Page 8: 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,

Introduce Parameter Object

Problem: You have a method that requires a long parameter list You may have a group of parameters that go naturally together If so, make them into an object

Example: Replace public void marry(String name, int age, boolean gender, String name2, int age2, boolean gender2) {...}with public void marry(Person person1, Person person2) {...}

Page 9: 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,

Preserve Whole Object

Problem: You have a method that requires a long parameter list

If you are passing in multiple values from the same object, pass the object in instead

Example: Replace sendBill(customer.name, customer.address, customer.order, amount);with sendBill(customer, amount);

Page 10: 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,

Replace Method With Method Object If: you have a long method that uses local variables, and you

can’t use Extract Method, Then: turn the method itself into a object

Create a new class, named after the method Give the new class the following fields:

A final field to hold the object that the method originally came from A field for each temporary variable and parameter in the method

Write a constructor that takes as parameters the original object and the parameters of the original method

Copy the original method into the new class If you need anything from the original object, you have a reference to it

All the old local variables are now fields of the object This makes it easy to decompose the long method into as many methods

as you want

Page 11: 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,

Long parameter list

Long parameter lists are difficult to understand, difficult to remember, and make it harder to format your code nicely

We’ve already discussed some solutions, such as Introduce Parameter Object

Another solution, which we won’t go into in detail, is called Replace Parameter With Method The idea is that you shouldn’t pass a parameter into a method

if the method has enough information to compute the parameter for itself

Page 12: 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,

Large class

Classes can get overly large Too many instance variables More than a couple dozen methods Seemingly unrelated methods in the same class

Possible refactorings are Extract Class and Extract Subclass

A related refactoring, Extract Interface, can be helpful in determining how to break up a large class

Page 13: 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,

Extract Class

Extract Class is used when you decide to break one class into two classes Classes tend to grow, and get more and more data Good signs:

A subset of the data and a subset of the methods seem to go together A subset of the data seems to be interdependent

Useful tests: If you removed a method or a particular piece of data, what other

fields and methods would become nonsense? How is the class subtyped?

The actual refactoring technique involves creating a new (empty) class, and repeatedly moving fields and methods into it, compiling and testing after each move

Page 14: 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,

Extract Subclass

Extract Subclass is used when some behaviors of a class are used for certain instances, but not others

If you have a “type code” that is used to distinguish between types of objects, this suggests that a subclass may be appropriate

The type code can be eliminated when you create the subclass Extract Subclass should not be used when the instances vary in more

than one respect

The basic steps are: Define the subclass, provide constructors, and use Push Down Method and Push Down Field refactorings

We won’t go into the details of these refactorings

Page 15: 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,

Extract Interface

Extract Interface is used when two or more classes share a related set of behaviors For example, you might provide two or more types of

services to your customers, with similar but separate billing needs

This suggests a Billable interface I hire J&K landscaping to do routine mowing and yard

clearing; they also remove fallen trees, but bill the job differently

Java’s Collections make heavy use of interfaces, as you have to do similar things (add, remove, iterate over) the elements of Sets, Vectors, Stacks, etc.

Page 16: 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,

Feature envy

“Feature envy” is when a method makes heavy use of data and methods from another class Use Move Method to put it in the more desired class

Sometimes only part of the method makes heavy use of the features of another class Use Extract Method to extract those parts that belong in the

other class

Page 17: 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,

Primitive Obsession

Many programmers are reluctant to introduce “little” classes that represent things easily represented by primitives—telephone numbers, zip codes, money amounts, ranges (variables with upper and lower bounds)

If your primitive needs any additional data or behavior, consider turning it into a class For example, you may want to format your primitive in a

special way, such as (215)898-0587 or 19104-6389

Page 18: 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,

More bad smells, I

Divergent Change: One class keeps being changed in different ways for different reasons Identify each cause of change, and use Extract Class to isolate

the required changes for that cause

Shotgun Surgery: Every time you make a change, you have to make a lot of little changes in various classes Group all the changes into a single class with Move Method

and Move Field

Page 19: 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,

More bad smells, II

Data Clumps: Data fields that occur together in numerous places Use Extract Class to group the fields into a single object Look for parameter lists that can be abbreviated by using this new object,

and use Introduce Parameter Object or Preserve Whole Object

Switch Statements: A switch statement is used to do different things based on some type flag

Perhaps the types should be subclasses Use Extract Method to isolate the switch statement Use Move Method to put it into the class that needs these types Use Replace Type Code with Subclasses

Page 20: 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,

Testing for null According to Fowler:

“The essence of polymorphism is that instead of asking an object what type it is and then invoking some behavior based on the answer, you just invoke the behavior. The object, depending on its type, does the right thing.”

Unfortunately, if the object might be null, you have to test it first, or risk getting a NullPointerException

An occasional test for null isn’t so bad, but a lot of them will clutter up the code and be a nuisance

Solution: Introduce a “null object”—a real object of the correct class (or a subclass of the correct class) that has the appropriate behavior

Page 21: 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 in Eclipse 3.2.1

Page 22: 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,

The End