0% found this document useful (0 votes)
2K views

Clean Code

The document discusses principles and best practices for writing clean code, including: 1) Code should have meaningful names through intention-revealing names and avoiding abbreviations. 2) Conditionals should be written positively and avoid magic numbers through intermediate variables. Complex conditionals should be encapsulated. 3) Functions should be small, do one thing, and follow the step-down rule of reading code from top to bottom.

Uploaded by

Teodor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2K views

Clean Code

The document discusses principles and best practices for writing clean code, including: 1) Code should have meaningful names through intention-revealing names and avoiding abbreviations. 2) Conditionals should be written positively and avoid magic numbers through intermediate variables. Complex conditionals should be encapsulated. 3) Functions should be small, do one thing, and follow the step-down rule of reading code from top to bottom.

Uploaded by

Teodor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 88

1

CLEAN CODE
CONTENTS
 THERE WILL BE CODE
 NAMING 2
 FUNCTIONS
 COMMENTS
 FORMATTING
 OBJECTS AND DATA STRUCTURES
 CLASSES AND SOLID PRINCIPLES

2
RESOURCES
 Clean Code – A Handbook of Agile Software Craftsmanship (Robert C. Martin)

 Clean Architecture (Robert C. Martin)


 The Clean Coder – The Code of Conduct for3 Professional Programmers (Robert C. Martin)
 Refactoring – Improving the Design of Existing Code (Martin Fowler)
 Domain Driven Design – Tackling Complexity in the Heart of Software (Eric Evans)

 Test-Driven Development By Example (Kent Beck)


 Extreme Programming Explained (Kent Beck)

 Design Patterns Elements of Reusable Object Oriented Software (Erich Gamma)


 Head First Design Patterns (Eric Freeman)

 Agile Software Development Principles, Patterns and Practices (Robert C. Martin)

 Spring Microservices In Action (John Carnell)


3
THERE WILL BE CODE
- Why do we need code? Soon all code will be generated
instead of written. We should be concerned about models
and requirements instead. Programmers simply4 won’t be
needed because business people will generate programs
from specifications.

- Nonsense! We will never get rid of code, because


code represents the details of the requirements. At
some level those details cannot be ignored or
abstracted; they have to be specified. And specifying
requirements in such detail that a machine can execute
them is programming. Such a specification is code.

4
WHY SHOULD I CARE?

Readability5 Flexibility

Efficiency Maintainability

Empathy
5
WRITING CODE IS THE ART OF WRITING A BOOK
“Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.”
– Martin Fowler
6
 ”Code is like humor. When you have to explain it, it’s bad.”
– Cory House

“First, solve the problem. Then, write the code.”


– John Johnson

“Programming is the art of telling another human what one


wants the computer to do”
– Donald Knuth

6
CLEAN CODE IS FOUNDATION
TDD
DDD
Design
Patter
7 ns

Refactoring

SOLID Code

Clean Code

7
THE MESS BUILDS QUIETLY

8
THE MESS BUILDS QUIETLY
A book or a newspaper article Well organized code
9
Paragraph Method
1
Heading1 1
Class1
=
Paragraph Method
Chapter 2 Packag 2
Paragraph e
Heading2 Method
1 Class2
1

9
CODE QUALITY MEASUREMENT

10

10
THE TOTAL COST OF OWNING A MESS

11

11
THE TOTAL COST OF OWNING A MESS

12

12
THE GRAND REDESIGN IN THE SKY

13

13
ATTITUDE

14

14
THE BOY SCOUT RULE
The Boy Scouts of America have a simple rule that we can apply to our
profession.
15
Leave the campground cleaner than you found it.
or
Leave the code cleaner than you found it.

15
MEANINGFUL NAMES
• Use intention-revealing names
• Avoid disinformation
• Make meaningful distinctions
16
• Use pronounceable names (avoid abbreviations)
• Use searchable names
• Avoid encodings
• Avoid mental mapping
• Class names (noun or noun phrase e.g. Customer)
• Method names (verb or verb phrase e.g. save)
• Pick one word per concept (fetch, retrieve and get equivalent for different classes?)
• Use solution domain names (use computer science terms, algorithm names, pattern
terms, math terms e.g. AccountVisitor = Visitor pattern)
• Use problem domain names

16
MEANINGFUL NAMES – WARNING SIGNS
• Watch out for:
• AND IF OR
17
• Avoid abbreviations

• Booleans
• Dirty: open, start, status, login
• Clean: isOpen, done, isActive, loggedIn

17
CONDITIONALS – BE POSITIVE
DON’T BE ANTI-NEGATIVE

18
if (!isNotNumber())

if (isNumber())

18
CONDITIONALS – TERNARY OPERATOR ELEGANCE

if (a < b) {
minVal = a; 19
} else {
minVal = b;
}

minVal = (a < b) ? a : b;

19
CONDITIONALS - AVOID BEING “STRINGLY” TYPED
BE STRONGLY TYPED

20
if(user.getType() == "admin")

if(user.getType() == UserType.ADMIN)

20
CONDITIONALS – AVOID MAGIC NUMBERS

if (age > 55) { int minRetirementAge = 55;


... 21 if (age > minRetirementAge) {
} ...
}

if (status == 2) { if (status > Status.ACTIVE)


... {
} ...
}

21
CONDITIONALS – INTERMEDIATE VARIABLES
if (employee.getAge() > 55 &&
employee.getYearsEmployed() > 10 &&
employee.isRetired()) 22
{
...
}

22
CONDITIONALS – INTERMEDIATE VARIABLES
int minRetirementAge = 55;
int minPensionEmploymentYears 23
= 10;
boolean eligibleForPension = employee.getAge() > minRetirementAge &&
employee.getYearsEmployed > minPensionEmploymentYears &&
employee.isRetired()
if (eligibleForPension) {
...
}

23
CONDITIONALS – ENCAPSULATE COMPLEX
CONDITIONALS
if ((fileExtension == "mp4" ||
fileExtension == "mpg" ||
24 &&
fileExtension == "avi")
(isAdmin || isActiveFile)) {
...
}

24
CONDITIONALS – ENCAPSULATE COMPLEX
CONDITIONALS
if (isValidFileRequest(fileExtension, isActiveFile, isAdmin))

private boolean isValidFileRequest(


25 isActiveFile, boolean isAdmin) {
String fileExtension, boolean
return (fileExtension == "mp4" ||
fileExtension == "mpg" ||
fileExtension == "avi") &&
(isAdmin || isActiveFile);
}

private boolean isValidFileRequest(


String fileExtension, boolean isActiveFile, boolean isAdmin) {
return isValidFileType(fileExtension) &&
isUserAllowedToViewFile(isAdmin, isActiveFile);
}
25
FUNCTIONS
We can describe the function by describing it as a brief TO paragraph:

The LOGO language used the keyword “TO” in the same way that Ruby and Python use “def.” So
26
every function began with the word “TO.” This had an interesting effect on the way functions were
designed.

TO RenderPageWithSetupsAndTeardowns, we check to see whether the page is a test page


and if so, we include the setups and teardowns. In either case we render the page in
HTML.

26
FUNCTIONS – STEPDOWN RULE
Reading Code from Top to Bottom: The Stepdown Rule

To include the setups and teardowns, we


27include setups, then we include the test page
content,
and then we include the teardowns.

To include the setups, we include the suite setup if this is a suite, then we include the
regular setup.
To include the suite setup, we search the parent hierarchy for the “SuiteSetUp” page
and add an include statement with the path of that page.
To search the parent. . .

27
FUNCTIONS – SMALL!
1. Functions should be small
2. They should be smaller than that
28
In the 80’s we used to say that a function should be no bigger than a screen-full.
(VT100 screens were 24 lines by 80 columns)

28
FUNCTIONS – DO ONE THING
FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL.
THEY SHOULD DO IT ONLY.
29

29
FUNCTIONS – MIXED LEVELS OF ABSTRACTION
public void makeBreakfast() {
addEggs();
cook();
30
wife.give(fryingPan.getContents(20, PERCENT));
self.give(fryingPan.getContents(80, PERCENT)); // huehuehue
}
private void addEggs() {
fridge
.getEggs()
.forEach(egg -> fryingPan.add(egg.open());
}
private void cook() {
fryingPan.mixContents();
fryingPan.add(salt.getABit());
fryingPan.mixContents();
}
30
FUNCTIONS – MIXED LEVELS OF ABSTRACTION
public void makeBreakfast() {
addEggs();
cook();
serve();
31
}
private void addEggs() {
fridge
.getEggs()
.forEach(egg -> fryingPan.add(egg.open());
}
private void cook() {
fryingPan.mixContents();
fryingPan.add(salt.getABit());
fryingPan.mixContents();
}
private void serve() {
wife.give(fryingPan.getContents(20, PERCENT));
self.give(fryingPan.getContents(80, PERCENT)); // huehuehue
}
31
FUNCTIONS – WHEN TO CREATE
Duplicatio Extract
n method
Excessive
32
Return
Indentatio
early
n
Unclear
Function Fail Fast
intent

> 1 task

Flag
32
arguments
FUNCTIONS – EXCESSIVE INDENTATION
ARROW SYMPTOM

if (...) {
33 if (...) {
if (...) {
switch (...) {
...

}
}
}
}
33
FUNCTIONS – HOW MANY ARGUMENTS ?
 Strive to 0 – 2

 > 3 params ?
34
 Primitive Obsession – Encapsulate into Class, group the params

 Raise params to instance level (method params will be class’ fields) by using
current class
or
create a separate class for this purpose (Extract Class refactoring technique)

34
FUNCTIONS - ARGUMENTS
• Monadic
boolean fileExists("MyFile");
35
• Flag arguments
render(true)
render(boolean isSuite)
renderForSuite() and renderForSingleTest()

• Dyadic
writeField(outputStream, name)

• Triads
assertEquals(message, expected, actual)

Natural cohesion and natural ordering rule

35
FUNCTIONS - ARGUMENTS
• Argument Objects
Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
36
• Argument Lists
String.format("%s worked %.2f hours.", name, hours);
public String format(String format, Object... args);

Functions that take variable arguments can be monads, dyads, or even triads.

void monad(Integer... args);


void dyad(String name, Integer... args);
void triad(String name, int count, Integer... args);

36
FUNCTIONS – GOOD NAMES
Choosing good names for a function can go a long way toward
• explaining the intent of the function
• and the order and intent of the arguments
37

write(name);
writeField(name);

assertEquals(expected, actual);
assertExpectedEqualsActual(expected, actual);

37
FUNCTIONS – HAVE NO SIDE EFFECTS
Side effects are lies.

Your function promises to do one thing, but it also does other hidden things.
38

38
FUNCTIONS – NO OUTPUT ARGUMENTS
• appenHeader(s);

39
• public void appendHeader(StringBuffer report);

• report.appendHeader();

39
FUNCTIONS – COMMAND QUERY SEPARATION
• public boolean set(String attribute, String value);

40
• if (set("username", "unclebob"))... ???

• if (attributeExists("username")) {
setAttribute("username", "unclebob");
...
}

40
FUNCTIONS – PREFER EXCEPTIONS TO RETURNING ERROR CODES

if (deletePage(page) == E_OK) {
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
41
logger.log("page deleted");
} else {
logger.log("configKey not deleted");
}
} else {
logger.log("deleteReference from registry failed");
}
} else {
logger.log("delete failed");
return E_ERROR;
}

41
FUNCTIONS – ERROR.JAVA DEPENDENCY MAGNET

public enum Error {


OK,
INVALID, 42
NO_SUCH,
LOCKED,
OUT_OF_RESOURCES,
WAITING_FOR_EVENT;
}

42
FUNCTIONS – EXTRACT TRY/CATCH BLOCKS

try {
deletePage(page); 43
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());

} catch (Exception e) {
logger.log(e.getMessage());
}

43
FUNCTIONS – EXTRACT TRY/CATCH BLOCKS
public void delete(Page page) {
try {
44
deletePageAndAllReferences(page);
}
catch (Exception e) {
logError(e);
}
}

private void deletePageAndAllReferences(Page page) throws Exception {…}


private void logError(Exception e) {…}

44
FUNCTIONS – DRY

45

45
FUNCTIONS – HOW DO WE WRITE THEM LIKE THIS?

46

46
FUNCTIONS – AVOID NULLPOINTER EXCEPTIONS

• Don’t return null


• Don’t pass null 47

47
FUNCTIONS – TYPES

• Procedural Programming - Functions \ Procedures


• OO Programming - Methods
48

48
SOFTWARE DEVELOPMENT PRINCIPLES

49
DRY
YAGNI and
WET
TMTWTDI

KISS

49
COMMENTS
“Don’t comment bad code - rewrite it.”
Brian W. Kernighan and P.50J. Plaugher

50
COMMENTS – EXPLAIN YOURSELF IN CODE
// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65)) 51

if (employee.isEligibleForFullBenefits())

51
COMMENTS – GOOD COMMENTS
AVOID THEM WHERE POSSIBLE
 Informative Comments
 Explanation of Intent
 Clarification 52
 Warning of Consequences
 TODO Comments
 Amplification
 Javadocs in Public APIs

52
COMMENTS – BAD COMMENTS
 Mumbling
 Redundant Comments
 Misleading Comments
 Mandated Comments 53
 Journal Comments
 Noise Comments
 Scary Noise
 Don’t Use a Comment When You Can Use a Function or a Variable
 Position Markers
 Closing Brace Comments
 Attributions and Bylines
 Commented-Out Code
 Nonlocal Information
 Too Much Information
 Function Headers
 Javadocs in Nonpublic Code
53
FORMATTING

54

54
FORMATTING

55

55
FORMATTING – VERTICAL OPENNESS
BETWEEN CONCEPTS
package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {


56
public static final String REGEXP = "'''.+?'''";

private static final Pattern pattern = Pattern.compile("'''(.+?)'''",


Pattern.MULTILINE + Pattern.DOTALL
);

public BoldWidget(ParentWidget parent, String text) throws Exception {


super(parent);

Matcher match = pattern.matcher(text);


match.find();

addChildWidgets(match.group(1));
}

public String render() throws Exception {


StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");

return html.toString();
56 }
}
FORMATTING – VERTICAL OPENNESS
BETWEEN CONCEPTS
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
57
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}

57
FORMATTING – VERTICAL DISTANCE
 Variable declarations (Mayfly variables)
 Instance variables
 Dependent Functions 58
 Conceptual Affinity

58
FORMATTING - VERTICAL DISTANCE
STEPDOWN RULE

private void serve() {


wife.give(fryingPan.getContents(20, PERCENT));
self.give(fryingPan.getContents(80, PERCENT)); // huehuehue
}

private void addEggs() { 59


fridge
.getEggs()
.forEach(egg -> fryingPan.add(egg.open());
}

private void cook() {


fryingPan.mixContents();
fryingPan.add(salt.getABit());
fryingPan.mixContents();
}

public void makeBreakfast() {


addEggs();
cook();
serve();
}

59
FORMATTING - VERTICAL DISTANCE
STEPDOWN RULE

public void makeBreakfast() {


addEggs();
cook();
serve();
}
60
private void addEggs() {
fridge
.getEggs()
.forEach(egg -> fryingPan.add(egg.open());
}

private void cook() {


fryingPan.mixContents();
fryingPan.add(salt.getABit());
fryingPan.mixContents();
}

private void serve() {


wife.give(fryingPan.getContents(20, PERCENT));
self.give(fryingPan.getContents(80, PERCENT)); // huehuehue
}

60
TEAM RULES

61

61
OBJECTS AND DATA STRUCTURES
• Data Structures (expose data, getters and setters)
• Objects (hide data and expose
62 behaviour)
• Hybrids (data + behaviour)

62
DATA ABSTRACTION
public class Point { public interface Point {
public double x; double getX();
public double y; 63
double getY();
} void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}

63
DATA ABSTRACTION
public interface Vehicle {
double getFuelTankCapacityInGallons();
64
double getGallonsOfGasoline();
}

public interface Vehicle {


double getPercentFuelRemaining();
}

64
DATA/OBJECT ANTI-SYMMETRY
public class Square {
public Point topLeft;
public double side; 65
}
public class Rectangle {
public Point topLeft;
public double height;
public double width;
}
public class Circle {
public Point center;
public double radius;
}

65
DATA/OBJECT ANTI-SYMMETRY
public class Geometry {
public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException
{
66
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
} else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}
66
}
DATA/OBJECT ANTI-SYMMETRY
public class Square implements Shape {
private Point topLeft;
private double side; 67
public double area() {
return side*side;
}
}
public class Rectangle implements Shape {
private Point topLeft;
private double height;
private double width;
public double area() {
return height * width;
}
67
}
DATA/OBJECT ANTI-SYMMETRY
public class Circle implements Shape {
private Point center;
private double radius; 68
public final double PI = 3.141592653589793;
public double area() {
return PI * radius * radius;
}
}

68
DATA/OBJECT ANTI-SYMMETRY
Procedural Code – easy to add new functions without changing the existing data structures
OO Code – easy to add new classes without changing existing functions
69
The complement is also true:

Procedural Code – hard to add new data structures because all the functions must change
OO Code – hard to add new functions because all the classes must change

69
LAW OF DEMETER
A module should not know about the innards
70
of the objects it manipulates.

An object should not expose internal


structure through accessors.

70
LAW OF DEMETER
A method f of a class C should only call the methods of these:
71
• C
• An object created by f
• An object passed as an argument to f
• An object held in an instance variable of C

71
LAW OF DEMETER

72

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

72
TRAIN WRECKS
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
73
final String outputDir = scratchDir.getAbsolutePath();

73
HIDING STRUCTURE
ctxt.getAbsolutePathOfScratchDirectoryOption();

or 74

ctx.getScratchDirectoryOption().getAbsolutePath();

74
HIDING STRUCTURE
ctxt.getAbsolutePathOfScratchDirectoryOption();

... 75

String outFile = outputDir + "/" + className.replace('.', '/') + ".class";


FileOutputStream fout = new FileOutputStream(outFile);
BufferedOutputStream bos = new BufferedOutputStream(fout);

75
HIDING STRUCTURE
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

76

76
HYBRIDS
Hybrid = Object + Data Structure
77
• Hard to add new functions
• Hard to add data structures

77
DATA STRUCTURE TYPES
• Data Transfer Objects
• Active Record 78

78
CLASSES
Classes Should Be Small!
79

79
CLASSES – SINGLE RESPONSIBILITY PRINCIPLE

80

80
CLASSES – COHESION SHOULD BE HIGH
• Classes should have a small number of instance variables.
• Each of the methods of a class should manipulate one or more of those
81
variables.

81
SOLID

82

82
OPEN / CLOSED
Software entities (classes, modules, functions, etc.) should be
open for extension, but closed83for modification.

A class is closed, since it may be compiled, stored in a library,


baselined, and used by client classes. But it is also open, since any
new class may use it as parent, adding new features. When a
descendant class is defined, there is no need to change the original
or to disturb its clients.

83
LISKOV SUBSTITUTION
Let Φ(x) be a property provable about objects x of type T.
Then Φ(y)should be true for objects y of
84
type S where S is a subtype
of T.

84
INTERFACE SEGREGATION
Clients should not be forced to depend upon interfaces that they do
not use. 85

Many client-specific interfaces are better than one general-purpose interface.

85
INTERFACE SEGREGATION

86

86
DEPENDENCY INVERSION
1. High-level modules should not depend on low-level modules. Both should
depend on abstractions. 87

2. Abstractions should not depend on details. Details should depend on


abstractions

87
THANK
88 YOU

You might also like