Upload
anderson-dias
View
13
Download
0
Embed Size (px)
Citation preview
Bad Smells
Baldoino Fonseca [email protected]
Introduc7on
To learn common design problems so you can recognize them in your own code.
The most common design problems result from code that is: Duplicated
Unclear
Complicated
Duplicated Code
You have the same code structure in more than one
place
Duplicated Code
Similarity between two expressions in two methods of the same class
CapitalStrategy
+advisedLine(loan : Loan) : double
+termLoan(loan : Loan) : double
return loan.getUnusedPercentage()* loan.getCommitment()* dura7on(loan)* riskFactFor(loan); return loan.getCommitment()*
dura7on(loan)* riskFactFor(loan);
+dura7on(loan : Loan) : double
+riskFactFor(loan : Loan) : double Similarity = 75%
Duplicated Code Similarity between two expressions in subclasses
CapitalStrategy
+capital(loan : Loan) : double +dura7on(loan : Loan) : double +riskFactFor(loan : Loan) : double
CapitalStrategyAdvisedLine
+capital(loan : Loan) : double
CapitalStrategyTermLoan
+capital(loan : Loan) : double +dura7on(loan : Loan) : double
return loan.getUnusedPercentage()* loan.getCommitment()* dura7on(loan)* riskFactFor(loan);
return loan.getCommitment()* dura7on(loan)* riskFactFor(loan);
Similarity = 75%
Duplicated Code Similarity between codes in two unrelated classes
Person
name areaCode number
getTelephoneNumber
Company
cnpj oceAreaCode oceNumber
getTelephoneNumber
Similarity = 66%
Duplicated Code public class Loan { public Loan(oat no7onal, oat outstanding, int ra7ng, Date expiry){ this.strategy = new TermROC(); this.no7onal = no7onal; this.outstanding = outstanding; this.ra7ng = ra7ng; this.expiry = expiry; } public Loan(oat no7onal, oat outstanding, int ra7ng, Date expiry, Date maturity){ this.strategy = new RevolvingTermROC(); this.no7onal = no7onal; this.outstanding = outstanding; this.ra7ng = ra7ng; this.expiry = expiry; this.maturity = maturity; } public Loan(CapitalStrategy strategy, oat outstanding, int ra7ng, Date expiry, Date maturity){ this.strategy = strategy; this.no7onal = no7onal; this.outstanding = outstanding; this.ra7ng = ra7ng; this.expiry = expiry; this.maturity = maturity; }
80%
67%
67%
Duplicated Code Similarity among the condi7onal logic applied throughout
the system to deal with a null object
MouseEventHandler
+mouseDown() : boolean +mouseMove() : boolean
MainMenuApplet
+mouseDown() : boolean +mouseMove() : boolean
Naviga7onApplet
+mouseDown() : boolean +mouseMove() : boolean
If (mouseEventHandler != null) return mouseEventHandler.mouseMove(); return true; If (mouseEventHandler != null) return mouseEventHandler.mouseMove(); return true;
100%
Long Parameter List
To pass in as parameters everything needed by a rou7ne
Long Method The size of the parameter list
analyze(start : String, end : String, startTime : int, endTime, amount, data: Type) : void
5 args
Long Method When an object invokes a method, then passes
the result as a parameter for a method
Int basePrice = _quan7ty * _itemPrice; discountLevel = getDiscountLevel(); Double nalPrice = discountPrice ( basePrice, discountLevel);
1 result
Long Method You are geEng several values from an object and
passing these values as parameters in a method call
Int low = range.getLow(); Int high = range.getHigh(); withinPlan = plan.withinRange(low, high);
2 values
Long Method You have a group of parameters that naturally
go together - Data Clumps
Customer
amountInvoiceIn(start:Date, end:Date) amountReceivedIn(start:Date, end:Date)
amountOverdueIn(start:Date, end:Date)
2 parameters 3 places
Long Method
A method is trying to do too much
Long Method You have many temporary variables
Vegeta7on vegeta7on = new Vegeta7on( ); Slope slope = new Slope( ); Rain = new Rain( ); Soil = new Soil( ); Occupa7on occupa7on = new Occupa7on( ); Region region = new Region( );
Analyze
apply( ) : Strategy
6 temps
Long Method
The amount of switch statement for dispatching and handling request
CatalogApp
If ( ac7onName.equals(NEW_WORKSHOP){ //lots of code to create a new workshop } else if (ac7onName.equals(ALL_WORKSHOPS) { //lots of code to display informa7on about all workshops } many more else if statements
2 ifs 2 requests
Long Method The amount of switch statement to gather data from numerous
classes with dierent interfaces
Node
StringBuer results = new StringBuer(); NodeIterator nodes = parser.elements(); while(nodes.hasMoreNodes()){
Node node = nodes.nextNode(); if(node instanceof StringNode){ add contents to results }else if(node instanceof LinkTag){ add contents to results }else if(node instanceof Tag){ add contents to results }else if }
} return retults.toString();
LinkTag
Tag
StringNode
TextExtractor
+extractText( ) : String
4 ifs 4 gather data
Long Method The amount of versions of an algorithm and condiIonal
logical to choose which version to use at runIme capital(){ if(expiry == null && maturity != null) return commitment*dura7on()*riskFactor(); if(expiry == null && maturity == null){ if(getUnusedPercentage() != 1.0) return commitment*getUnusedPercentage()* dura7on()*riskFactor(); else return (outstandingRiskAmount()*dura7on()*riskFactor() + (unusedRiskAmount()*dura7on()*unusedRiskFactor()); } return 0.0; }
Loan
+capital( ) : double 4 ifs
3 strategy
Long Method You have a single bulky method that accumulates informaIon to
a local variable
String result = new String(); result += ; Iterator it = children.iterator(); while(it.hasNext()){ TagNode node = (TagNode)it.next(); result += node.toString(); } If(! tagValue.equals( )) result+= tagValue; result+= ; return result;
TagNode
toString( ) : String
9 lines
Large Class
A class is trying to do too much
Large Class Fields and Methods
Home dvd: DVD cd: CD
watchMovie() : void
tv: TV
tuner: Tuner light: Light
temperature: Temperature projector: Projector
endMovie() : void listenToCd() : void endCd() : void listenToRadio() : void endRadio() : void
7 lines
6 lines
Large Class The condiIonal expressions that control an objects state
transiIons are complex.
If ( state != REQUESTED && state != UNIX_REQUESTED)
return; willBeHandledBy(admin); If ( state == REQUESTED)
state = CLAIMED; else if (state == UNIX_REQUESTED)
state = UNIX_CLAIMED;
SystemPermission
state: String REQUESTED : String
claimedBy() : void
CLAMED: String
GRANTED: String DENIED: String
UNIX_REQUESTED: String UNIX_CLAIMED: String
grantedBy() : void deniedBy() : void
4 Verica7ons
Large Class Numerous methods on a class combine elements of an
implicit language
List nonWhiteProductsBelowNineDollars = productFinder.belowPriceAvoidingAColor(9.00f, Color.white);
SystemPermission
byColor() : List byPrice() : List
bySize() : List
belowPriceAvoidingAColor() : List byColorAndBelowPrice() : List
byColorSizeAndBelowPrice() : List
Client
6 lines
Divergent Change On class is commonly changed in dierent ways for dierent reasons.
Home
watchMovie() : void endMovie() : void
listenToCd() : void
endCd() : void listenToRadio() : void endRadio() : void
onProjector() : void
oProjector() : void
8 methods 8 concerns
Shotgun Surgery When every 7me you make a kind of change, you have to make a lot of Liule changes to a lot of dierent classes
Movie Cd DVD Radio Projector
Media
Feature Envy A method that seems more interested in a class other than the one it actually is in.
Media
descrip7on: String gender : String
mediaDescrip7on() : String
Contact
email: String prex: String
getEmail() : String
areacode: String
number: String webpage: String
getPrex() : String getAreaCode() : String
getNumber() : String
getWebpage() : String
return descrip7on + gender + getEmail() + getPrex() + getAreaCode() + getNumber() + getWebpage();
6 interests
2 auributes
Primi7ve Obsession
It occurs when the designer uses primi7ve data types to represent domain ideas
Primi7ve Obsession You have an array in which certain elements
mean dierent things
String[] row = new String[3]; row[0] = Liverpool; row[1] = 15;
2 dierent auributes
Primi7ve Obsession The primiIve value controls logic in a class and
the primiIve value isnt type-safe SystemPermission
state: String REQUESTED : String
claimedBy() : void
CLAMED: String
GRANTED: String DENIED: String
UNIX_REQUESTED: String UNIX_CLAIMED: String
grantedBy() : void deniedBy() : void
public nal sta7c String REQUESTED = REQUESTED;
If(state.equals(REQUESTED))
state = CLAIMED;
7 Primi7ve Types
Primi7ve Obsession You have a data item that needs addiIonal data or behavior.
Order
customer : String
Primi7ve Obsession You have an immutable type code that aects
the behavior of a class.
Order
ENGINEER : int
SALESMAN: int
type: int
Lazy Class A class that is not doing enough to pay for itself.
Employee
Salesman
Only one subclass
Specula7ve Generality
I think we need the ability to this kind of thing someday.
Specula7ve Generality You have abstract classes that arent doing
much
Employee
Salesman
Only one subclass
Specula7ve Generality Methods with unused parameters
Customer
getContact(date:Date) 1 unused parameter
Specula7ve Generality The name of a method does not reveal its
purpose.
Customer
ge7nvcdtlmt
Message Chains The client is coupled to the structure of the navigaIon.
object.getE().getD().getC().getB().getA().getValue(); 6 chains
Middle Man
A class is doing too much simple delegaIon.
Middle Man If only a few methods arent doing much
int getRa7ng(){ return (moreThanFiveLateDeliveries()) ? 2 : 1; } Boolean moreThanFiveLateDeliveries(){ return _numberOfLateDeliveries > 5; }
1 line
Indecent Exposure
It occurs when methods or classes that ought not be visible to clients are publicity visible to
them.
Indecent Exposure Methods or classes that ought not to be visible
to clients are publicly visible to them
ARributeDescriptor
+AuributeDescriptor()
BooleanDescriptor
+BooleanDescriptor ()
DefaultDescriptor
+DefaultDescriptor ()
ReferenceDescriptor
+ReferenceDescriptor ()
Client
3 subclass
Data Class
These are classes that have elds, ge~ng and se~ng method for elds, and nothing else. In early stages these classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes.
Data Class Fields
Home
+ dvd: DVD + cd: CD
+ tv: TV
+ tuner: Tuner + light: Light
+ temperature: Temperature + projector: Projector
7 elds
Refused Bequest
Subclasses get to inherit the methods and data of their parents. But what if they dont want or need what they are given? They are given all these great gis and pick just a few to play with.
Comments
TIP: When you feel the need to write a comment, rst try to refactor the code so that any comment becomes superuous.