05-Clean Code
05-Clean Code
Content
1. Introduction Clean Code
Keep it Clean, Your Mother Doesn’t Work Here!
2. Meaningful Names
3. Clean Function/Method
4. Clean Class
5. Clean Test
3
… by anyone
Going fast
”The only way to go fast, is to go well”
Robert C. Martin
• Don’t hack and skip testing just to finish at
the end of an iteration
• Write unit tests
• Fix the code
• Refactor
8
• Poor reusability
• It breaks when you change it
• Changes to component require inspecting/ modifying
more code
D.R.Y Principle
• Don’t Repeat Yourself
• Applicable whenever we copy / paste a
piece of code
• Just use a method or a class
16
K.I.S.S Principle
• Keep It Simple and Stupid
• Whenever we want to implement a method to do
all things
17
Y.A.G.N.I principle
• You Ain’t Gonna Need It
• Don’t write methods which are not yet
necessary (may be you will never need
them)
• Unused classes, methods, parameters,
variables à remove them
• Somehow related with KISS
18
Law of Demeter
Karl Lieberherr i and colleagues
• Law of Demeter: An object should know as little as possible
about the internal structure of other objects with which it
interacts – a question of coupling
• Or… “only talk to your immediate friends”
• Closely related to representation exposure and
(im)mutability
• Bad example – too-tight chain of coupling between classes
general.getColonel().getMajor(m).getCaptain(cap)
.getSergeant(ser).getPrivate(name).digFoxHole();
• Better example
general.superviseFoxHole(m, cap, ser, name);
19
S.O.L.I.D Principles
• SRP: The Single Responsibility Principle
• OCP: The Open Closed Principle
• LSP: The Liskov Substitution Principle
• ISP: The Interface Segregation Principle
• DIP: The Dependency Inversion Principle
21
Content
1. Introduction Clean Code
Keep it Clean, Your Mother Doesn’t Work Here!
2. Meaningful Names
3. Clean Function/Method
4. Clean Class
5. Clean Test
22
Example
What is the purpose of this code?
Solution
• The simplicity of this code is not changed, but much more
meaningful
VS
29
VS
30
Content
1. Introduction Clean Code
Keep it Clean, Your Mother Doesn’t Work Here!
2. Meaningful Names
3. Clean Function/Method
4. Clean Class
5. Clean Test
35
HtmlUtil.java (v2)
public static String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite) throws Exception{
boolean isTestPage = pageData.hasAttribute("Test"); //low
if (isTestPage){
WikiPage testPage = pageData.getWikiPage(); // high
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent();
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml(); Two levels of
}
abstraction
39
HtmlUtil.java (v3)
public static String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite) throws Exception{
if (isTestPage(pageData))
includeSetupAndTeardownPages(pageData, isSuite);
return pageData.getHtml();
}
4
0
41
3.2. (cont.)
• Extract Try/Catch Blocks
• Try/Catch mixes error processing with normal processing
Error Processing
• Extract bodies of try/catch out into separated functions
3.2. (cont.)
• Prefer Exceptions to Returning Error Codes
(Control Coupling)
3.2. (cont.)
• Prefer Exceptions to Returning Error Codes
(Control Coupling) – Benefits:
1. No more code for checking various error codes
2. Exception classes can implement their own method,
i.e., error handling functionality
3. Error codes can’t be used in a constructor, since a
constructor must return only a new object
46
3.2. (cont.)
• Have No Side Effect
• Not do hidden things
• Side Effect: Make unexpected changes to the variables
of its own class or parameters or global data (Common
coupling)
47
WHY?
51
5
8
Data-Level Refactoring
Move an expression inline
• Improve the readability of the program by getting rid of the unnecessary variable
5
9
Data-Level Refactoring
Introduce an intermediate variable
• Introduce explaining variable
Drawbacks?
6
0
Data-Level Refactoring
Convert a multi-use variable to a multiple single-use
variables
• Create separate variable for each usage
6
2
Data-Level Refactoring
Convert a set of type codes (constants) to enum
6
3
Data-Level Refactoring
Convert a set of type codes (constants) to enum/class
What if the method receives the same string but in lower case “admin”?
6
5
Data-Level Refactoring
Convert a set of type codes to a class with subclasses with
different behavior
Benefits:
• Delete control flow code by moving the code to appropriate subclasses
• Need to add a new value for a coded type è Add new subclass, so OCP!
6
6
Data-Level Refactoring
What if:
• your type code affects the behavior of a class
• the value of coded type can be changed during the
object’s lifetime?
You cannot use:
• Replace Type Code with Class/Enum
• Replace Type Code with Subclasses
6
7
Replace type code by Strategy/State
If a new value of a coded type is needed, just create a new state subclass!
6
8
Data-Level Refactoring
Change an array to an object
• When you use an array with different goals for each element
Solution: Replace the array with an object that will have separate
fields for each element.
6
9
Data-Level Refactoring
Encapsulate a collection
Problem: A class contains a collection field and a simple getter/setter for working
with this collection
7
0
71
Statement-Level Refactoring
• Decompose a boolean expression
• Move a complex boolean expression into a well-
named boolean function
72
Statement-Level Refactoring
• Consolidate Conditional Expression
• Multiple conditionals that lead to the same
result or action
73
Statement-Level Refactoring
• Consolidate duplicated code in conditionals
74
Statement-Level Refactoring
Return as soon as you know
the answer instead of
assigning a return value
75
Statement-Level Refactoring
Replace conditionals with polymorphism
Problem: We have a conditional that performs various actions depending on
object type or properties
76
Statement-Level Refactoring
Use null-object design pattern instead of
checking for null
Method-Level Refactoring
• Extract method / inline method
• Rename a method
• Convert a long routine to a class
• Add / remove parameter
• Combine similar methods by parameterizing them
• Substitute a complex algorithm with simpler
• Separate methods whose behavior depends on
parameters passed in (create new ones)
• Pass a whole object rather than specific fields
• Encapsulate downcast / return interface types
79
Content
1. Introduction Clean Code
Keep it Clean, Your Mother Doesn’t Work Here!
2. Meaningful Names
3. Clean Function/Method
4. Clean Class
5. Clean Test
81
9
2
Restructure class
• Pull up constructor body
• Your subclasses have constructors with code that’s mostly
identical
9
3
Restructure class
• Push down field/method
• If some members of superclass are used only in a few
subclasses
9
4
Extract subclass
• Code smell: a class has features that are used only in
certain cases
• Solution: create a subclass and use it in these cases
• Case study:
• Car class, you had field isElectricCar and depending on
it, in the refuel() method the car is either fueled up with gas
or charged with electricity.
9
5
96
Extract superclass
• Code smell: two
classes with common
fields and methods
(duplication code)
• Solution: create a
superclass containing
all duplication code
97
Extract superclass
• Code smell: two
classes with common
fields and methods
(duplication code)
• Solution: create a
superclass containing
all duplication code
98
Collapse Hierarchy
• Code smell: Subclass is practically the same as its
superclass
• Solution: Merge the subclass and superclass
99
• Solution:
• Create a field and put a superclass object in it, delegate
methods to the superclass object, and get rid of inheritance
1
0
Replace Inheritance with Delegation (2)
• Case study:
1
0
Replace Inheritance with Delegation (3)
• Case study:
1
0
Replace Inheritance with Delegation (4)
• Case study: A navigation application for casual
travelers
1
0
Replace Inheritance with Delegation (4)
• Solution: Inheritance. Is it good enough?
1
0
Replace Inheritance with Delegation (5)
• Solution: Delegation
Strategy Pattern
1
0
Replace Delegation with Inheritance
• Problem: A class contains many simple methods that
delegate to all methods of another class
1
0
Replace Delegation with Inheritance
• Solution: Make the class a delegate inheritor, which makes the
delegating methods unnecessary
• When not to use?
1
0
110
1
1
Extract interfaces (2)
• Case study
1
1
Hide delegate
• Problem: The client gets object B from a field or
method of object A, then the client calls a
method of object B
• Code smell: message chain
• a.b().c().d()
• Why refactoring?
• a: server – the object to which the client has direct access
• c(): return an object – delegate – the end object that
contains the functionality needed by the client
• These sequences of calls involve the client in navigation
along the class structure, any changes in these 1
interrelationships will require changes on the client side 1
Hide delegate (2)
• Solution: Create a new method in class A that delegates
the call to object B
manager = aPerson.getDepartment().getManager() 1
1
Hide delegate (3)
• Solution: Create a new method in class A that delegates
the call to object B
• Benefit?
manager = aPerson.getManager()
return this.department.manager
1
1
Remove Middle Man
• Problem: A class has too many methods that
simply delegate to objects of other classes
• Result from the elimination of Message Chains
• Solution: Delete these methods and force the
client to call the end methods directly
1
1
Introduce Foreign Method
• Problem: A utility class doesn’t contain the method
that you need and you can’t add the method to the
class
1
1
Introduce Foreign Method (2)
• Solution: Add the method to a client class and
pass an object of the utility class to it as an
argument
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (2)
• Case stydy:
• Problem: You need other kinds of notification than just email
notification
• You just inherit the base class Notifier
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (3)
• Case stydy:
• What if someone asks you to provide notification on multiple
channels?
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (4)
• Case stydy:
• What if someone asks you to provide notification on multiple
channels?
! ! !
ps
Oo
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (5)
• Case study – Solution: Using Aggregation or Composition
instead Inheritance
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (6)
• Case study – Solution: We
leave the simple email
notification inside the base class
Notifier and turn all other
notification methods into
decorators
wrappee = notifier
1
2
Using Decorator to resolve the Incomplete
Library Class Code Smell (7)
• How does the client work?
• Client wraps a basic notifier
object into a set of decorators
that match the client’s
preferences
• The resulting object will be
structured as a stack
1
2
128
1
2
130
Content
1. Introduction Clean Code
Keep it Clean, Your Mother Doesn’t Work Here!
2. Meaningful Names
3. Clean Function/Method
4. Clean Class
5. Clean Test
132
Bug handling
1. Write a test that proves the existense of the bug
2. Fix the code and watch the test pass
à Automated regression testing
• Security benefit
• If we find a bug somewhere, we can make sure it does
not reappear
134
SerializedPageResponderTest.java
public void testGetDataAsHtml() throws Exception {
crawler.addPage(root, PathParser.parse("TestPageOne"), "test page");
request.setResource("TestPageOne");
request.addInput("type", "data");
Responder responder = new SerializedPageResponder();
SimpleResponse response =
(SimpleResponse) responder.makeResponse(
new FitNesseContext(root), request);
String xml = response.getContent();
assertEquals("text/xml", response.getContentType());
assertSubString("test page", xml); assertSubString("<Test", xml);
}
SerialDate d4 = SerialDate.addMonths(1,
SerialDate.addMonths(1, d1));
assertEquals(30, d4.getDayOfMonth());
assertEquals(7, d4.getMonth());
assertEquals(2004, d4.getYYYY());
}
143
5.5. F.I.R.S.T
• Fast: Tests should be fast.
• To run them frequently
• Independent: Tests should not depend on each other
• One test should not set up the conditions for the next test
• Able to run each test independently and run the tests in any order
• Repeatable: Tests should be repeatable in any environment
• Able to run the tests in development, testing, production, QA
environment… without a network.
• Self-Validating: The tests should have a boolean output
either they pass or fail.
• Make the failure objective, not subjective (not manlually)
• Timely: The tests need to be written in a timely fashion
• Unit tests should be written just before the production code that makes
them pass
144