refactoring bad codesmell
TRANSCRIPT
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
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
Code Smells and Refactoring
Table of Contents
• Bloaters( 훈제 청어 :: 비림 )
• Object-Oriented Abusers( 객체지향 학대자 )
• Change Preventers( 변경 예방자 )
• Dispensable( 없어도 되는 )
• Couplers( 결합도 )
Reference: https://refactoring.guru/smells/smells
Bloaters
Bloaters
• Bloaters– gargantuan code, methods and classes that
are difficult to handle• Long Methods• Large Class• Primitive Obsession( 기본 타입에 대한 강박관념 )• Long Parameter List( 과다한 매개변수 )• Data Clumps( 데이터 덩어리 )
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
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); }
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)...
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
BloatersPrimitive Obsession
• Do we really need classes for Numbers, Strings and Dates?
• Money classes, Telephone numbers, ZIP/PIN Codes
• “Overhead” of creating these : why?
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;}
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
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
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; }
}
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
BloatersData Clumps
• A few data items “hanging out” together
• Examples– fields in classes– Parameters in multiple methods
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) }
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.
–
Object-Oriented Abusers
• Object-Oriented Abusers– incomplete or incorrect application of OO
principles • Switch Statement• Temporary Field• Refused Bequest( 방치된 유산 )• Alternative Classes With Different Interface
Object-Oriented AbusersSwitch Statement
• Not really “Object oriented” code
• Should be polymorphism instead!
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();
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
Object-Oriented AbusersTemporary Field
• Instance variables instead of parameters?
• Set only in “certain” circumstances
• Complicated algorithm requiring several variables
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; } }
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
Object-Oriented AbusersRefused Bequest( 방치된 유산 )
• Subclasses don’t want or need all the methods or features
• Just need what they need
• Wrong Hierarchy!
Object-Oriented Abusers• Example(Push Down Method)
Sale() Sale()
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
Object-Oriented AbusersAlternative Classes with Different Interfaces( 인터페이스가 다른 대용 클레스 )• Classes perform identical functions but have different method names
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}}
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
Change Preventers
• Change Preventers– change is one place resulting in many
changes in other places• Divergent Change • Shotgun Surgery• Parallel Inheritance Hierarchies
Change PreventersDivergent Change( 수정의 산발 )
• One class changed in different ways for different reasons
• Two objects in this case?
• All change should be in one class?
Change Preventers• Example(Extract Class)
Change Preventers
• Refactoring
– Move method
– Move field
– Inline class (to bring behaviour together in a class)
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
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);}
Change Preventers
• Refactoring
– Move method
– Move field
– Inline class (to bring behaviour together in a class)
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
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.
Dispensables
• Dispensables– something pointless and unnecessary whose
absence would make code cleaner• Comments • Duplicate Code• Lazy Class• Data Class• Dead Code• Speculative Generality
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
Dispensables
• Use a comment is when you don’t know what to do• Code becomes more intuitive and obvious.
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
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
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.
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
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
Dispensables
• A class that isn’t doing enough to pay for itself should be eliminated
• Reduced code size. Easier maintenance.
Dispensables
• Refactoring- Subclasses that aren’t doing enough Collap
se Hierarchy- Nearly useless component should be subjec
t Inline Class and Inline Module
• 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
Dispensables
• Improves understanding and organization of code.• to participate as a grownup object, they need to take so
me responsibility.
Dispensables
• 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
• 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
• Refactoring- Delete unused code and unneeded files- The case of an unnecessary class Inline Class or Collapse Hierarchy- Remove unneeded parameters Remove Parameter
Dispensables
• 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
• 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
Couplers
• Couplers– contributing to excessive coupling between
classes• Feature Envy• Inappropriate Intimacy• Message Chains• Middle Man• Incomplete Library Class
• 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
• Refactoring
- The method clearly wants to be elsewhere Move Method
- Part of the method suffers from envy Extract Method and Move Method
Couplers
• 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
• 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
• 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
• Refactoring- Object requests another one Hide Delega
te- The end object is being used Extract Metho
d and Move Method
Couplers
• 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
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
• 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
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
END