Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
Refactoring
An interesting comment
• "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." (Fowler)
Another quote• “Refactoring is like continuing repair of a living
system. The goal is to stay within reasonable operating limits with limited continual damage. By staying within these limits you keep costs low, because costs relate nonlinearly to the amount of repair necessary. It is like maintaining your house. You are best off (financially) if you continuously maintain rather than do large lump repairs.” (Dirk Riehle (quoted in Jim Highsmith’s Agile Software Development Ecosystems, page 155))
What is refactoring?• Refactoring is changing a software system by improving
its internal structure without changing its external behavior, i.e. it is a technique to restructure the code in a disciplined way to improve its internal structure.
• The process could be informally referred to as "cleaning up" or "taking out the garbage." Refactoring neither fixes bugs nor adds new functionality, though it might precede either activity. Rather, it improves the understandability of the code, changes its internal structure and design, and removes dead code. (Wiki)
Definition from http://www.refactoring.com/
• “Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations.Each transformation (called a 'refactoring') does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it is less likely to go wrong. The system is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.”
What is refactoring
• “A change to the system that leaves itsbehavior unchanged, but enhances somenonfunctional quality – simplicity,flexibility, understandability, performance”(Kent Beck, Extreme Programming
Explained)
Defining Refactoring
• (Noun) – A change made to internal structure of software to make it easier to understand and modify without changing its observable behavior.
• (Verb) – to structure software by applying a series of refactorings without changing its observable behavior
Why refactor? Argument 1
• The changes in refactoring are intended to make the code easier to comprehend, more maintainable, and more amenable to change.
• Refactoring is usually motivated by the difficulty of adding new functionality to a program or fixing a bug in it.
Why should refactoring be done? Argument 2
• Refactoring Improves the Design of Software. - Without refactoring, the design of the program will decay. As people change code - changes to realize short-term goals or changes made without a full comprehension of the design of the code -the code loses its structure.
Why should refactoring be done? Argument 3
• Refactoring makes software easier to understand.
• There are users of your code:– The computer, – the writer, and – the updater.
• The most important is the updater. • Who cares if the compiler takes a few more
cycles to compile your code. • If it takes someone 3 weeks to update your code
that is a problem.
Why refactoring? Argument 4
• Refactoring helps you find bugs. • Part of refactoring code is understanding
the code and putting that understanding back into the code.
• In that process a clarification takes place. • In that clarification bugs will be found.
Why refactor? Argument 5
• Refactoring Helps you Program Faster. • Without a good design, you can progress
quickly for a while, but soon poor design start to slow you down.
• You spend time finding and fixing bugs and understanding the system instead of adding new function.
• New features need more coding as you patch over a patches.
Refactoring and Design?
• Refactoring compliments design. • By doing some of the design along the
way, programmers avoid the problems of over designing for reuse, flexibility, or extendibility that is never needed.
Refactoring and Performance.
• In the short refactoring may make the code slower.
• Manage the optimization for performance in a different way to alleviate the above problem.
Manage Optimization
• The intent in refactoring is of better design and more understandable code.
• Often, but not always, this makes the code slower.
• The recommendation is for a system to be completely built, then analyzed for performance and optimized for the 10% of the system that is the slowest.
• That optimization may work better in the end and the refactoring will meet its intent.
Why people hesitate to refactor• Conventional wisdom would discourage
modifying a design– You might break something in the code,– You have to update the documentation.
• Expensive• But, there are longer term concerns.• Sticking with an inappropriate design
– Makes the code harder to change– Makes the code harder to understand and maintain– Very expensive in the long run
Motivation for refactoring• Contrary to idealized development strategy: analysis and design code test• At first, code is pretty good but as requirements
change or new features are added, the code structure tends to atrophy. Refactoring is the process of fixing a bad or chaotic design.
• Amounts to moving methods around, creating new methods, adding or deleting classes.
From Crispin & House, Testing Extreme Programming
• Duplication & needless complexity areremoved from the code during each codingsession, even when this requires modifyingcomponents that are already “complete.”• Automated unit tests are used to verifyevery change.
When to Refractor ?
• When you add a functionHelps you to understand the code you are modifying.Sometimes the existing design does not allow you to easily add the feature.
• When you need to fix a bugIf you get a bug report its a sign the code needs refactoring because the code was not clear enough for you to see the bug in the first place.
When to Refactor ? Continued
• When you do a Code Review- Code reviews help spread knowledge through the development team.- Works best with small review groups.
Benefits of Refactoring
Refactoring is useful to any program that has at least one of the following shortcomings:
• Programs that are hard to read are hard to modify.
• Programs that have duplicate logic are hard to modify.
Benefits of Refactoring(Continued)
• Programs that require additional behavior which requires you to change running code are hard to modify.
• Programs with complex conditional logic are hard to modify.
Refactoring Risks
• Introducing a failure with refactoring can have serious consequences.
• When done on a system that is already in production, the consequences of introducing bugs without catching them are very severe.
Costs of Refactoring
Language / Environment :Depends on how well the operations on the source code are supported. But in general the cost of applying the basic text modifications should be bearable.
Testing :Relies heavily on testing after each small step and having a solid test suite of unit tests for the whole system substantially reduces the costs which would be implied by testing manually
Costs of Refactoring (Continued)
Documentation :
Costs of updating documentation of the project should not be underestimated as applying refactorings involves changes in interfaces, names, parameter lists and so on.
All the documentation concerning these issues must be updated to the current state of development.
Costs of Refactoring (Continued)
System :
The tests covering the system need an update as well as the interfaces and responsibilities change. These necessary changes can contribute to higher costs as tests are mostly very dependent on the implementation.
When to put Off Refactoring ?• Concerned code is neither able to compile
or to run in a stable manner, it might be better to throw it away and rewrite the software from scratch.
• When a deadline is very close. Then it would take more time to do the refactoring than the deadline allows.
Properties of Refactoring
• Preserve Correctness
• One step at a time
• Frequent Testing
Design Attributes
• Abstraction (information hiding)
• Flexibility
• Clarity
• Irredundancy
Steps to Refactoring
• Identify heavily used or time consuming code.
• Refactoring begins by designing a solid set of tests for the section of code under analysis.
• Identify problems in code by review using bad smells of code.
• Introduce a refactoring and test.
Steps to Refactoring (Continued)
• The steps taken when applying the refactoring should be:
- Small enough to oversee the consequences they have.
- Reproduceable to allow others to understand them.
- Generalized in a way, that they are more a rule that can be applied to any structure.
- Written down to allow sharing these steps and to keep a reference, with step by step instructions how to apply them.
The first steps in refactoring is testing.
• The first step in refactoring is to build a solid set of tests for that section of code.
• In refactoring functionality does not change.
• Tests are the only insurance that changes to the coded design will not change the functionality.
Basic idea
Make sure your tests passFind some code that “smells”Determine how to simplify this codeMake the simplificationsRun tests to ensure things still work
correctlyRepeat the simplify/test cycle until the
smell is gone
What is “code smell”?• In computer programming, code smell is any symptom
in the source code of a program that possibly indicates a deeper problem.
• Often the deeper problem hinted by a code smell can be uncovered when the code is subjected to a short feedback cycle where it is refactored in small, controlled steps, and the resulting design is examined to see if there are any further code smells that indicate the need of more refactoring.
• From the point of view of a programmer charged with performing refactoring, code smells are heuristics to indicate when to refactor, and what specific refactoring techniques to use. Thus, a code smell is a driver for refactoring. (From Wiki)
Common “smells”• Duplicate code: identical or very similar code exists in
more than one location. • Long method: a method, function, or procedure that has
grown too large. • Large class: a class that has grown too large.• Long Parameter List: too many parameters in a method.• Feature envy: a class that uses methods of another
class excessively. • Divergent Change: a class that does distinctly different
things.• Shotgun Surgery: a change in one class repeatedly
requires little changes in a bunch of other classes.
Common “smells”• Inappropriate intimacy: a class that has dependencies on
implementation details of another class. • Data Clumps Data that's always hanging with each other
(e.g. name street zip).• Switch (case) statements: Long and complicated switch
case.• Refused bequest: a class that overrides a method of a base
class in such a way that the contract of the base class is not honored by derived class. This will be clear when we go to Liskov substitution principle.
• Lazy class: a class that does too little. • Duplicated method: a method, function, or procedure that is
very similar to another. • Contrived Complexity: forced usage of overly complicated
design patterns where simpler design would suffice.
A quick tour of basic refactoring techniques
• Extract Method :• When we have a code fragment that can be grouped together.• Turn the fragment into a method whose name explains the purpose
of the method.
void printOwing() {
printBanner(); //print details
System.out.println ("name:" + _name);
System.out.println("amount" + getOutstanding());
}
void printOwing() {
printBanner();
printDetails(getOutstanding());}void printDetails (double outstanding) {System.out.println ("name:" +
_name);System.out.println ("amount:" +
outstanding);}
A quick tour of basic refactoring techniquesDuplicated Code
--extract out the common bits into their own method (extract method), if code is in same class.
--if two classes duplicate code, consider extract class to create a new class to hold the shared functionality.
Long Methods
use extract method to break it up into smaller, more understandable pieces.
A quick tour of basic refactoring techniquesLong Parameter List
--replace parameter with method (dont' pass data the receiver can get on its own accord -- receiver explicitly asks for data itself via sender getter method)
OR: if the parameters are a natural, self-contained grouping, introduce parameter object.Example: day month, year, hour minute second parameters ==> date parameter
Large Class:Class trying to do too much - often shows up as too many
instance variables. Break into smaller cohesive classes.
A quick tour of basic refactoring techniques
Divergent ChangeIf you have a fixed class that does distinctly different things consider separating out the varying code into varying classes (extract class)that either subclass or are contained by the non-varying class. This is closely related to the Single Responsibility Principle.
Do you look at a class and say:a) These three methods deals with data baseb) These four methods deal with financial policy.
Divergent change is needed when you have a class that has to be involved in many different “kinds” of changes.
Then you probably need at least two classes not one.Any change to handle a variation should change a distinct class
A quick tour of basic refactoring techniques
Shotgun SurgeryThis situation occurs when every time you make a kind of change, you have to make a lot of little changes to a lot of different classes. This is the opposite to divergent change.Shotgun surgery is needed when you have many classes that have to be involved in one “kind” of change.
--perform MOVE METHOD/FIELD to bring a whole bunch of behavior together since they are obviously highly interdependent.
If no suitable target class exists – create one.
A quick tour of basic refactoring techniquesFeature EnvyIt is a method that seems more interested in a class other
in the one that it is in.Example: a method that invokes numerous getter methods
on another object to get some information and then perform the operation.
Solution -- perform MOVE METHOD or EXTRACT METHOD on the jealous bit and get it home.
However, a method may use features of several classes. Heuristic – determine which class has most of the data and
move the method with that data.
Idea to remember – put together things that change together.
A quick tour of basic refactoring techniquesData Clumps
Data that's always hanging with each other (e.g. name street zip).--Extract out a class (extract class) for the data. Will help trim argument lists too, since name street zip now passed as one address object. Related to long parameter list above.
One good test – delete of the data values. Do others by themselves make sense?
Idea – don’t be shy about making “small” objects for “small tasks.
Example – money class that have a currency and amount.
A quick tour of basic refactoring techniquesSwitch (case) statements
switch statements are often duplicated – the same switch statement appears in multiple places in the code.
Consider a method that deals with customers from Canada, the US, the UK, Germany and Italy. You are likely to find multiple places where different actions are taken depending on the country the customer is from.Now suppose you wish to add China to that list.
Conclusion:If you add or remove a clause in one switch, you often have to find and repair the others too.
Refactoring Actions-- Use EXTRACT METHOD to extract the switch statement and then
MOVE METHOD to get it into the class where the polymorphism is needed.
-- Then use replace type code with subclass or replace type code with state/strategy (to be discussed later)
A quick tour of basic refactoring techniquesLazy Class
Class doesn't seem to be doing anything. -- Get rid of it!
collapse hierarchy if subclasses are nearly vacuous. inline class (stick the class' methods and fields in the
class that was using it and get rid of original class).
A quick tour of basic refactoring techniquesHide Delegate :
When a client is calling a delegate class of an object.Idea : a class should not access features of other classes unless it is
absolutely needed. If the delegate class changes the client also has to change. So we should remove the dependency by putting a delegating method to avoid calling capabilities of the delegate class.
Example:Suppose the client deals with object myObject1 of class X which includes
an object myObject2 of class Y that includes method m().
The client can say myObject1.m() to access method m().This is bad practice since the definition of class Y, including method m() ,
may7 change with time.
It is better to design class X() including a delegating method say m1() which calls myObject2.m(). This way the client is shielded from changes.
of an object.
A quick tour of basic refactoring techniques
Message chainsSay you want to send a message to object D in class A but you have to go through B to get C and C to get D. --use hide delegate to hide C and D in B, and add a method to B that does what A wanted to do with D.
Inappropriate IntimacyDirectly getting in and messing about with the internals of another class. --To fix this, move methodsto consolidate the intimate bits.
A quick tour of basic refactoring techniques
CommentsComments in the middle of methods are “deodorant”. You should really refactor so each comment block is its own method. Do extract method.
Consolidate conditionals :
double disabilityAmount(){
if (_seniority < 2) return 0;
if (_monthsDisabled > 12)
return 0;
if (_isPartTime) return 0;
// compute the disability amount
double disabilityAmount(){
if (isNotEligableForDisability())
return 0;
// compute the disability amount
A quick tour of basic refactoring techniques
A quick tour of basic refactoring techniquesDecompose Conditionals :
When we have a complicated conditional (if-then-else) statement.
if (date.before (SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;else charge = quantity * _summerRate;if (notSummer(date))
charge = winterCharge(quantity);else charge = summerCharge (quantity);
Idea: Extract condition into its own method. Extract the then part and else part into two methods.
A quick tour of basic refactoring techniques• Encapsulate Downcast :
When a method returns an object that needs to be downcasted by its callers.
Object lastReading() {return readings.lastElement();}
Reading lastReading() {return (Reading) readings.lastElement();}
If we know that the object returned by a method must be downcasted, do so inside the method.Idea: downcast the client should be downcasting as little as possible.(The availability of Generic classes in Java makes this refactoring less important than before)
A quick tour of basic refactoring techniques
• Extract Class :When we have one class doing the work that should be done by two.
• Inline Class :When a class isn't doing very much. (The opposite what
we just said!!)
A quick tour of basic refactoring techniques