aula 15 - bad smells
TRANSCRIPT
-
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.