refactoring bad codesmell

71
Chapter 3. Bad Smells in Code Refactoring: Improving the Design of Existing Code Software Engineering Laboratory Department of Computer Science & Engineering ERICA Campus, Hanyang University HyungLak Kim, Kuangkyu Choi

Upload: hyunglak-kim

Post on 12-Jan-2017

34 views

Category:

Science


1 download

TRANSCRIPT

Page 1: Refactoring bad codesmell

Chapter 3. Bad Smells in CodeRefactoring:

Improving the Design of Existing Code

Software Engineering LaboratoryDepartment of Computer Science & EngineeringERICA Campus, Hanyang University

HyungLak Kim, Kuangkyu Choi

Page 2: Refactoring bad codesmell

What is Refactoring

Definition•The process of changing a software system in such as a way that it does not alter the external behavior of the code yet improves its internal structure

Page 3: Refactoring bad codesmell

Code Smells and Refactoring

Page 4: Refactoring bad codesmell

Table of Contents

• Bloaters( 훈제 청어 :: 비림 )

• Object-Oriented Abusers( 객체지향 학대자 )

• Change Preventers( 변경 예방자 )

• Dispensable( 없어도 되는 )

• Couplers( 결합도 )

Reference: https://refactoring.guru/smells/smells

Page 5: Refactoring bad codesmell

Bloaters

Page 6: Refactoring bad codesmell

Bloaters

• Bloaters– gargantuan code, methods and classes that

are difficult to handle• Long Methods• Large Class• Primitive Obsession( 기본 타입에 대한 강박관념 )• Long Parameter List( 과다한 매개변수 )• Data Clumps( 데이터 덩어리 )

Page 7: Refactoring bad codesmell

BloatersLong Methods

•A method contains too many lines of code» Ex) any method longer than ten lines

•Refactoring – To reduce the length of a method body, use Extract Method– Conditional operators and loops are a good clue that code can be

moved to a separate method. For conditionals, use Decompose Conditional

Page 8: Refactoring bad codesmell

Bloaters• Example(Extract Method)

void aboutPrint (String interesting){ printBar(); System.out.println( ”fun:" + fun); System.out.println( ”interesting" + interesting);

..…..…….

} void aboutPrint(String interesting){ printBar(); printDetails(interesting); } void printDetails (String interesting){ System.out.println( ”fun:" + fun); System.out.println( ”interesting" + interesting); }

Page 9: Refactoring bad codesmell

BloatersLarge Class•A class contains many fields/methods/lines of code

function __construct($url = null, $useBrackets = true)...function initialize()...function getURL()...function addQueryString($name, $value, $preencoded =

false)...function removeQueryString($name)...function addRawQueryString($querystring)...function getQueryString()...function _parseRawQuerystring($querystring)...function resolvePath($path)...function getStandardPort($scheme)...function setProtocol($protocol, $port = null)...function setOption($optionName, $value)...function getOption($optionName)...

Page 10: Refactoring bad codesmell

Bloaters• Refactoring

– Extract Class helps if part of the behavior of the large class can be spun off into a separate component

– Extract Subclass helps if part of the behavior of the large class can be implemented in different ways or is used in rare cases

– Extract Interface helps if it is necessary to have a list of the operations and behaviors that the client can use

Page 11: Refactoring bad codesmell

BloatersPrimitive Obsession

• Do we really need classes for Numbers, Strings and Dates?

• Money classes, Telephone numbers, ZIP/PIN Codes

• “Overhead” of creating these : why?

Page 12: Refactoring bad codesmell

Bloaters(Primitive Obsession)•Example(Replace Type Code with class)

publicclass City {

    public static void main(String args[]) {           Integer[] cityPopulations = {           13000000, // London           21903623, // New York           12570000, // Tokyo           1932763, // Stockholm           1605602, // Barcelona           4119190 // Sydney           };}        

public class City {

private final String name;private final int  population;private final Continent continent;// 대륙public String getName() {return name;}public int getPopulation() {return  population;}public Continent getContinent() {return continent;}

Page 13: Refactoring bad codesmell

Bloaters• Refactoring

– Replace Data Value with Object on individual data values

– Replace Type Code with Class if the value does not affect behaviour

– Replace Type Code with Subclasses if conditionals that depend upon type code present

– Replace Type Code with State/Strategy , if conditionals depending upon type code present

– Extract class if group of fields are going together

Page 14: Refactoring bad codesmell

BloatersLong Parameter List

• Procedural programming – Pass in as many parameters as you need• Reduced need with OOP • Solution

– Pass an object instead in the parameters– Method’s host class contains all the data – Method gets what it needs, nothing more nothing less

Page 15: Refactoring bad codesmell

Bloaters• Example(Replace Parameter with Method)

public Person createPerson( final String lastName, final String firstName, final String middleName, final String salutation, final String suffix, final String streetAddress, final String city, final String state, final boolean isFemale, final boolean isEmployed, final boolean isHomeOwner) { // implementation goes here }        

public final class Name {

private final String name; //last + first + middle public Name(final String newName) { this.name = newName; }

public String getName() { return this.name; }

@Override public String toString() { return this.name; }

}

Page 16: Refactoring bad codesmell

Bloaters• Refactoring

– Check what values are passed to parameters. If some of the arguments are just results of method calls of another object, use Replace Parameter with Method Call

– Instead of passing a group of data received from another object as parameters, pass the object itself to the method, by using Preserve Whole Object

– If there are several unrelated data elements, sometimes you can merge them into a single parameter object via Introduce Parameter Object

Page 17: Refactoring bad codesmell

BloatersData Clumps

• A few data items “hanging out” together

• Examples– fields in classes– Parameters in multiple methods

Page 18: Refactoring bad codesmell

Bloaters• Example(Extract Class)

public class Person { final String lastName, final String firstName, final String middleName, final String streetAddress, final String city, final String state, final boolean isFemale, final boolean isEmployed, final boolean isHomeOwner) }        

public class Name { final String lastName, final String firstName, final String middleName, }public class Address { final String streetAddress, final String city, final String state, }public class Company{ final boolean isFemale, final boolean isEmployed, final boolean isHomeOwner) }

        

Page 19: Refactoring bad codesmell

Bloaters• Refactoring

– If repeating data comprises the fields of a class, use Extract Class to move the fields to their own class

– If the same data clumps are passed in the parameters of methods, use Introduce Parameter Object to set them off as a class

– If some of the data is passed to other methods, think about passing the entire data object to method instead of just individual fields. Preserve Whole Object will help with this.

– Look at the code used by these fields. It may be a good idea to move this code to a data class.

Page 20: Refactoring bad codesmell

Object-Oriented Abusers

• Object-Oriented Abusers– incomplete or incorrect application of OO

principles • Switch Statement• Temporary Field• Refused Bequest( 방치된 유산 )• Alternative Classes With Different Interface

Page 21: Refactoring bad codesmell

Object-Oriented AbusersSwitch Statement

• Not really “Object oriented” code

• Should be polymorphism instead!

Page 22: Refactoring bad codesmell

Object-Oriented Abusers• Example(Replace Conditional with Polymorphism)

class Num{int state; String getString() { switch (state) { case 0 : // behaviour for state 0

return "zero"; case 1 : // behaviour for state 1

return "one"; case 2 : // behaviour for state 2

return ”two"; case 3 : // behaviour for state 3

return ”three"; } }}

abstract class Num { abstract String getString();}

class Zero extends Num { String getString() { return “zero”;}}class One extends Num { String getString() { return “one”;}}………….// Somewhere in client codenum = num.getString();

Page 23: Refactoring bad codesmell

Object-Oriented Abusers

• Refactoring

– Extract Method to extract the switch statement and Move Method to move it to specified class

– Decide on Replace Type Code with Polymorphism or Replace Type Code with State/Strategy

– Non-changing case affecting a single method, use Replace Parameter with Explicit Methods

Page 24: Refactoring bad codesmell

Object-Oriented AbusersTemporary Field

• Instance variables instead of parameters?

• Set only in “certain” circumstances

• Complicated algorithm requiring several variables

Page 25: Refactoring bad codesmell

Object-Oriented Abusers• Example(Inline Temp Method)

public int foo(int a, int b){ int temp = a * b; if(temp > 100){ return temp * 0.95; } else { return temp * 0.25; } }

public int foo(int a, int b){ if(a * b > 100){ return a * b * 0.95; } else { return a * b * 0.25; } }

        

Page 26: Refactoring bad codesmell

Object-Oriented Abusers

• Refactoring

– Extract Class to create a home for these variables

– Introduce null object to create a component for when these variables are not valid

Page 27: Refactoring bad codesmell

Object-Oriented AbusersRefused Bequest( 방치된 유산 )

• Subclasses don’t want or need all the methods or features

• Just need what they need

• Wrong Hierarchy!

Page 28: Refactoring bad codesmell

Object-Oriented Abusers• Example(Push Down Method)

Sale() Sale()

Page 29: Refactoring bad codesmell

Object-Oriented Abusers

• Refactoring

– Extract Class to create a home for these variables

– Introduce null object to create a component for when these variables are not valid

Page 30: Refactoring bad codesmell

Object-Oriented AbusersAlternative Classes with Different Interfaces( 인터페이스가 다른 대용 클레스 )• Classes perform identical functions but have different method names

Page 31: Refactoring bad codesmell

Object-Oriented Abusers• Example(Move Method)

public class Conveyance { void train(){ implement} void truck(){implement}}

public class Conveyance { void train(){ implement} move void truck(){implement}}public class KTX { move void train(){ implement}}

Page 32: Refactoring bad codesmell

Object-Oriented Abusers

• Refactoring

– Rename Method for classes with different interfaces that do the same thing

– Repeatedly use Move method until the protocols are the same

Page 33: Refactoring bad codesmell

Change Preventers

• Change Preventers– change is one place resulting in many

changes in other places• Divergent Change • Shotgun Surgery• Parallel Inheritance Hierarchies

Page 34: Refactoring bad codesmell

Change PreventersDivergent Change( 수정의 산발 )

• One class changed in different ways for different reasons

• Two objects in this case?

• All change should be in one class?

Page 35: Refactoring bad codesmell

Change Preventers• Example(Extract Class)

Page 36: Refactoring bad codesmell

Change Preventers

• Refactoring

– Move method

– Move field

– Inline class (to bring behaviour together in a class)

Page 37: Refactoring bad codesmell

Change PreventersShotgun Surgery

• Opposite of divergent change

• One kind of change involves touching several classes

• Changes are all over the place and something gets missed

Page 38: Refactoring bad codesmell

Change Preventers• Example(Inline Class)

ChangePublic class Func1{void myFunc1(int){…………………..}}Public class Func2{void myFunc2(int){…………………..}} …Public class FuncN{void myFuncN(int){…………………..}}

Public class Allfunc{

void myFunc(){…………}void myFunc2(){………..}void myFuncN(){……….}}

        

Public class Orgin{Func1.myFunc1(string name);}Public class Orgin1{Func2.myFunc2(string name);}….Public class OrginN{FuncN.myFuncN(string name);}

Page 39: Refactoring bad codesmell

Change Preventers

• Refactoring

– Move method

– Move field

– Inline class (to bring behaviour together in a class)

Page 40: Refactoring bad codesmell

Change PreventersParallel Inheritance Hierarchies• Special case of Shotgun Surgery• Every time a subclass of one class is made, a subclass of another is needed• Solution

– Eliminate duplication , instances of one hierarchy refer to another

Page 41: Refactoring bad codesmell

Change Preventers

• Refactoring

– Move method and Move field to eliminate one hierarchy

– You may de-duplicate parallel class hierarchies in two steps. First, make instances of one hierarchy refer to instances of another hierarchy. Then, remove the hierarchy in the referred class, by using Move Method and Move Field.

Page 42: Refactoring bad codesmell

Dispensables

• Dispensables– something pointless and unnecessary whose

absence would make code cleaner• Comments • Duplicate Code• Lazy Class• Data Class• Dead Code• Speculative Generality

Page 43: Refactoring bad codesmell

Dispensables

• we aren’t saying that shouldn’t write comments.• comments here is that comments often are used a

s a deodorant• you look at thickly commented code and notice th

at the comments are there because the code is bad

Comment

Page 44: Refactoring bad codesmell

Dispensables

• Use a comment is when you don’t know what to do• Code becomes more intuitive and obvious.

Page 45: Refactoring bad codesmell

Dispensables• Refactoring

- need a comment to explain what a block of code Extract Method

- method is already extracted but you still need a comment to explain what is does Rename Method

- If you need to state some rules about the required state of the system Introduce Assertion

Page 46: Refactoring bad codesmell

Dispensables

• Number one in the stink parade is duplicated code• the same code structure in more than one place• when specific parts of code look different but actually p

erform the same job. This kind of duplication can be hard to find and fix.

Duplicate Code

Page 47: Refactoring bad codesmell

Dispensables

• program will be better if you find a way to unify them• Merging duplicate code simplifies the structure of you

r code and makes it shorter.• Simplification + shortness = code that is easier to sim

plify and cheaper to support.

Page 48: Refactoring bad codesmell

Dispensables• Refactoring

- Same expression in two methods of the same class Extract Method

- Same expression in two sibling subclasses Extract Method and Pull Up Field

- Code is similar but not the same Extract Method Form Template Method

- Methods do the same thing with a different algorithm Substitute Algorithm

- Duplicated code in two unrelated classes Extract Class

Page 49: Refactoring bad codesmell

Dispensables

• Each class you create costs money to maintain and understand

• Class was designed to be fully functional but after some of the refactoring it has become ridiculously small

• It was designed to support future development work that never got don

Lazy Class

Page 50: Refactoring bad codesmell

Dispensables

• A class that isn’t doing enough to pay for itself should be eliminated

• Reduced code size. Easier maintenance.

Page 51: Refactoring bad codesmell

Dispensables

• Refactoring- Subclasses that aren’t doing enough Collap

se Hierarchy- Nearly useless component should be subjec

t Inline Class and Inline Module

Page 52: Refactoring bad codesmell

• Classes that have fields, getting and setting methods for the fields, and nothing else

• Such classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes.

• the true power of objects is that they can contain behavior types or operations on their data

Data Class

Dispensables

Page 53: Refactoring bad codesmell

Dispensables

Page 54: Refactoring bad codesmell

• Improves understanding and organization of code.• to participate as a grownup object, they need to take so

me responsibility.

Dispensables

Page 55: Refactoring bad codesmell

• Refactoring

- These classes may have public fields Encapsulate Field

- Check to see whether they are properly encapsulated Encapsulate Collection

- Any fields that should not be changed Remove Setting Method

- These getting and setting methods are used by other classes Move Method

- Can’t move whole method Extract Method and Hide Method

Dispensables

Page 56: Refactoring bad codesmell

• A variable, parameter, field, method or class is no longer used (usually because it is obsolete).

• When requirements have changed or corrections have been made, nobody had time to clean up the old code.

• Found in complex conditionals, when one of the branches becomes unreachable (due to error or other circumstances).

DispensablesDead Code

Page 57: Refactoring bad codesmell

• Refactoring- Delete unused code and unneeded files- The case of an unnecessary class Inline Class or Collapse Hierarchy- Remove unneeded parameters Remove Parameter

Dispensables

Page 58: Refactoring bad codesmell

• thus want all sorts of hooks and special cases to handle things that aren't required.

• The result often is harder to understand and maintain• get rid of it

Speculative Generality

Dispensables

Page 59: Refactoring bad codesmell

• Refactoring- Abstract classes that aren’t doing much

Collapse Hierarchy- Unnecessary delegation Inline Class- Methods with unused parameters Remov

e Parameter- Methods named with odd abstract name

Rename Method

Dispensables

Page 60: Refactoring bad codesmell

Couplers

• Couplers– contributing to excessive coupling between

classes• Feature Envy• Inappropriate Intimacy• Message Chains• Middle Man• Incomplete Library Class

Page 61: Refactoring bad codesmell

• Seems more interested in a class other than the one it actually is in

• The most comment focus of the envy is data

Feature Envy

Couplers

Page 62: Refactoring bad codesmell

• Refactoring

- The method clearly wants to be elsewhere Move Method

- Part of the method suffers from envy Extract Method and Move Method

Couplers

Page 63: Refactoring bad codesmell

• Sometimes classes become far too intimate and spend too much time delving in each other’s private parts

• Good classes should know as little about each other as possible

Inappropriate Intimacy

Couplers

Page 64: Refactoring bad codesmell

• Refactoring

- Overintimate classes Move Method And Move Field

- Classes do have common interests Extract Class And Hide Delegate

- Redundantly move code to accomplish Extract Subclass

Couplers

Page 65: Refactoring bad codesmell

• A message chain occurs when a client requests another object, that object requests yet another one and so on.

• Navigating this way means the client is coupled to the structure of the navigation

• Any change to the intermediate relationships causes the client to have to change

Message Chains

Couplers

Page 66: Refactoring bad codesmell

• Refactoring- Object requests another one Hide Delega

te- The end object is being used Extract Metho

d and Move Method

Couplers

Page 67: Refactoring bad codesmell

• One of the prime feature of objects is encapsulation• Encapsulation often comes with delegation• class’s interface find half the methods are delegating to

this other class

Middle Man

Couplers

Page 68: Refactoring bad codesmell

Refactoring Method– Half the methods are delegating to this othe

r class Remove Middle Man– Only a few methods aren’t doing much Inlin

e Method– there is additional behavior Replace Delegat

ion with Inheritance

Couplers

Page 69: Refactoring bad codesmell

• Reuse is often touted as the purpose of objects, reuse is overrated

• Builders of library classes are rarely omniscient• that is usually impossible to modify a library class to do

something

Incomplete Library Class

Couplers

Page 70: Refactoring bad codesmell

Refactoring Method

- A couple of methods that you wish the library class Introduce Foreign Method

- There is whole load of extra behavior Introduce Local Extension

Couplers

Page 71: Refactoring bad codesmell

END