0% found this document useful (0 votes)
69 views100 pages

Refactoring: How To Improve Your Code

The document discusses refactoring code to improve its structure and readability without changing its external behavior. It defines refactoring as restructuring code internally to improve understandability and maintainability. Some goals of refactoring are to prevent quality degradation, improve clarity, help find bugs, and help programmers work faster. Common signs that code could benefit from refactoring include duplication, long methods/classes, long parameter lists, divergent changes, and comments used as deodorant. The document provides examples of various refactoring techniques such as extracting methods, moving methods/fields, introducing temporary variables, and replacing conditionals with polymorphism.

Uploaded by

Hammad Asghar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
69 views100 pages

Refactoring: How To Improve Your Code

The document discusses refactoring code to improve its structure and readability without changing its external behavior. It defines refactoring as restructuring code internally to improve understandability and maintainability. Some goals of refactoring are to prevent quality degradation, improve clarity, help find bugs, and help programmers work faster. Common signs that code could benefit from refactoring include duplication, long methods/classes, long parameter lists, divergent changes, and comments used as deodorant. The document provides examples of various refactoring techniques such as extracting methods, moving methods/fields, introducing temporary variables, and replacing conditionals with polymorphism.

Uploaded by

Hammad Asghar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 100

Refactoring

How to improve your code

ARTEM TABALIN
What is refactoring?
Definition. Goals. When to Refactor. Pitfalls.
What is Refactoring?

“Refactoring is a change made to the internal structure


of software to make it easier to understand and
cheaper to modify without changing its observable
behavior.”
- Martin Fowler

Is it just cleaning up code?

The technique of cleaning up code in more organized


and controlled way
The Two Hats

Two distinct activities

1.ꢀ adding functions


2.ꢀ refactoring

These two activities should NOT take place at the


same time
Goals

•ꢀ Prevent code quality reduction

•ꢀ Make code clear

•ꢀ Help to find bugs

•ꢀ Help to program faster


When to Refactor
The Rule of Three

Three strikes and you refactor

1.ꢀ You do something the first time

2.ꢀ You do similar thing again with regret

3.ꢀ On the third time – start refactoring


When to Refactor

•ꢀ When adding new functionality


•ꢀ understanding the code
•ꢀ prepare code for adding new functionality

•ꢀ When fixing a bug


•ꢀ error is a sign for refactoring

•ꢀ Code reviews
Problems with Refactoring

Database
•ꢀ difficult to change since tightly coupled to scheme
•ꢀ existing data migration

Changing Interface
•ꢀ deprecate old interface
•ꢀ just call new method in old method
•ꢀ don’t publish premature interfaces
When You Shouldn’t Refactor

Low code quality


•ꢀ easier rewrite than refactor
•ꢀ code should work correctly before refactoring

Deadline is too close


•ꢀ postpone refactoring = technical debt
Smelling Code
Signs of low quality code
Code Duplication

•ꢀ The same code in two methods


Extract Method

•ꢀ The same code in two subclasses


Extract Method + Pull Up Field / Method

•ꢀ The same code in two different classes


Extract Class
Long Method

•ꢀ Sections in method

•ꢀ Wish to comment part of code

•ꢀ Long loops and conditionals


Extract Method
Large Class

•ꢀ To many methods

•ꢀ To many fields
Extract Class / Extract Subclass
Long Parameter List

•ꢀ Method can calculate parameter itself


Replace Parameter with Method

•ꢀ Parameters are fields of single object


Preserve Whole Object

•ꢀ Several related parameters


Introduce Parameter Object
Divergent Change

•ꢀ Class is changed for different reasons


Extract Class
Shotgun Surgery

•ꢀ Lots of little changes to lot of different classes


Move Method / Move Field
Feature Envy

•ꢀ Method is interested in another class too much


Move Method [+ Extract Method]

Exceptions
•ꢀ Strategy
•ꢀ Visitor
•ꢀ Data Access Layer
Data Clumps

•ꢀ Few data items together in lots of places


Extract Class / Introduce Parameter Object
Primitive Obsession

•ꢀ Avoiding small classes and using primitives instead


range, money, phone, array instead of object

Replace Data Value with Object


Extract Class / Introduce Parameter Object
Switch Statements

•ꢀ Switch statements all over the class


Replace Type Code with Subclasses
Replace Conditional with Polymorphism


Speculative Generality

We need this functionality someday

•ꢀ Unnecessary base class


Collapse Hierarchy

•ꢀ Unnecessary delegation
Inline Class

•ꢀ Strange abstract method name


Rename Method
Inappropriate Intimacy

Classes too coupled

•ꢀ Use fields and methods of each other


Change Bidirectional Association with Unidirectional

•ꢀ Have common interests


Extract Class

•ꢀ High coupling due to inheritance


Replace Inheritance with Delegation
Other Smells

•ꢀ Lazy Class
Inline Class

•ꢀ Temporary Field
Extract Class

•ꢀ Message Chains getThis().getThat().getObject().method()


Hide Delegate

•ꢀ Refused Bequest
Replace Inheritance with Delegation
Comments
Used like a deodorant

Indicators of bad code

If you need a comment try to refactor


•ꢀ Extract Method
•ꢀ Rename Method
•ꢀ Introduce Assertion
Catalog of Refactorings
Composing Methods
Extract Method. Inline Method. Temporary Variables.
Replace Method with Method Object.
Extract Method
Turn the fragment of code into a method

When
•ꢀ Method is too long
•ꢀ Code needs an explanatory comment

Why
•ꢀ Increase reusability
•ꢀ Higher level methods become more readable
•ꢀ Easier to override
Extract Method
publicꢀvoidꢀPrintClient(Clientꢀclient)ꢀ{ꢀ
ꢀꢀꢀꢀPrintBanner();ꢀ
ꢀꢀꢀꢀ//ꢀprintꢀclientꢀdetailsꢀ
ꢀꢀꢀꢀConsole.Write("Name:ꢀ"ꢀ+ꢀclient.Name);ꢀ
ꢀꢀꢀꢀConsole.Write("Address:ꢀ"ꢀ+ꢀclient.Address);ꢀ
}ꢀ

publicꢀvoidꢀPrintClient(Clientꢀclient)ꢀ{ꢀ
ꢀꢀꢀꢀPrintBanner();ꢀ
ꢀꢀꢀꢀPrintClientDetails(client);ꢀ
}ꢀ

privateꢀvoidꢀPrintClientDetails(Clientꢀclient)ꢀ{ꢀ
ꢀꢀꢀꢀConsole.Write("Name:ꢀ"ꢀ+ꢀclient.Name);ꢀ
ꢀꢀꢀꢀConsole.Write("Address:ꢀ"ꢀ+ꢀclient.Address);ꢀ
}ꢀ
Inline Method
Put the method body to callers and remove it

When
•ꢀ Method body is as clear as its name
•ꢀ Calling method is badly factored

Why
•ꢀ Reduce redundant delegation
•ꢀ Restructure calling method
Inline Method

publicꢀintꢀGetRating()ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀMoreThanFiveLateDeliveries()ꢀ?ꢀ2ꢀ:ꢀ1;ꢀ
}ꢀ

privateꢀboolꢀMoreThanFiveLateDeliveries()ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ_numberOfLateDeliveriesꢀ>ꢀ5;ꢀ
}ꢀ

publicꢀintꢀGetRating()ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ(_numberOfLateDeliveriesꢀ>ꢀ5)ꢀ?ꢀ2ꢀ:ꢀ1;ꢀ
}ꢀ
Replace Temp with Query
Extract expression to a method and replace temp

When
•ꢀ Temp holds an expression result for other methods
•ꢀ Temp prevents from another refactoring

Why
•ꢀ Cleaner code
•ꢀ Shorter method
•ꢀ The result is available to all methods
Replace Temp with Query
publicꢀdoubleꢀGetPrice()ꢀ{ꢀ
ꢀꢀꢀꢀdoubleꢀbasePriceꢀ=ꢀ_quantityꢀ*ꢀ_itemPrice;ꢀ

ꢀꢀꢀꢀreturnꢀ(basePriceꢀ>ꢀ1000)ꢀꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀ?ꢀbasePriceꢀ*ꢀ0.95ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀ:ꢀbasePriceꢀ*ꢀ0.98;ꢀ
}ꢀ

publicꢀdoubleꢀGetPrice()ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ(BasePriceꢀ>ꢀ1000)ꢀꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀ?ꢀBasePriceꢀ*ꢀ0.95ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀ:ꢀBasePriceꢀ*ꢀ0.98;ꢀ
}ꢀ

privateꢀdoubleꢀBasePriceꢀ{ꢀ
ꢀꢀꢀꢀgetꢀ{ꢀreturnꢀ_quantityꢀ*ꢀ_itemPrice;ꢀ}ꢀ
}ꢀ
Introduce Explaining Variable
Assign a part of expression to explaining variable

When
•ꢀ Complex condition
•ꢀ Complex algorithm

Why
•ꢀ Improve code readability
Introduce Explaining Variable
ifꢀ((platform.toUpperCase().indexOf("MAC")ꢀ>ꢀ-1)ꢀ&&ꢀ
ꢀꢀꢀꢀ(browser.toUpperCase().indexOf("IE")ꢀ>ꢀ-1)ꢀ&&ꢀ
ꢀꢀꢀꢀisInitialized()ꢀ&&ꢀresizeꢀ>ꢀ0)ꢀ{ꢀ
ꢀꢀꢀꢀ//ꢀdoꢀsomethingꢀ
}ꢀ

varꢀisMacꢀ=ꢀplatform.toUpperCase().indexOf("MAC")ꢀ>ꢀ-1;ꢀ
varꢀisIEBrowserꢀ=ꢀbrowser.toUpperCase().indexOf("IE")ꢀ>ꢀ-1;ꢀ
varꢀisResizedꢀ=ꢀresizeꢀ>ꢀ0;ꢀ
ifꢀ(isMacꢀ&&ꢀisIEBrowserꢀ&&ꢀisInitialized()ꢀ&&ꢀisResized){ꢀ
ꢀꢀꢀꢀ//ꢀdoꢀsomethingꢀ
}ꢀ
Replace Method with Method Object

Transform long method into object

When
•ꢀ Long method with lots of temp variables

Why
•ꢀ Improve readability
•ꢀ Increase reusability
Replace Method with Method Object
classꢀTransactionꢀ{ꢀ
ꢀꢀꢀꢀpublicꢀdoubleꢀBankFee()ꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀdoubleꢀamount;ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀdoubleꢀprice;ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀdoubleꢀtax;ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀ//ꢀlongꢀcomputationsꢀ
ꢀꢀꢀꢀ}ꢀ

BankFeeCalculator
Transaction -amount
1 -price
+BankFee() -tax
+Compute()

return new BankFeeCalculator(this).Compute();


Moving Features Between Objects
Move Method. Move Field. Extract Class. Inline Class.
Hide Delegation.
Move Method
Move the method to the class that uses it most

When
•ꢀ Method references another object too much
•ꢀ Two classes are too coupled
•ꢀ Class is overcomplicated

Why
•ꢀ Lower coupling
•ꢀ Simplify design
Move Method
classꢀAccountꢀ{ꢀ classꢀAccountꢀ{ꢀ
ꢀꢀprivateꢀAccountTypeꢀ_type;ꢀ ꢀꢀpublicꢀdoubleꢀBankCharge()ꢀ{ꢀ
ꢀꢀpublicꢀdoubleꢀBankCharge()ꢀ{ꢀ ꢀꢀꢀꢀdoubleꢀresultꢀ=ꢀFIXED_FEE;ꢀ
ꢀꢀꢀꢀdoubleꢀresultꢀ=ꢀFIXED_FEE;ꢀ ꢀꢀꢀꢀif(HasOverdraft())ꢀ
ꢀꢀꢀꢀif(HasOverdraft())ꢀ ꢀꢀꢀꢀꢀꢀresultꢀ+=ꢀ_type.OverdraftFee();ꢀ
ꢀꢀꢀꢀꢀꢀresultꢀ+=ꢀOverdraftFee();ꢀ ꢀꢀꢀꢀreturnꢀresult;ꢀ
ꢀꢀꢀꢀreturnꢀresult;ꢀ ꢀꢀ}ꢀ
ꢀꢀ}ꢀ
classꢀAccountTypeꢀ{ꢀ
ꢀꢀprivateꢀdoubleꢀOverdraftFee()ꢀ{ꢀ
ꢀꢀpublicꢀdoubleꢀOverdraftFee()ꢀ{ꢀ
ꢀꢀꢀꢀif(_type.IsPremium())ꢀ{ꢀ
ꢀꢀꢀꢀif(IsPremium())ꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀ//ꢀpremiumꢀaccountꢀ
ꢀꢀꢀꢀꢀꢀ//ꢀpremiumꢀaccountꢀ
ꢀꢀꢀꢀ}ꢀelseꢀ{ꢀ
ꢀꢀꢀꢀ}ꢀelseꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀ//ꢀstandardꢀaccountꢀ
ꢀꢀꢀꢀꢀꢀ//ꢀstandardꢀaccountꢀ
ꢀꢀꢀꢀ}ꢀ
ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ
ꢀ ꢀꢀ}ꢀ
Move Field
Move the field to class that uses it most

When
•ꢀ Another class uses a field more than its owner
•ꢀ Performing Extract Class refactoring

Why
•ꢀ Lower coupling
•ꢀ Simplify design
Move Field
ꢀ ꢀ
classꢀAccountꢀ{ꢀ classꢀAccountꢀ{ꢀ

ꢀꢀprivateꢀAccountTypeꢀ_type;ꢀ ꢀꢀdoubleꢀInterest(intꢀdays)ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ_type.InterestRateꢀ*ꢀdays/365;ꢀ
ꢀꢀprivateꢀdoubleꢀ_interestRate;ꢀ ꢀꢀ}ꢀ
ꢀꢀpublicꢀdoubleꢀInterestRateꢀ{ꢀ
ꢀꢀꢀꢀgetꢀ{ꢀreturnꢀ_interestRate;ꢀ}ꢀ classꢀAccountTypeꢀ{ꢀ
ꢀꢀ}ꢀ ꢀꢀprivateꢀdoubleꢀ_interestRate;ꢀ
ꢀꢀdoubleꢀInterest(intꢀdays)ꢀ{ꢀ ꢀꢀpublicꢀdoubleꢀInterestRateꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀInterestRateꢀ*ꢀdays/365;ꢀ ꢀꢀꢀꢀgetꢀ{ꢀreturnꢀ_interestRate;ꢀ}ꢀ
ꢀꢀ}ꢀ ꢀꢀ}ꢀ

Extract Class
Create new class and move fields and methods

When
•ꢀ Class is too big
•ꢀ Single Responsibility Principle violation
•ꢀ Data or methods dependent on each other

Why
•ꢀ Simplify design
Extract Class
Person
-name
-officeAreaCode
-officeNumber

+OfficePhone()

Person PhoneNumber
-officePhone
areaCode
-name
-number
+OfficePhone()
+Phone()
Inline Class
Move fields & methods from class and remove it

When
•ꢀ Class is useless

Why
•ꢀ Simplify design
Inline Class

Person PhoneNumber
-phone
-areaCode
-name
-number
+Phone()
+Phone()

Person
-name
-areaCode
-number

+Phone()
Hide Delegate
Create method on the server to hide the delegate

When
•ꢀ object.getAnotherObject().method()

Why
•ꢀ Lower coupling
•ꢀ Strengthen encapsulation
Hide Delegate

Client
Client

Person
+Manager()
Person Department
+Department() +Manager()

Department
Organizing Data
Self Encapsulate Field. Replacing Value with Object.
Replace Magic Number with Constant.
Replace Type Code with Subclasses/State/Strategy.
Self Encapsulate Field
Create and use getter and setter to access field

When
•ꢀ Provide access to the field from outside
•ꢀ Override property in a child class

Why
•ꢀ Strengthen encapsulation
•ꢀ Higher flexibility
Self Encapsulate Field
privateꢀdoubleꢀ_interestRate;ꢀ

publicꢀdoubleꢀInterest(intꢀdays)ꢀ{ꢀ
ꢀꢀreturnꢀ_interestRateꢀ*ꢀdays/365;ꢀ
}ꢀ

privateꢀdoubleꢀ_interestRate;ꢀꢀꢀ

publicꢀdoubleꢀInterestRateꢀ{ꢀ
ꢀꢀgetꢀ{ꢀreturnꢀ_interestRate;ꢀ}ꢀ
ꢀꢀsetꢀ{ꢀ_interestRateꢀ=ꢀvalue;ꢀ}ꢀ
}ꢀ
publicꢀdoubleꢀInterest(intꢀdays)ꢀ{ꢀ
ꢀꢀreturnꢀInterestRateꢀ*ꢀdays/365;ꢀ
}ꢀꢀꢀ

Replace Data Value with Object
Turn the data item to an object

When
•ꢀ Data item has dedicated methods
•ꢀ Data items are used together in lots of places

Why
•ꢀ Higher flexibility
Replace Data Value with Object

Order
-customer: string

Customer
Order
-customer -name: string
Replace Magic Number with Constant

Replace magic value with named constant

When
•ꢀ There is a magic value in the code

Why
•ꢀ Improve code readability
Replace Magic Number with Constant

doubleꢀPotentialEnergy(doubleꢀmass,ꢀdoubleꢀheight)ꢀ{ꢀ
ꢀꢀreturnꢀmassꢀ*ꢀ9.81ꢀ*ꢀheight;ꢀ
}ꢀ

staticꢀconstꢀdoubleꢀGRAVITATIONAL_CONSTANTꢀ=ꢀ9.81;ꢀ

doubleꢀPotentialEnergy(doubleꢀmass,ꢀdoubleꢀheight)ꢀ{ꢀ
ꢀꢀreturnꢀmassꢀ*ꢀGRAVITATIONAL_CONSTANTꢀ*ꢀheight;ꢀ
}ꢀ


Replace Type Code with Subclasses

Replace the type code with subclasses

When
•ꢀ There is a type code influencing on class behavior

Why
•ꢀ Increase extensibility
Replace Type Code with Subclasses
classꢀEmployeeꢀ{ꢀ abstractꢀclassꢀEmployeeꢀ{ꢀ
ꢀꢀabstractꢀEmployeeTypeꢀTypeꢀ{ꢀget;ꢀ}ꢀ
ꢀꢀprivateꢀEmployeeTypeꢀ_type;ꢀ
ꢀꢀabstractꢀdoubleꢀBonusꢀ{ꢀget;ꢀ}ꢀ
ꢀꢀEmployee(EmployeeTypeꢀtype)ꢀ{ꢀ }ꢀ
ꢀꢀꢀꢀ_typeꢀ=ꢀtype;ꢀ
ꢀꢀ}ꢀ classꢀEngineer:ꢀEmployeeꢀ{ꢀ
ꢀꢀpublicꢀoverrideꢀEmployeeTypeꢀTypeꢀ{ꢀ
ꢀꢀpublicꢀdoubleꢀBonusꢀ{ꢀ
ꢀꢀꢀꢀgetꢀ{ꢀ ꢀꢀꢀꢀgetꢀ{ꢀꢀ
ꢀꢀꢀꢀꢀꢀreturnꢀEmployeeType.Engineer;ꢀꢀ
ꢀꢀꢀꢀꢀꢀswitch(_type)ꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀcaseꢀEmployeeType.Engineer:ꢀ ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀꢀꢀreturnꢀ0.0;ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀcaseꢀEmployeeType.Salesman:ꢀ ꢀꢀpublicꢀoverrideꢀdoubleꢀBonusꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀꢀꢀreturnꢀ0.25;ꢀ ꢀꢀꢀꢀgetꢀ{ꢀꢀ
ꢀꢀꢀꢀꢀꢀ}ꢀ ꢀꢀꢀꢀꢀꢀreturnꢀ0.0;ꢀꢀ
ꢀꢀꢀꢀ}ꢀ ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ ꢀꢀ}ꢀ
} }ꢀ
Replace Type Code with State/Strategy

Replace the type code with state/strategy classes

When
•ꢀ There is a type code influencing on class behavior
•ꢀ Type code may change during object life

Why
•ꢀ Increase extensibility
Replace Type Code with State/Strategy

<< enum >>


-type EmployeeType
Employee
Salesman
Engineer

-type
Employee EmployeeType

Salesman Engineer
Simplifying Conditional Expressions
Decompose Conditional Expression.
Replace Conditional with Polymorphism.
Guard Clauses.
Decompose Conditional
Extract methods from condition and branches

When
•ꢀ Condition with complex expression and branches

Why
•ꢀ Improve code readability
Decompose Conditional
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);ꢀ
Replace Nested Conditional with Guard Clauses

Use guard clauses for all special cases

When
•ꢀ Conditional expression with special case branch

Why
•ꢀ Improve code readability
Replace Nested Conditional with Guard Clauses

doubleꢀPayAmount()ꢀ{ꢀ doubleꢀPayAmount()ꢀ{ꢀ
ꢀꢀdoubleꢀresult;ꢀ
ꢀꢀif(_isDead)ꢀꢀ
ꢀꢀif(_isDead)ꢀ ꢀꢀꢀꢀreturnꢀDeadAmount();ꢀ
ꢀꢀꢀꢀresultꢀ=ꢀDeadAmount();ꢀ
ꢀꢀif(_isSeparated)ꢀꢀ
ꢀꢀelseꢀ{ꢀ
ꢀꢀꢀꢀif(_isSeparated)ꢀꢀ ꢀꢀꢀꢀreturnꢀSeparatedAmount();ꢀ
ꢀꢀꢀꢀꢀꢀresultꢀ=ꢀSeparatedAmount();ꢀ ꢀꢀif(_isRetired)ꢀꢀ
ꢀꢀꢀꢀelseꢀ{ꢀ ꢀꢀꢀꢀreturnꢀRetiredAmount();ꢀ
ꢀꢀꢀꢀꢀꢀif(_isRetired)ꢀꢀ ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀresultꢀ=ꢀRetiredAmount();ꢀ ꢀꢀreturnꢀNormalAmount();ꢀ
ꢀꢀꢀꢀꢀꢀelseꢀꢀ
}ꢀ
ꢀꢀꢀꢀꢀꢀꢀꢀresultꢀ=ꢀNormalAmount();ꢀ
ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ
ꢀꢀreturnꢀresult;ꢀ
}ꢀ

Replace Conditional with Polymorphism

Move every condition branch to subclass method

When
•ꢀ There are conditions depending on object type

Why
•ꢀ Increase extensibility
•ꢀ Improve code readability
Replace Conditional with Polymorphism
classꢀEmployeeꢀ{ꢀ
ꢀꢀpublicꢀdoubleꢀPayAmount()ꢀ{ꢀ
ꢀꢀꢀꢀswitchꢀ(_type)ꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀcaseꢀEmployeeType.Engineer:ꢀreturnꢀ_salary;ꢀ
ꢀꢀꢀꢀꢀꢀcaseꢀEmployeeType.Salesman:ꢀreturnꢀ_salaryꢀ+ꢀ_commission;ꢀ
ꢀꢀꢀꢀꢀꢀcaseꢀEmployeeType.Manager:ꢀreturnꢀ_salaryꢀ+ꢀ_bonus;ꢀ
ꢀꢀꢀꢀꢀꢀdefault:ꢀthrowꢀnewꢀWrongEmployeeTypeException();ꢀꢀ
ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ

Employee
+PayAmount()

Engineer Salesman Manager


+PayAmount() +PayAmount() +PayAmount()
Making Method Calls Simpler
Rename Method. Separate Query from Modifier.
Preserve Whole Object. Introduce Parameter Object.
Error Handling Refactorings.
Rename Method
Change method name

When
•ꢀ Method name doesn't show its intention

Why
•ꢀ Improve code readability
Rename Method

SecurityPrice
+LowerLimitExceed()

SecurityPrice
+IsLowerLimitExceeded()
Separate Query from Modifier
Create methods for query and for modification

When
•ꢀ Method returning value modifies object state

Why
•ꢀ Simplify interface
Separate Query from Modifier
publicꢀList<Employee>ꢀFindRetired(List<Employee>ꢀemployees)ꢀ{ꢀ
ꢀꢀvarꢀresultꢀ=ꢀnewꢀList<Employee>();ꢀ
ꢀꢀforeach(varꢀempꢀinꢀemployees)ꢀ{ꢀ
ꢀꢀꢀꢀif(emp.IsRetired)ꢀ{ꢀ
ꢀꢀꢀꢀꢀꢀAddBonus(emp);ꢀ
ꢀꢀꢀꢀꢀꢀresult.Add(emp);ꢀ
ꢀꢀꢀꢀ}ꢀ
ꢀꢀ}ꢀ
ꢀꢀreturnꢀresult;ꢀ
}ꢀ

publicꢀList<Employee>ꢀFindRetired(List<Employee>ꢀemployees)ꢀ{ꢀ
ꢀꢀreturnꢀemployees.Where(empꢀ=>ꢀemp.IsRetired).ToList();ꢀꢀꢀ
}ꢀ
publicꢀvoidꢀAddBonusToRetired(List<Employee>ꢀemployees)ꢀ{ꢀ
ꢀꢀforeach(varꢀempꢀinꢀemployees)ꢀ{ꢀ
ꢀꢀꢀꢀif(emp.IsRetired)ꢀ
ꢀꢀꢀꢀꢀꢀAddBonus(emp);ꢀ
ꢀꢀ}ꢀ
}ꢀ

Preserve Whole Object
Send the whole object to the method

When
•ꢀ Method has several object field values as params

Why
•ꢀ Simplify interface
Preserve Whole Object
DateTimeꢀstartꢀ=ꢀPeriod.Start;ꢀ
DateTimeꢀendꢀ=ꢀPeriod.End;ꢀ
List<Event>ꢀeventsꢀ=ꢀschedule.FindEvents(start,ꢀend);ꢀ



List<Event>ꢀeventsꢀ=ꢀschedule.FindEvents(Period);ꢀ
Introduce Parameter Object
Replace method parameters with an object

When
•ꢀ Method accepts several related parameters

Why
•ꢀ Simplify interface
Introduce Parameter Object

Schedule
+FindEvents(DateTime start, DateTime end)

Schedule
+FindEvents(Period period)
Replace Error Code with Exception
Throw exception instead of returning error code

When
•ꢀ Method returns error code

Why
•ꢀ Simplify interface
Replace Error Code with Exception
intꢀWithdraw(intꢀamount)ꢀ{ꢀ voidꢀWithdraw(intꢀamount)ꢀ{ꢀ
ꢀꢀifꢀ(amountꢀ>ꢀ_balance)ꢀ{ꢀ ꢀꢀifꢀ(amountꢀ>ꢀ_balance)ꢀꢀ
ꢀꢀꢀꢀreturnꢀ-1;ꢀ ꢀꢀꢀꢀthrowꢀnewꢀBalanceException();ꢀ
ꢀꢀ}ꢀ ꢀ
ꢀꢀelseꢀ{ꢀ ꢀꢀ_balanceꢀ-=ꢀamount;ꢀ
ꢀꢀꢀꢀ_balanceꢀ-=ꢀamount;ꢀ }ꢀ
ꢀꢀꢀꢀreturnꢀ0;ꢀ
ꢀꢀ}ꢀ
}ꢀ
Replace Exception with Test
Put conditional instead of throwing exception

When
•ꢀ Exception is used non-exceptional case

Why
•ꢀ Improve code readability
Replace Exception with Test
publicꢀdoubleꢀValueForPeriod(intꢀperiodIndex)ꢀ{ꢀ
ꢀꢀtryꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ_values[periodIndex];ꢀ
ꢀꢀ}ꢀ
ꢀꢀcatchꢀ(IndexOutOfRangeExceptionꢀe)ꢀ{ꢀ
ꢀꢀꢀꢀreturnꢀ0;ꢀ
ꢀꢀ}ꢀ
}ꢀ

publicꢀdoubleꢀValueForPeriod(intꢀperiodIndex)ꢀ{ꢀ
ꢀꢀifꢀ(periodIndexꢀ>=ꢀ_values.length)ꢀꢀ
ꢀreturnꢀ0;ꢀ
ꢀꢀreturnꢀ_values[periodIndex];ꢀ
}ꢀ
Generalization Refactorings
Pull Up and Push Down Method/Field.
Replace Inheritance with Delegation.
Extract Subclass/Superclass.
Pull Up Field/Method
Move method/field into the superclass

When
•ꢀ The same method/field is in several child classes

Why
•ꢀ Remove duplication
Pull Up Field/Method
Employee

Salesman Engineer
+name +name

Employee
+name

Salesman Engineer
Push Down Field/Method
Move method/field into the subclass

When
•ꢀ Superclass has method/field used only in one child

Why
•ꢀ Simplify design
Push Down Field/Method
Employee
+ComissionRate

Salesman Engineer

Employee

Salesman Engineer
+ComissionRate
Extract Subclass
Create subclass for subset of features

When
•ꢀ Subset of features used only in some instances

Why
•ꢀ Improve code readability
Extract Subclass

Event
+Start: DateTime
+Duration: TimeSpan
Event
+Start: DateTime
+Duration: TimeSpan
+Repeat: EventPeriodicity

PeriodicEvent
+Repeat: EventPeriodicity
Extract Superclass
Create superclass and move common features

When
•ꢀ Several classes have the same subset of features

Why
•ꢀ Remove duplication
Extract Superclass

AccountTransaction Transaction

+Change: decimal +Change: decimal


+Saldo: decimal +TradeDate: DateTime
+TradeDate: DateTime

Order
+Amount: int Order AccountTransaction
+Price: decimal
+Change: decimal +Amount: int +Saldo: decimal
+Security: Security +Price: decimal
+TradeDate: DateTime +Security: Security
Replace Inheritance with Delegation
Put superclass to a field and use delegation

When
•ꢀ Unable to say “subclass is a superclass”
•ꢀ Subclass implements superclass interface partially

Why
•ꢀ Simplify design
Replace Inheritance with Delegation

Array Array
+Insert(T item) +Insert(T item)
+IsEmpty() +IsEmpty()

-array

Stack Stack
+Push(T Item) +Push(T Item)
+Pop(): T +Pop(): T
+IsEmpty()

return _array.IsEmpty();
Architectural Refactorings
Tease Apart Hierarchies. Extract Hierarchy.
Convert Procedural Design to Objects.
Separate Domain from Presentation.
Tease Apart Inheritance
Create two hierarchies using one another

When
•ꢀ The inheritance hierarchy has two responsibilities

Why
•ꢀ Simplify design
Tease Apart Inheritance
*
Security
Security

Action Bond

Action Bond 1
SecurityOperation

SoldAction DeliveredBond
Delivery Selling
Extract Hierarchy
Create hierarchy with subclass per special case

When
•ꢀ The single class overwhelmed with conditionals

Why
•ꢀ Improve code readability
•ꢀ Improve architecture
Extract Hierarchy
Logger

+SendEmail(message)
+WriteToFile(message)
+WriteToSystemLog(message)

Logger

SystemLogger FileLogger EmailLogger


Convert Procedural Design to Objects

Turn data into objects and behavior into methods

When
•ꢀ The classes with long methods but without fields
•ꢀ The classes with fields but without methods

Why
•ꢀ Improve code readability
•ꢀ Improve architecture
Convert Procedural Design to Objects

OrderCalculator
OrderLine Order
+CalculatePrice(order)
+CalculateTaxes(order)

Order OrderLine
+Price() 1 * +Price()
+Taxes() +Taxes()
Separate Domain from Presentation
Create domain logic classes separated from ui

When
•ꢀ UI logic is mixed with domain logic

Why
•ꢀ Improve code readability
•ꢀ Improve architecture
Separate Domain from Presentation

ClientPage
(business logic embedded)

1
ClientPage Client
Thank you!

Your questions, please!


ARTEM TABALIN
References

•ꢀ Martin Fowler Refactoring

•ꢀ Robert C. Martin Clean Code

•ꢀ Steve McConnell Code Complete!

You might also like