Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Clean Code
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
GDP Labs
March 24, 2017
Programming
1.8k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Clean Code
GDP Labs
March 24, 2017
More Decks by GDP Labs
See All by GDP Labs
Cracking the Coding Interview 6th Edition
gdplabs
14
29k
Top Strategic Trends in IT Industry
gdplabs
0
660
React Introduction
gdplabs
1
630
Clean Architecture
gdplabs
8
9.9k
ECML PKDD 2017
gdplabs
1
520
KDD 2017
gdplabs
2
460
O'reilly AI Conference
gdplabs
5
670
The AI Summit
gdplabs
3
360
Reinventing KASKUS & GDP Labs
gdplabs
1
440
Other Decks in Programming
See All in Programming
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
170
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
240
Contextとはなにか
chiroruxx
1
320
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
130
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
OSもどきOS
arkw
0
560
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
7
4.4k
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
140
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
200
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
10
4.1k
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
2k
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
2
640
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
3.1k
Producing Creativity
orderedlist
PRO
348
40k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
720
We Are The Robots
honzajavorek
0
250
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.4k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
220
The Mindset for Success: Future Career Progression
greggifford
PRO
0
360
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
160
Music & Morning Musume
bryan
47
7.2k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
200
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
330
Transcript
Clean Code Benedikus H Tjuatja David Setyanugraha Fakhri Lutvianes Advendianto
None
3 Overview • Issues • Solution • Conclusion © GDP
Labs 2017
4 Issues • Bad Code • Great vs Bad Company
• Who is Responsible? ! © GDP Labs 2017
5 • 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 Bad Code © GDP Labs 2017
6 © GDP Labs 2017 • LeBlanc’s Law: Later equals
never ◦ They never go back to fix the bad code • Sink projects, careers and companies • Example: netscape and myspace Bad Code
7 Death Spiral: The downward, corkscrew-motion of a disabled aircraft
which is unrecoverably headed for a crash
8 Great Company vs Bad Company © GDP Labs 2017
9 © GDP Labs 2017 Great Company vs Bad Company
10 © GDP Labs 2017 Great Company vs Bad Company
11 • BOD? • Management? • Program Manager? • Product
Manager? • Unrealistic schedule? Who is Responsible for Bad Code? Unprofessional Software Engineers. It is your job to defend your code with equal passion. © GDP Labs 2017
12 It is a crime if a surgeon does not
“clean” his hands
For the things we have to learn before we can
do them, we learn by doing them - Aristotle 13
14 Solution • Naming • Function • Comment • Formatting
• Objects and Data Structures • Error Handling • Class • Emergence © GDP Labs 2017
15 Naming The name of a variable, function, or class,
should answer all the big questions. It should tell you why it exists, what it does, and how it is used. - Robert C. Martin ” “ © GDP Labs 2017
16 public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1; } Say that we’re working in a mine sweeper game. Naming © GDP Labs 2017
17 Use intention-revealing names public List<int[]> getFlaggedCells() { List<int[]> flaggedCells
= new ArrayList<int[]>(); for (int[] cell : gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); return flaggedCells; } Naming © GDP Labs 2017
18 Use intention-revealing names public List<Cell> getFlaggedCells() { List<Cell> flaggedCells
= new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells; } Naming © GDP Labs 2017
19 Avoid misleading and unmeaningful distinctions int a = l;
if (O == l) a = O1; else l = 01; private void copyChars(char a1[], char a2[]) { for (int i = 0; i < a1.length; i++) { a2[i] = a1[i]; } } Naming © GDP Labs 2017 MISLEADING UNMEANINGFUL DISTINCTIONS
20 public class DtaRcrd102 { private Date genymdhms; private Date
modymdhms; private final String pszqint = ”102”; /* … */ } CAN YOU PRONOUNCE THEM? Naming © GDP Labs 2017
21 Use pronounceable names public class Customer { private Date
generationTimestamp; private Date modificationTimestamp; private final String recordId = ”102”; /* … */ } Naming © GDP Labs 2017
22 Classes and objects should be noun, methods should be
verb public class Point { private int x, y; public Point(int x, int y) {...} public int getX() {...} public void setX(int x) {...} public int getY() {...} public void setY(int y) {...} } Naming © GDP Labs 2017
23 public class Circle { double radius; String color; public
double getRadius() {...} public String fetchColor() {...} public double retrieveArea() {...} } GET OR FETCH OR RETRIEVE? Naming © GDP Labs 2017
24 Pick one word per concept public class Circle {
double radius; String color; public double getRadius() {...} public String getColor() {...} public double getArea() {...} } Naming © GDP Labs 2017
25 for (int i=0; i<34; i++) { s += (t[i]*4)/5;
} if single-letter names and numeric constants are used across body of text, they are not easy to locate NOT EASY TO SEARCH Naming © GDP Labs 2017
26 Use searchable names int realDaysPerIdealDay = 4; const int
WORK_DAYS_PER_WEEK = 5; int sum = 0; for (int i=0; i < NUMBER_OF_TASKS; i++) { int realTaskDays = taskEstimate[i] * realDaysPerIdealDay; int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } Naming © GDP Labs 2017
27 Function The first rule of functions is that they
should be small. The second rule of functions is that they should be smaller than that. - Robert C. Martin ” “ © GDP Labs 2017
28 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
29 Do one thing public static String renderPageWithSetupsAndTeardowns( PageData pageData,
boolean isSuite) throws Exception { if (isTestPage(pageData)) includeSetupAndTeardownPages(pageData, isSuite); return pageData.getHtml(); } Function is doing more than “one thing” if you can extract another function from it with a name that is not merely a restatement Function © GDP Labs 2017
30 public boolean set(String attribute, String value); if (set(”username”, ”unclebob”))
Is it asking whether the “username” attribute was previously set to “unclebob”? Or is it asking whether the “username” attribute was successfully set to “unclebob”? Function © GDP Labs 2017
31 Do something or answer something, but not both if
(attributeExists(”username”)) { setAttribute(”username”, ”unclebob”); } Function © GDP Labs 2017
32 Transformational function should appear as the return value StringBuffer
transform(StringBuffer in) void transform(StringBuffer out) These implementation simply returns the input argument Function © GDP Labs 2017
33 Avoid too many function parameters Car createCar(Wheel wheel, Engine
engine); Car createCar(float wheelDiameter, float wheelColor, float wheelMaterial, float wheelManufacturer, String engineType, String engineColor, String engineManufacturer); Too many parameters will make function hard to be understood and maintained. Function © GDP Labs 2017
34 Comments Good code is its own best documentation. As
you’re about to add a comment, ask yourself, ‘How can I improve the code so that this comment isn’t needed?' - Steve McConnell ” “ © GDP Labs 2017
// 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 Comments © GDP Labs 2017 Redundant Comments The comment is not more informative than the code
/** * Returns the day of the month. * @return
the day of the month. */ public int getDayOfMonth() { return dayOfMonth; } 36 Comments © GDP Labs 2017 Noise Comments Only restate the obvious and provide no new information
Explain yourself in code 37 // Check to see if
the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) if (employee.isEligibleForFullBenefits()) Comments © GDP Labs 2017
// format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher
= Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*"); INFORMATIVE public void writeJournal(Diary diary) { for (Thread thread : threadList) { thread.run(() -> { // Prevent original object to be modified Diary copyOfDiary = new Diary(diary); write(copyOfDiary); }); } } EXPLANATION OF INTENT 38 Comments © GDP Labs 2017
public static SimpleDateFormat makeStandardHttpDateFormat() { //SimpleDateFormat is not thread safe,
//so we need to create each instance independently. SimpleDateFormat df = new SimpleDateFormat( ”EEE, dd MMM yyyy HH:mm:ss z”); df.setTimeZone(TimeZone.getTimeZone(”GMT”)); return df; } WARNING OF CONSEQUENCES 39 Comments © GDP Labs 2017
Formatting 40 © GDP Labs 2017
Variables Should be declared as close to their usage as
possible 41 public void paySalary(Employee employee) { float bonus; float totalSalary; bonus = calculateBonus(employee.getSalary()); totalSalary = bonus + employee.getSalary(); sendMoney(employee, totalSalary); } Formatting © GDP Labs 2017
42 Variables Should be declared as close to their usage
as possible Formatting public void paySalary(Employee employee) { float bonus; bonus = calculateBonus(employee.getSalary()); float totalSalary; totalSalary = bonus + employee.getSalary(); sendMoney(employee, totalSalary); } © GDP Labs 2017
43 public class Employee { private String name; private String
id; private float salary; public void getName() { … } } Instance Variables Should be declared at the top of the class Formatting © GDP Labs 2017
44 public void paySalary() { calculateBonus(salary); } private float calculateBonus(float
salary) { return (salary / 10); } Dependent Functions Should be vertically close, and the caller should be above the called Formatting © GDP Labs 2017
45 public class Employee { public void payTax() { }
public void payOverdueTax(Date date) { } public void increaseSalary() { } public void decreaseSalary() { } } Conceptual Affinity Certain bits of code want to be near other bits Formatting © GDP Labs 2017
public float volume (float length,float width,float height) { // code
} 46 public float volume(float length, float width, float height) { // code } Space Formatting © GDP Labs 2017
47 public class WebService { private Request request; private Response
response; private FitnesseContext context; protected long requestTimeLimit; } Horizontal Alignment Formatting © GDP Labs 2017 DIFFICULT TO MAINTAIN
public class WebService { private Request request; private Response response;
private FitnesseContext context; protected long requestTimeLimit; } 48 Horizontal Alignment Formatting © GDP Labs 2017
public String functionName() {return "";} public String functionName() { return
""; } 49 Indentation Formatting © GDP Labs 2017
Objects and Data Structures 50 © GDP Labs 2017
51 public class Point { public double x; public double
y; } Data structures expose data and have no behavior Data structures make it easy to add functions without the need to modify existing structures. Objects and Data Structures © GDP Labs 2017
52 public class Vehicle { public getFuelCapacity() {...} public getPercentageFuelRemaining()
{...} } Object expose behavior and hide data Objects make it easy to add classes without the need to modify existing functions. Objects and Data Structures © GDP Labs 2017
53 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 Objects and Data Structures © GDP Labs 2017
54 public class Vehicle { public getFuelCapacity() {...} public getPercentageFuelRemaining()
{ return (fuel / getFuelCapacity() * 100); } } Law of Demeter Given method f of class C, f should only call methods of: • C Objects and Data Structures © GDP Labs 2017
55 public void registryEmployee() { Employee newEmployee = new Employee();
registry.createEmplyeeId(newEmployee); employeeIdList.add(newEmployee.getId()); } Law of Demeter Given method f of class C, f should only call methods of: • An Object created by f Objects and Data Structures © GDP Labs 2017
56 public void calculateEmployeeBonus(Employee employee) { return (employee.getSalary() / 10);
} Law of Demeter Given method f of class C, f should only call methods of: • An Object passed as an argument to f Objects and Data Structures © GDP Labs 2017
57 public class Car { private Engine engine; public String
getCarFuelType() { return engine.getFuelType(); } } Law of Demeter Given method f of class C, f should only call methods of: • An instance variable of C Objects and Data Structures © GDP Labs 2017
Error Handling 58 © GDP Labs 2017
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 Prefer exceptions to return error code Error Handling © GDP Labs 2017
try { deletePage(page); registry.delete(page.reference); } catch (Exception e) { logger.log(e.getMessage());
} 60 Prefer exceptions to return error code Error Handling © GDP Labs 2017
• Functions should do one thing and error handling is
one thing ◦ Implement the normal flow of the function • Don’t return NULL ◦ So other function doesn’t need to implement error handling • Don’t pass NULL ◦ So other function doesn’t need to implement error handling 61 Error Handling © GDP Labs 2017
Class 62 © GDP Labs 2017
63 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 } Class Class Organization Declare the constants, variables, and methods in this order: © GDP Labs 2017
Classes should be small! • The first rule is that
they should be small • The second rule is that they should be smaller than that Single Responsibility Principle (SRP) • A class or module should have one, and only one, reason to change • SRP is one of the more important concept in OO design 64 Class © GDP Labs 2017
Refactored: 65 public class TimeCalculator { … public int addTime(int
time) { … } … } public class UserConfiguration { … public int getConfigTime() { … } … } Class © GDP Labs 2017
Cohesion • Classes should have a small number of instance
variables • The more variables (or class modules) a method manipulates the more cohesive that method is to its class. • A class in which each variable is used by each method is maximally cohesive. • Maintaining cohesion results in many small classes 66 Class © GDP Labs 2017
67 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 { … } public void sleep() { TimeUnit.SECONDS.sleep(duration); } public void log() { … logger.log(Level.WARNING, ”This is a warning!”); … } … } LOW COHESION © GDP Labs 2017
68 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 © GDP Labs 2017
Emergence 69 © GDP Labs 2017
• Runs all the tests. To make it easy, make
sure: ◦ Low coupling ◦ SRP • Contains no duplication (Refactoring) • Expresses the intent of the programmer (Refactoring) ◦ Easy to read and understand • Minimizes the number of classes and methods (Refactoring) ◦ But don’t take it too far 70 Emergence © GDP Labs 2017
71 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 © GDP Labs 2017
72 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 © 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
74 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 © 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
77 Thank You Q & A speakerdeck.com/gdplabs
78 We Are Hiring!
[email protected]
Cracking the Coding Interview: 189 Programming Questions and Solutions Gayle
Laakmann McDowell ©2015 | CareerCup 79 © GDP Labs 2017
80 Extras • Code Smells • OO Design Principles ©
GDP Labs 2017
• Large class • Feature envy • Inappropriate intimacy •
Refused bequest • Lazy class • Excessive use of literals • Cyclomatic complexity • Data clump • Orphan variable or constant class 81 • Duplicated code • Too many parameters • Long method • Excessive return of data • Excessively long identifiers • Excessively short identifiers Code Smells © GDP Labs 2017
Single-responsibility principle Open-closed principle Liskov substitution principle Interface segregation principle
Dependency Inversion Principle 82 OO Design Principles: S.O.L.I.D S O L I D © GDP Labs 2017