chapter 7: bad code smells omar meqdadi se 3860 lecture 7 department of computer science and...

45
Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Upload: ethan-floyd

Post on 01-Jan-2016

223 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Chapter 7: Bad Code Smells

Omar Meqdadi

SE 3860 Lecture 7

Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Page 2: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

2

Topic Covered

Bad Code Smells Smells Categorization Smells Refactoring

Page 3: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells

The most common design problems result from code because of bad code smells such as: Code duplication Unclear code Complicated Code

Page 4: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Example

Why is this implementation bad? How can you improve it? Provide a list of improvements.

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"; } }}

Page 5: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

5

Bad Code Smells: Example

Bad Implementation because of switch statements are very rare in properly designed object-

oriented code A switch statement should not be used to distinguish

between various kinds of object

Code improvement solution Refactoring : the simplest is the creation of subclasses

Page 6: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Example

Improved code:

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"; } }

Page 7: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Example

How is this an improvement? Adding a new animal type, such as Insect, does not require

revising and recompiling existing code Mammals, birds, and reptiles are likely to differ in other

ways, and we’ve already separated them out (so we won’t need more switch statements)

we’re now using Objects the way they were meant to be used

Page 8: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Types

Duplicate code Long method Conditional Complexity Data Class Solution Sprawl Switch statements Large class Lazy class Combinatorial Explosion Long Parameter List Data Clumps Comments

Page 9: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Categorization

Bloaters Something that has grown so large that it cannot be effectively handled

Object-Orientation Abusers Cases where the solution does not fully exploit the possibilities of

object-oriented design

Change Preventers Smells that hinder changing or further developing the software.

Dispensable Something unnecessary that should be removed from the source code

Couplers: coupling-related smells

Page 10: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Indications

Frequent failures Overly complex structure Very large components Excessive resource requirements Deficient documentation High personnel turnover Different technologies in one system

Page 11: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells: Solution

Resolving the code smells is a Reengineering Process Steps:

Program Comprehension (Understanding) Refactoring

A set of transformations that are guaranteed to preserve the behavior while they can remove bad code smells

Refining

Page 12: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Bad Code Smells Refactoring

Page 13: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Duplicate Code (Code Clones): The same, or very similar code, appears in many places

Problems: Bug introducing Makes code larger that it needs to be

Page 14: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Case1: occurs within a single class Refactoring: Extract

Method Turn the fragment into

a method whose name explains the purpose of the method

Any local variables that the method requires can be passed as parameters

int sum1 = 0;

int sum2 = 0;

int average1 = 0;

int average2 = 0;

for (int i = 0; i < size1; i++){

sum1 += array1[i]; }

average1 = sum1/size1;

for (int i = 0; i < size2; i++){

sum2 += array2[i];

}

average2 = sum2/size2;

 int calcAverage (int A[] , int size){

int sum = 0;

for (int i = 0; i < size; i++) {

sum += A[i]; }

return sum/size;}  

Page 15: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Case2: occurs in sibling classes Refactoring:

Use Extract Method in each class Be sure the code is identical If necessary, adjust the method signatures to be identical Pull Up Method :Copy the extracted method to the common

superclass Delete the method from subclasses

Page 16: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Example: consider the ocean scenario: Fish move about randomly A big fish can move to where

a little fish is (and eat it) A little fish will not move to where

a big fish is

General move method: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()

Page 17: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Refactoring solution: Extract the check on whether it’s ok to moveIn the Fish class, put the actual move() methodCreate an abstract okToMove() method in the Fish class Implement okToMove() in each subclass

BigFishokToMove(locn):boolean

Fishmove()

<<abstract>>okToMove(locn):boolean

BigFishokToMove(locn):boolean

Page 18: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code

Case3: occurs in unrelated classes Refactoring Solution1:

Use Extract Method in one class Then , invoke the method from the other class

Refactoring Solution2: Use Extract Superclass if that is possible

Page 19: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Duplicate Code: Example

class Car{private:int mpg;double fuelInTank;public:Car() { mpg = 25; fuelInTank = 5.056;}void MoreGas(double g){fuelInTank = fuelInTank + g;}void move(double miles){double used = miles / mpg;fuelInTank = fuelInTank - used;}}    

class Van{private:int mpg;double fuelInTank;public:Van() { mpg = 20; fuelInTank = 9.056;}void MoreGas(double g){fuelInTank = fuelInTank + g;}void move(double miles){double used = miles / mpg;fuelInTank = fuelInTank - used;}}    

class Vehicle{private:int mpg;double fuelInTank;public:void MoreGas(double g){fuelInTank = fuelInTank + g;}void move(double miles){double used = miles / mpg;fuelInTank = fuelInTank - used;}}    

class Car: public Vehicle {public:Car() { mpg = 25; fuelInTank = 5.056;}}class Van: public Vehicle {public:Van() { mpg = 20; fuelInTank = 9.056;}}

    

Page 20: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Long Method

Long method Over 20 LOC is usually bad. Under 10 lines is typically good. Problems: Difficult to

Understand Change Reuse

Refactoring Solution: Method Extraction Take portions of code from inside long method, and make a

new method Then, Call new method inside the now-not-so-long method

Page 21: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Long Method

Example:

void methodA(){Statement 1;Statement 2;..Statement 30;

}

void methodA(){Statement 1;Statement 2;..Statement 30;

}

private void m1(){Statement 1;..Statement 9;

}

private void m2(){Statement 10;..Statement 19;

}

private void m3(){Statement 20;..Statement 30;

} public void methodA(){ m1(); m2(); m3(); }

private void m1(){Statement 1;..Statement 9;

}

private void m2(){Statement 10;..Statement 19;

}

private void m3(){Statement 20;..Statement 30;

} public void methodA(){ m1(); m2(); m3(); }

Page 22: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Feature Envy

Feature Envy A method in one class uses primarily data and methods

from another class to perform its work Indicates the method was incorrectly placed in the wrong

class Problems:

High class coupling Difficult to change , understand, and reuse

Refactoring Solution:Extract Method & Method Movement Move the method with feature envy to the class containing

the most frequently used methods and data items

Page 23: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Feature Envy

Example: Method updateItemPanel

is defined in class

OrderItemPanel, but the

method interests 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);  }} } 

Page 24: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Feature Envy

Example: Refactoring solution:

Extract method doUpdate

in class OrderItemPanel Move method doUpdate

to class ItemPanel

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);  }} } 

Page 25: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Large Classes

Large Classes Classes try to do too much (many methods and data

members) Problems:

Low class cohesion Difficult to change and understand Bug introducing

Refactoring Solution: Class Extraction

Take a subset of the instance variables and methods and create a new class with them

Method Movement

Page 26: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

PhoneNumber

Customer

nameareaCodenumber

String: getPhoneNumber()

PhoneNumber: getPhoneNumber()

Large Classes

Page 27: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Switch Statements

Switch Statements The cases in a switch statement contain logic for different

types of instances of the same class In object-oriented code, this indicates new subclasses should be

created Problems:

Introducing code clones The same switch/case structure appears in many places

Refactoring Solution: Create new subclasses Extract method to move case block logic into methods on the

new subclasses

Page 28: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Switch Statements

Example: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 “skin"; } }}

class Animal { string getSkin() { return “skin"; }

}class Mammal : public Animal {

string getSkin() { return "hair"; }}class Bird: public Animal {

string getSkin() { return "feathers"; }}class Reptile : public Animal {

string getSkin() { return "scales"; }}

After Refactoring

Page 29: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Data Classes

Data Classes A class that has only class variables, get/set methods Acting as a data holder only Problems:

Other classes have methods with feature envy That is, there are usually other methods that primarily

manipulate data in the data class Indicates these methods should really be on the data class

Refactoring Solution: Method Movement Find methods that use data class attributes, and then

move them to the data class

Page 30: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Data Classes

Example: After Refactoring

Page 31: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Long Parameter List

Long Parameter List Many parameters passed into a method Problems:

Hard to understand , change, and reuse Refactoring Solution:

Replace Parameter with Method Introduce Parameter Object Preserve Whole Object

Page 32: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Long Parameter List

Example: void paint (Graphics gr, double x, double y, double width, double height, bool shouldValidate) {.....}   Caller side: public void someMethod(Graphics gr){ double x = 100; double y = 200; double width = 100; double height = width/2; paint(gr, x, y, width, height, true);}  

void paint

(Graphics gr, Shape rec , bool shouldValidate)

{.....}

Caller side:

void someMethod(Graphics gr){

double x = 100;

double y = 200;

double width = 100;

double height = width/2;

Shape rect = new Shape( x, y, width, height);

paint(gr, rect, true);

}

 

After Refactoring

Page 33: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Shotgun Surgery

Shotgun Surgery Making one change requires changing code in multiple

places Problems:

Hard to change Refactoring Solution:

Method Movement Data members(fields) movement Inline classes

Page 34: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Lazy Class

Lazy Class A class just doesn’t do enough Refactoring Solution:

If a class is very similar to its superclass, you can try to use Collapse Hierarchy to merge the two classes

Use Inline class If a class just isn’t doing very much, move all its features into

another class with Move Field and Move Method

Page 35: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Lazy Class

Example: Salesman and Employee are not very different So , merge them

Page 36: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Data Clumps

Data Clumps Sets of variables usually passed together in multiple places Refactoring Solution:

Extract Classes Introduce Parameter Object

Page 37: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Data Clumps

Example: 

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){ }

After Refactoring

Page 38: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Middle Man

Middle Man Delegation : one class simply delegates many of its

requests to another class Refactoring Solution:

Replace Delegation with Inheritance Use Remove Middle Man and talk to the object that really

knows what is going on Use Inline Method to absorb a few small methods into the

caller

Page 39: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Middle Man

Example: using Inline Method

int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; }

boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; }

int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; }

boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; }

int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1;

}

int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1;

}

Page 40: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Temporary Field

Temporary Field We expect an object to use all its fields. However, it’s a

problem when a field is used only in certain cases Or , a case in which a variable is in the class scope, when it

should be in method scope Refactoring Solution:

Use Extract Class to create a home for these variables

Page 41: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

LaborItem

JobItem

getTotalPrice()getUnitPrice()getEmployee()

Do all the JobItem objects need have getEmployee function?

getUnitPrice()

Temporary Field

Page 42: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Refused Bequest

Refused bequest Subclasses may inherit unwanted methods from their

superclasses Refactoring Solution:

Extract Classes and Move Methods Create a new subclass and use method movement on the

unused methods Replace inheritance with delegation

Page 43: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Replace inheritance with delegation A subclass uses only part of a superclasses interface or does not

want to inherit data. Create a field for the superclass, adjust methods to delegate to the

superclass, and remove the subclassing.

Refused Bequest

Page 44: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Comments

Comments Often used as deodorant for other smells

may indicate areas where the code is not as clear as it could be

Refactoring Solution: Extract Method: if you need a comment to explain what a

block of code does Rename Method: if you need a comment to explain what a

method does Introduce Assertion: if you need to describe the required

state of the system

Page 45: Chapter 7: Bad Code Smells Omar Meqdadi SE 3860 Lecture 7 Department of Computer Science and Software Engineering University of Wisconsin-Platteville

Comments

Example:

void PrintBill ( Customer C , double Amount){

PrintBanner();

string name = c.getname();

// print details

cout << “name: ” << name << endl;

cout << ”amount: ” << Amount << endl;

}

void PrintBill ( Customer C , double Amount){

PrintBanner();

PrintDetails (c.getname() , Amount);

}

void PrintDetails(string name , double amount){

cout << “name: ” << name << endl;

cout << ”amount: ” << Amount << endl;

}

Comment deleted , temp variable removed

After Extract Method Refactoring