SOEN6461: Software Design Methodologies
Zeinab (Azadeh) Kermansaravi, Diana El-Masri Smells: Anti-patterns, code smells
Contributions: Yann-Gaël Guéhéneuc, Foutse Khomh, Fàbio Petrillo, Zéphryin Soh and Naouel Moha
1
SOEN6461: Software Design Methodologies Zeinab (Azadeh) - - PowerPoint PPT Presentation
SOEN6461: Software Design Methodologies Zeinab (Azadeh) Kermansaravi, Diana El-Masri Smells: Anti-patterns, code smells Contributions: Yann-Gal Guhneuc, Foutse Khomh, Fbio Petrillo, Zphryin Soh and Naouel Moha 1 Quality Evolution
Zeinab (Azadeh) Kermansaravi, Diana El-Masri Smells: Anti-patterns, code smells
Contributions: Yann-Gaël Guéhéneuc, Foutse Khomh, Fàbio Petrillo, Zéphryin Soh and Naouel Moha
1
Code Smells Design patterns
Name conventions
Design Smells Lexical Smells, … Evolution Development Team Quality
2
“qual·i·ty noun \ˈkwä-lə-tē\
has: something that can be noticed as a part of a person or thing
—Merriam-Webster, 2013
3
In the context of software engineering, software quality measures how well software is designed (quality of design), and how well the software conforms to that design (quality
4
9126:2001, 25000:2005…
http://www.sqa.net/iso9126.html
5
9126:2001, 25000:2005…
http://www.sqa.net/iso9126.html
6
7
http://romainvv.ddns.net/iso-25010/
Code Smells Design patterns
Name conventions
Design Smells Lexical Smells, … Evolution Development Team Quality
8
9
Development team may implement software features with poor design, or bad coding…
Poor coding decisions
Poor practice in the naming, documentation, … in the implementation of an entity.
Poor design solutions to recurring design problems
recurring design and implementation problems.
evolution and maintenance activities.
development process, to reduce the maintenance costs.
William H. Brown, 1998
10
11
12
13
code
14
cohesion*
architectures.
*How closely the methods are related to the instance variables in the class.
Measure: LCOM (Lack of cohesion metric)
15
https://www.slideshare.net/Ptidej/cascon06-tooldemoppt
16
17
http://antipatterns.com/briefing/sld025.htm
Refactoring…
18
http://antipatterns.com/briefing/sld026.htm
Refactoring…
19
http://antipatterns.com/briefing/sld027.htm
Refactoring…
20
http://antipatterns.com/briefing/sld028.htm
Refactored
21
http://antipatterns.com/briefing/sld029.htm
22
23
http://joostdevblog.blogspot.ca/2012/05/programming-with-pasta.html
24
parameters
reuse, no polymorphism
no parameters and low cohesion
programing
https://www.slideshare.net/Ptidej/cascon06-tooldemoppt
25
predictable.
is not used to extend the system; polymorphism is not used.
contribute to the problem.
26
27
https://www.slideshare.net/ygerasimov/clean-code-and-refactoring
Refactoring…
28
29
public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] if (x[0] x : theList) == 4) list1.add(x); return list1; }
This code is quite simple but what does it do?
30 https://www.slideshare.net/mariosangiorgio/clean-code-and-code-smells (slide30-46)
public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] if (x[0] x : theList) == 4) list1.add(x); return list1; }
This code is quite simple but what does it do? Looking at it we can’t tell what it is actually doing!
31
public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] cell : if gameBoard) (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(x); return flaggedCells; }
Is this code any better?
32
public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(x); return flaggedCells; }
What about this?
33
What we have done: used intention revealing names
flaggedCells
rather than list1
34
What we have done: used intention revealing names replaced magic numbers with constants
flaggedCells
rather than list1
cell[STATUS_VALUE]
rather than x[0]
35
What we have done: used intention revealing names replaced magic numbers with constants created an appropriate abstract data type
flaggedCells
rather than list1
cell[STATUS_VALUE]
rather than x[0]
Cell cell rather than int[] cell
36
more flexible thanks to use of objects instead of primitives int[ ]. Better understandability and organization of code.
Operations on particular data are in the same place, instead of being scattered.
No more guessing about the reason for all these strange constants and why they are in an array.
37
int d;
What does it mean? Days? Diameter? ...
38
int d;
What does it mean? Days? Diameter? ...
int d; //elapsed time in days
Is this any better?
39
int d;
What does it mean? Days? Diameter? .. .
int d; //elapsed time in days
Is this any better?
int elapsedTimeInDays;
What about this?
40
public bool isEdible() { if (this.ExpirationDate > Date.Now && this.ApprovedForConsumption == true && this.InspectorId != null) { return true; } else { return false; } }
How many things is the function doing?
41
public bool isEdible() { if (this.ExpirationDate > Date.Now && this.ApprovedForConsumption == true && this.InspectorId != null) { return true; } else { return false; } }
Can we implement it better?
42
public bool isEdible() { return isFresh() && isApproved() && isInspected(); }
Now the function is doing one thing! Easier to understand (shorter method) A change in the specifications turns into a single change in the code!
Long Method example (~1622 LOC)
https://github.com/dianaelmasri/FreeCadMod/blob/master/Gui/ViewProviderSketch.cpp
Is this any better? Why?
43
public void bar(){ foo(“A”); foo(“B”); foo(“C”); }
Is this a good practice?
44
DO NOT EVER COPYAND P ASTE CODE
public void bar(){ foo(“A”); foo(“B”); foo(“C”); } public void bar(){ String [] elements = {“A”, “B”, “C”}; for(String element : elements){ foo(element); } }
Now logic to handle the elements is written once for all
45
46
somewhere in your code. Use the smell to track down the problem.
choices [Martin Fowler]
http://wiki.c2.com/?CodeSmell
47
48
What we don’t want to see in your code
49
https://github.com/dianaelmasri/FreeCadMod/blob/master/Gui/ViewProviderSketch.cpp
Bloaters are code, methods and classes that have increased to such gargantuan proportions that they are hard to work with.
https://sourcemaking.com/refactoring/smells
Single responsibility principle violated Symptoms of Bad Design
50
public Class Car{ private int public void red, green, blue; paint(int red, int green, int blue){ this.red this.green this.blue = red; = green; = blue; } } public Class Car{ private Color color; public void paint(Color this.color = color; color){ } }
51 https://www.slideshare.net/mariosangiorgio/clean-code-and-code-smells
bool SubmitCreditCardOrder (string creditCardNumber, int expirationMonth, int expirationYear, double saleAmount) { } bool Isvalid (string creditCardNumber, int expirationMonth, int expirationYear) { } bool Refund(string creditCardNumber, int expirationMonth, int expirationYear, double Amount) { }
52
bool SubmitCreditCardOrder (string creditCardNumber, int expirationMonth, int expirationYear, double saleAmount) { } bool Isvalid (string creditCardNumber, int expirationMonth, int expirationYear) { } bool Refund(string creditCardNumber, int expirationMonth, int expirationYear, double Amount) { }
class CreditCard { private: string creditCardNumber;, int expirationMonth; int expirationYear; }; bool SubmitCreditCardOrder ( CreditCard card, double saleAmount) { } bool Isvalid (CreditCard card) { } bool Refund(CreditCard card , double Amount) { }
53
Problem: Hard to understand , change, and reuse
54
55
https://sourcemaking.com/refactoring/smells/long-parameter-list
56
primitives.
Operations on particular data are in the same place, instead of being scattered.
strange constants and why they are in an array.
57
Different Interfaces
All these smells are incomplete or incorrect application
programming principles.
https://sourcemaking.com/refactoring/smells
Poor class hierarchy Should use Polymorphism
58
improve it?
class Animal { int MAMMAL = 0, BIRD = 1, REPTILE = 2; int myKind; // set in constructor ... string getSkin() { switch (myKind) { case MAMMAL: return "hair"; case BIRD: return "feathers"; case REPTILE: return "scales"; default: return "integument"; } } }
59
http://slideplayer.com/slide/7833453/ slides 59 to 62
60
Bad Implementation because
various kinds of object
“Food:?
class Animal { string getSkin() { return "integument"; } } class Mammal extends Animal { string getSkin() { return "hair"; } } class Bird extends Animal { string getSkin() { return "feathers"; } } class Reptile extends Animal { string getSkin() { return "scales"; } }
61
ways : class ”housing” or class “food”
more switch statements we’re now using Objects as they were meant to be used
62
Subclass doesn’t use superclass methods and attributes
public abstract class Employee{ int quota; int getQuota(); private public ... } public class Salesman extends Employee{ ... } public ... class Engineer extends Employee{ public int getQuota(){ throw new NotSupportedException(); } }
Engineer does not use quota. It should be pushed down to Salesman
63
Inheritance (is a …). Does it make sense?? Delegation (has a…)
64
65
How this is an improvement?
was implemented only to combine common code but not because the subclass is an extension of the superclass.
superclass.
to call.
66
Something pointless and unneeded whose absence would make the code cleaner, more efficient and easier to understand.
https://sourcemaking.com/refactoring/smells
Class not providing logic That isn’t useful Predicting the future
67
Which one is clearer?
if(employee.isEligibleForFullBenefits()) //Check to see if the employee is eligible for full benefits if((employee.flags & HOURLY_FLAG)&&(employee.age > 65))
(A) (B)
68
int a [ ]; int b [ ] ; int sumofa = 0; for (int i=0; i<size1; i++){ sumofa += a[i]; } int averageOfa= sumofa/size1; …. int sumofb = 0; for (int i = 0; i<size2; i++){ sumofb += b[i]; } int averageOfb = sumofb/size2; int calcAverage(int* array, int size) { int sum= 0; for (int i = 0; i<size; i++) sum + =array[i]; return sum/size; } int a[]; int b[]; int averageOfa = calcAverage(a[], size1) int averageOfb = calcAverage(b[], size2)
Refactor: Extract method
69
https://www.slideshare.net/annuvinayak/code-smells-and-its-type-with-example
a little fish is (and eat it)
a big fish is
public void move() { choose a random direction; // same for both find the location in that direction; // same for both check if it’s ok to move there; // different if it’s ok, make the move; // same for both }
BigFish move() Fish
<<abstract >>move()
LittleFish move()
70
http://slideplayer.com/slide/7833453/
Refactoring solution:
move() method
method in the Fish class
subclass
BigFish
Fish
move() <<abstract>>okToMove(locn):boolean
BigFish
71
http://slideplayer.com/slide/7833453/
All the smells in this group contribute to excessive coupling between classes or show what happens if coupling is replaced by excessive delegation.
https://sourcemaking.com/refactoring/smells
Misplaced responsibility T
Classes should know as little as possible about each other ( Cohesion)
72
It’s obvious that the method wants to beelsewhere, so we can simply use MOVE METHOD to give the method its dream home.
We are reducing the coupling and enhancing the cohesion
Before Refactored
Feature Envy
73
https://www.slideshare.net/annuvinayak/code-smells-and-its-type-with-example
Feature Envy
another class to perform its work
frequently used methods and data items
74
Feature Envy
class OrderItemPanel { private: itemPanel _itemPanel; void updateItemPanel( ) { Item item = getItem(); int quant = getQuantity( ); if (item == null) _itemPanel.clear( ); else{ _itemPanel.setItem(item); _itemPanel.setInstock(quant); } } }
75
http://slideplayer.com/slide/7833453/ slides 75 to 77
Feature Envy
but the method interests are in class ItemPanel
class OrderItemPanel { private: itemPanel _itemPanel; void updateItemPanel( ) { Item item = getItem(); int quant = getQuantity( ); if (item == null) _itemPanel.clear( ); else{ _itemPanel.setItem(item); _itemPanel.setInstock(quant); } } }
76
class OrderItemPanel { private: itemPanel _itemPanel; void updateItemPanel( ) { Item item = getItem(); int quant = getQuantity( ); _itemPanel.doUpdate(item, quant); } } class ItemPanel { public: void doUpdate(Item item, int quantity){ if (item == null) clear( ); else{ setItem(item); setInstock(quantity); } } }
77
a.getB().getC().getD().getTheNeededData()
Law of Demeter: Each unit should
a.getTheNeededData()
78 https://www.slideshare.net/mariosangiorgio/clean-code-and-code-smells
https://sourcemaking.com/refactoring/smells
Message chains Refactor: Hide delegate
79
if you need to change something in one place in your code, you have to make many changes in other places too. Program development becomes much more complicated and expensive as a result.
https://sourcemaking.com/refactoring/smells
A class has to be changed in several parts A single change requires changes in severall classes
80
When changes are all over the place, they are hard to find and it’s easy to miss an important change
81
public class Account { private String type; private String accountNumber; private int amount; public Account(String type,String accountNumber,int amount) { this.amount=amount; this.type=type; this.accountNumber=accountNumber; } public void debit(int debit) throws Exception { if(amount <= 500) { throw new Exception("Mininum balance shuold be over 500"); } amount = amount-debit; System.out.println("Now amount is" + amount); } public void transfer(Account from,Account to,int cerditAmount) throws Exception { if(from.amount <= 500) { throw new Exception("Mininum balance shuold be over 500"); } to.amount = amount+cerditAmount; } }
The problem occurs when we add another criterion in validation logic that is if account type is personal and balance is over 500 then we can perform above
82
http://javaonfly.blogspot.ca/2016/09/code-smell-and-shotgun-surgery.html
public class AcountRefactored { private String type; private String accountNumber; private int amount; public AcountRefactored(String type,String accountNumber,int amount) { this.amount=amount; this.type=type; this.accountNumber=accountNumber; } private boolean isAccountUnderflow() { if(amount <= 500) { return true; } return false; } public void debit(int debit) throws Exception { if(isAccountUnderflow()) { throw new Exception("Mininum balance shuold be over 500"); } amount = amount-debit; System.out.println("Now amount is" + amount); } public void transfer(AcountRefactored from,AcountRefactored to,int cerditAmount) throwsException { if(isAccountUnderflow()) { throw new Exception("Mininum balance shuold be over 500"); } to.amount = amount+cerditAmount; }
83
http://javaonfly.blogspot.ca/2016/09/code-smell-and-shotgun-surgery.html
Bad Smells hinder code comprehensibility
[Abbes et al.CSMR 2011]
84 https://www.slideshare.net/fabiopalomba/icse15-smell-inducingchange
Bad Smells increase change- and fault-proneness
[Khomh et al.EMSE 2012]
85 https://www.slideshare.net/fabiopalomba/icse15-smell-inducingchange
Bad Smells increase maintenance costs
[Banker et al.Communications of theACM]
86 https://www.slideshare.net/fabiopalomba/icse15-smell-inducingchange
87
88
http://slideplayer.com/slide/7833453/ slides 88 to 90
behavior while they can remove bad code smells
89
90
http://slideplayer.com/slide/7833453/
91
!! This is clearly reflected by the results of the activity you did last week
92
93
94
95
Method
instance
confirm
collection
are opposite
Attribute’s
not
contains
96
https://b.socrative.com/login/student/
Login to the room “SOEN6461LA”
97
98
Rational:
counterintuitive.
Consequences:
the expired time.”
99
Doesn't set anything!!! Creates a new objects and returns it
100
Rational:
! Valid exceptions: returning the modified attribute, or returning the object in which the method is defined to allow chaining method calls
Consequences:
Refactoring:
source.”
101
(do less)
Nothing is returned!! Where is the retrieved data stored and how to
102
(do less)
in the parameter unit”.
103
method = predicate but the return type is not Boolean.
104
not Boolean.
conditional control structure, which is however not possible
message are stored in res”.
selection is valid and “false” otherwise.
105
106
be discovered at compile time.
where it should not be negated (or it should be)..
the state is enabled but also where the state is disabled.
107
! Don’t know whether the change impacts a one or multiple objects
108
impacts a one or multiple objects.
109
! Not clear how to handle this attribute. int True/False
110
declared type must be indeed Boolean
control flow statement condition
111
! contains statistics (collection) single boolean
112
type must also.
113
114
with each other. Not contradict the other.
traversed.
115
116
no contradiction between the attribute’s comments and declaration.
code, the developer might not clearly understand the role of the attribute.
the name of the attribute_ i.e. INCLUDE_NAME_DEFAULT
117
Detector
as part of the Eclipse Checkstyle Plugin5
http://www.veneraarnaoudova.ca/linguistic-anti-pattern-detector-lapd/
118
https://form.jotform.com/azadehks/quiz-on-anti-pattern
119