Clean Code

Download as pdf or txt
Download as pdf or txt
You are on page 1of 48

Clean Code

@mariosangiorgio
Why?
Goals

Readable, maintainable and


extendable code
Meaningful names
A simple example
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
A simple example
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}

This code is quite simple but


what does it do?
A simple example
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}

This code is quite simple but


what does it do?
Looking at it we can’t tell
what it is actually doing!
A simple example
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for (int[] cell : gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(x);
return flaggedCells;
}

Is this code any better?


A simple example
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(x);
return flaggedCells;
}

What about this?


A simple example
What we have done:
A simple example
What we have done:
used intention flaggedCells
revealing names rather than list1
A simple example
What we have done:
used intention flaggedCells
revealing names rather than list1
replaced magic numbers cell[STATUS_VALUE]
with constants rather than x[0]
A simple example
What we have done:
used intention flaggedCells
revealing names rather than list1
replaced magic numbers cell[STATUS_VALUE]
with constants rather than x[0]
created an appropriate Cell cell rather
abstract data type than int[] cell
Another example
int d;
What does it mean?
Days? Diameter? ...
Another example
int d;
What does it mean?
Days? Diameter? ...

int d; //elapsed time in days


Is this any better?
Another example
int d;
What does it mean?
Days? Diameter? ...

int d; //elapsed time in days


Is this any better?

int elapsedTimeInDays;
What about this?
Functions
Do one thing
public
bool
isEdible()
{


if
(this.ExpirationDate
>
Date.Now
&&







this.ApprovedForConsumption
==
true
&&







this.InspectorId
!=
null)
{




return
true;


}
else
{




return
false;


}
}

How many things is the function doing?


Do one thing
public
bool
isEdible()
{


if
(this.ExpirationDate
>
Date.Now
&& 1.check expiration







this.ApprovedForConsumption
==
true
&&







this.InspectorId
!=
null)
{
2.check approval




return
true; 3.check inspection


}
else
{




return
false; 4.answer the request


}
}

How many things is the function doing?


Do one thing
public
bool
isEdible()
{




return
isFresh()



&&


isApproved()
&&
Now the function is doing one thing!


isInspected();
}
Do one thing
public
bool
isEdible()
{




return
isFresh()



&&


isApproved()
&&
Now the function is doing one thing!


isInspected();
}

A change in the specifications turns


into a single change in the code!
Don’t mix levels of abstraction

public
void
doTheDomesticThings()
{




takeOutTheTrash(); public
void
doTheDomesticThings()
{




walkTheDog(); 



takeOutTheTrash();




for
(Dish
dish
:
dirtyDishStack)
{ 



walkTheDog();







sink.washDish(dish); 



doTheDishes();







teaTowel.dryDish(dish); }




}
}

Which one is easier to read and understand?


Separate commands and queries

Commands should Queries should


only do something only answer
(One thing) something
public
class
Car{




private
boolean
isOn





public
void
turnOn(){








isOn
=
true;




} AVOID SIDE EFFECTS!




public
boolean
isOn(){








return
isOn;




}
}
Use exceptions
public
int
foo(){



...
}

public
void
bar(){



if(foo()
==
OK)






...



else






//
error
handling
}
Use exceptions
public
int
foo(){
Errors have to be encoded



...
}

public
void
bar(){



if(foo()
==
OK)






...



else






//
error
handling
}
Use exceptions
public
int
foo(){
Errors have to be encoded



...
}

public
void
bar(){
Checks (when performed)



if(foo()
==
OK) require a lot of code






...



else






//
error
handling
}
Use exceptions
public
int
foo(){
Errors have to be encoded



...
}

public
void
bar(){
Checks (when performed)



if(foo()
==
OK) require a lot of code






...



else






//
error
handling
} It’s harder to extend such
programs
Use exceptions
public
void
foo()







throws
FooException{



...
}

public
void
bar(){



try{






foo();






...



}
catch(FooException){






//
error
handling



}
}
Use exceptions
public
void
foo()







throws
FooException{ No need to mix return



...
}
values and control values
public
void
bar(){



try{






foo();






...



}
catch(FooException){






//
error
handling



}
}
Use exceptions
public
void
foo()







throws
FooException{ No need to mix return



...
}
values and control values
public
void
bar(){



try{ Cleaner syntax






foo();






...



}
catch(FooException){






//
error
handling



}
}
Use exceptions
public
void
foo()







throws
FooException{ No need to mix return



...
}
values and control values
public
void
bar(){



try{ Cleaner syntax






foo();






...



}
catch(FooException){






//
error
handling Easier to extend



}
}
Don’t Repeat Yourself
public
void
bar(){


String
[]
elements
=
{“A”,
“B”,
“C”};
public
void
bar(){


foo(“A”);


for(String
element
:
elements){


foo(“B”);




foo(element);


foo(“C”);


}
}
}

DO NOT EVER COPY AND PASTE CODE


Don’t Repeat Yourself
public
void
bar(){


String
[]
elements
=
{“A”,
“B”,
“C”};
public
void
bar(){


foo(“A”);


for(String
element
:
elements){


foo(“B”);




foo(element);


foo(“C”);


}
}
}

Logic to handle the elements


it’s written once for all
DO NOT EVER COPY AND PASTE CODE
Comments
Explain yourself in the code

Which one is clearer?

// Check to see if the employee is eligible for full benefits


if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

if (employee.isEligibleForFullBenefits())
Comments
GOOD BAD

API Documentation Redundant


Explanation of intent Obsolete
Clarification Code commented-out
Other code smells
What we don’t want to see in your code
The bloaters
Something in your code grow too large

Long methods Single responsibility


and large classes principle violated

Primitive obsession
It is a symptom of bad
and too much
design
parameters
Primitive obsession
public Class Car{
private int red, green, blue;

public void paint(int red, int green, int blue){


this.red = red;
this.green = green;
this.blue = blue;
}
}

public Class Car{


private Color color;

public void paint(Color color){


this.color = color;
}
}
The OO abusers
Object orientation is not fully exploited

Switch statements on It is better to use


objects polymorphism

Refused bequest
Poor class hierarchy
Alternative classes with design
different interfaces
Switch vs polymorphism
public Money calculatePay(Employee e)
throws InvalidEmployeeType{
switch(e.type){
case COMMISSIONED:
return calculateCommissionedPay(e);
case HOURLY:
return calculateHourlyPay(e);
case SALARIED:
return calculateSalariedPay(e);
default:
throw new
InvalidEmployeeType(e.type);
}
}

public abstract class Employee{


public abstract Money calculatePay();
}
Refused bequest
Subclass doesn’t use superclass methods and attributes
public abstract class Employee{
private int quota;
public int getQuota();
...
}

public class Salesman extends Employee{ ... }

public class Engineer extends Employee{


...
public int getQuota(){
throw new NotSupportedException();
}
}

Engineer does not use quota. It should be


pushed down to Salesman
The change preventers
Something is making hard to change the code

A class has to be changed


Divergent change
in several parts

A single change requires


Shotgun surgery
changes in several classes
The dispensables
The code contains something unnecessary

A class is not doing


Class not providing logic
enough

Unused or
It isn’t something useful
redundant code
The couplers
Some classes are too tightly coupled

Feature Envy Misplaced responsibility

Classes should know as little


Inappropriate Intimacy
as possible about each other

Message Chains Too complex data access


Feature Envy
public class Customer{
private PhoneNumber mobilePhone;

...

public String getMobilePhoneNumber(){


return “(” +
mobilePhone.getAreaCode() + “)” +
mobilePhone.getPrefix() + “-” +
mobilePhone.getNumber();
}
}
Feature Envy
public class Customer{
private PhoneNumber mobilePhone;

...

public String getMobilePhoneNumber(){


return “(” +
mobilePhone.getAreaCode() + “)” +
mobilePhone.getPrefix() + “-” +
mobilePhone.getNumber();
}
}

public String getMobilePhoneNumber(){


return mobilePhone.toFormattedString();
}
Message chains
a.getB().getC().getD().getTheNeededData()

a.getTheNeededData()

Law of Demeter: Each unit should


only talk with friends

You might also like