Clean Code March 2017
Clean Code March 2017
Benedikus H Tjuatja
David Setyanugraha
Fakhri
Lutvianes Advendianto
Overview
● Issues
● Solution
● Conclusion
3
© GDP Labs 2017
Issues !
● Bad Code
● Who is Responsible?
4
© GDP Labs 2017
Bad Code
● Technical debt:
the eventual consequences of poor software
architecture and software development within a code
base.
○ Rushed the product to the market
○ Had made a huge mess in the code
○ Added more features
○ The code got worse and worse
5
© GDP Labs 2017
Bad Code
● LeBlanc’s Law:
Later equals never
○ They never go back
to fix the bad code
● Sink projects, careers
and companies
● Example: netscape and
myspace
6
© GDP Labs 2017
Death Spiral:
The downward,
corkscrew-motion of a disabled
aircraft which is unrecoverably
headed for a crash
7
Great Company vs Bad Company
8
© GDP Labs 2017
Great Company vs Bad Company
9
© GDP Labs 2017
Great Company vs Bad Company
10
© GDP Labs 2017
Who is ● BOD?
● Management?
Responsible ● Program Manager?
11
© GDP Labs 2017
It is a crime if a
surgeon does not
“clean” his hands
12
For the things we have
to learn before we can
do them, we learn by
doing them - Aristotle
13
Solution
● Naming
● Function
● Comment
● Formatting
● Objects and Data Structures
● Error Handling
● Class
● Emergence
14
© GDP Labs 2017
Naming
”
exists, what it does, and how it is used.
- Robert C. Martin
15
© GDP Labs 2017
Naming
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
16
© GDP Labs 2017
Naming
17
© GDP Labs 2017
Naming
18
© GDP Labs 2017
Naming
Avoid misleading and unmeaningful distinctions
int a = l;
if (O == l)
a = O1;
else
l = 01;
MISLEADING
19
© GDP Labs 2017
Naming
20
© GDP Labs 2017
Naming
21
© GDP Labs 2017
Naming
22
© GDP Labs 2017
Naming
23
© GDP Labs 2017
Naming
24
© GDP Labs 2017
Naming
for (int i=0; i<34; i++) {
s += (t[i]*4)/5;
} NOT EASY TO SEARCH
25
© GDP Labs 2017
Naming
26
© GDP Labs 2017
Function
- Robert C. Martin
”
27
© GDP Labs 2017
public static String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite
) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
} TOO BIG
28
Function
Do one thing
public static String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite) throws Exception {
if (isTestPage(pageData))
includeSetupAndTeardownPages(pageData, isSuite);
return pageData.getHtml();
}
29
© GDP Labs 2017
Function
if (set(”username”, ”unclebob”))
30
© GDP Labs 2017
Function
if (attributeExists(”username”)) {
setAttribute(”username”, ”unclebob”);
}
31
© GDP Labs 2017
Function
32
© GDP Labs 2017
Function
Avoid too many function parameters
33
© GDP Labs 2017
Comments
”
that this comment isn’t needed?'
- Steve McConnell
34
© GDP Labs 2017
Comments
Redundant Comments
The comment is not more informative than the code
// Throws an exception
// if the timeout is reached.
public synchronized void waitForClose(
final long timeoutMillis) throws Exception {
if(!closed) {
wait(timeoutMillis);
if(!closed)
throw new Exception(
"MockResponseSender could not be closed");
}
}
35
© GDP Labs 2017
Comments
Noise Comments
Only restate the obvious and provide no new information
/**
* Returns the day of the month.
* @return the day of the month.
*/
public int getDayOfMonth() {
return dayOfMonth;
}
36
© GDP Labs 2017
Comments
if (employee.isEligibleForFullBenefits())
37
© GDP Labs 2017
Comments
// format matched kk:mm:ss EEE, MMM dd, yyyy
Pattern timeMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*,
\\w* \\d*, \\d*");
INFORMATIVE
39
© GDP Labs 2017
Formatting
40
© GDP Labs 2017
Formatting
Variables
Should be declared as close to their usage as possible
41
© GDP Labs 2017
Formatting
Variables
Should be declared as close to their usage as possible
42
© GDP Labs 2017
Formatting
Instance Variables
Should be declared at the top of the class
43
© GDP Labs 2017
Formatting
Dependent Functions
Should be vertically close, and the caller should be above
the called
public void paySalary() {
calculateBonus(salary);
}
44
© GDP Labs 2017
Formatting
Conceptual Affinity
Certain bits of code want to be near other bits
public class Employee {
public void payTax() {
}
public void payOverdueTax(Date date) {
}
public void increaseSalary() {
}
public void decreaseSalary() {
}
}
45
© GDP Labs 2017
Formatting
Space
public float volume (float length,float width,float height) {
// code
}
46
© GDP Labs 2017
Formatting
Horizontal Alignment
47
© GDP Labs 2017
Formatting
Horizontal Alignment
48
© GDP Labs 2017
Formatting
Indentation
49
© GDP Labs 2017
Objects and Data
Structures
50
© GDP Labs 2017
Objects and Data Structures
Data structures expose data and have no behavior
Data structures make it easy to add functions without the
need to modify existing structures.
51
© GDP Labs 2017
Objects and Data Structures
Object expose behavior and hide data
Objects make it easy to add classes without the need to
modify existing functions.
52
© GDP Labs 2017
Objects and Data Structures
Law of Demeter
Given method f of class C, f should only call methods of:
● C
● An Object created by f
● An Object passed as an argument to f
● An instance variable of C
53
© GDP Labs 2017
Objects and Data Structures
Law of Demeter
Given method f of class C, f should only call methods of:
● C
public getPercentageFuelRemaining() {
return (fuel / getFuelCapacity() * 100);
}
}
54
© GDP Labs 2017
Objects and Data Structures
Law of Demeter
Given method f of class C, f should only call methods of:
● An Object created by f
55
© GDP Labs 2017
Objects and Data Structures
Law of Demeter
Given method f of class C, f should only call methods of:
● An Object passed as an argument to f
56
© GDP Labs 2017
Objects and Data Structures
Law of Demeter
Given method f of class C, f should only call methods of:
● An instance variable of C
57
© GDP Labs 2017
Error Handling
58
© GDP Labs 2017
Error Handling
Prefer exceptions to return error code
if (deletePage(page) == E_OK) {
if (registry.delete(page.reference) == E_OK) {
logger.log(“page deleted”);
} else {
logger.log(“delete registry failed”);
}
} else {
logger.log(“delete failed”);
}
59
© GDP Labs 2017
Error Handling
Prefer exceptions to return error code
try {
deletePage(page);
registry.delete(page.reference);
} catch (Exception e) {
logger.log(e.getMessage());
}
60
© GDP Labs 2017
Error Handling
62
© GDP Labs 2017
Class
Class Organization
Declare the constants, variables, and methods in this order:
public class TimeCalculator {
public static final int TIME = 25; // public static constant
public static int DURATION = 25; // private static variables
private int now; // private instance variables
public int addTime(int time) { // public functions
…
configTime = getConfigTime()
…
}
private int getConfigTime() { … } // private utilities
}
63
© GDP Labs 2017
Class
64
© GDP Labs 2017
Class
Refactored:
65
© GDP Labs 2017
Class
Cohesion
66
© GDP Labs 2017
public class CustomStack {
private int topOfStack = 0;
private int duration = 100;
List<Integer> elements = new LinkedList<Integer>();
public int size() { … }
public void push(int element) { … }
public int pop() throws PoppedWhenEmpty { … }
67
© GDP Labs 2017
public class Stack {
private int topOfStack = 0;
List<Integer> elements = new LinkedList<Integer>();
public int size() {
return topOfStack;
}
public void push(int element) {
topOfStack++;
elements.add(element);
}
public int pop() throws PoppedWhenEmpty {
if (topOfStack == 0)
throw new PoppedWhenEmpty();
int element = elements.get(--topOfStack);
elements.remove(topOfStack);
return element;
}
} HIGH COHESION
68
© GDP Labs 2017
Emergence
69
© GDP Labs 2017
Emergence
70
© GDP Labs 2017
public void scaleToOneDimension(…) {
…
RenderedOp newImage = ImageUtilities.getScaledImage(
image, scalingFactor, scalingFactor);
image.dispose();
System.gc();
image = newImage;
}
public synchronized void rotate(int degrees) {
RenderedOp newImage = ImageUtilities.getRotatedImage(
image, degrees);
image.dispose();
System.gc();
image = newImage;
} DUPLICATION
71
© GDP Labs 2017
public void scaleToOneDimension(…) {
…
replaceImage(ImageUtilities.getScaledImage(
image, scalingFactor, scalingFactor));
}
public synchronized void rotate(int degrees) {
replaceImage(ImageUtilities.getRotatedImage(
image, degrees));
}
private void replaceImage(RenderedOp newImage) {
image.dispose();
System.gc();
image = newImage;
}
DUPLICATION REFACTORED
72
© GDP Labs 2017
Give a man a fish and you feed
him for a day; teach a man to fish
and you feed him for a lifetime.
- Anne Thackeray Ritchie
73
Conclusion
1. Practice
Is there a set of simple practices that
can replace experience? Clearly not
2. Beware of Bad Code or Code Smell
3. Refactor
74
© GDP Labs 2017
Clean Code:
A Handbook of Agile
Software Craftsmanship
Robert C. Martin
©2009 | Prentice Hall
75
© GDP Labs 2017
A programmer who writes clean
code is an artist who can take a
blank screen through a series of
transformations until it is an
elegantly coded system
76
Thank You
Q&A
speakerdeck.com/gdplabs
77
We Are Hiring!
[email protected]
78
Cracking the
Coding Interview:
189 Programming
Questions and Solutions
79
© GDP Labs 2017
Extras
● Code Smells
● OO Design Principles
80
© GDP Labs 2017
Code Smells
81
© GDP Labs 2017
OO Design Principles: S.O.L.I.D
S Single-responsibility principle
O Open-closed principle
82
© GDP Labs 2017