Cleancode 110520031623 Phpapp02
Cleancode 110520031623 Phpapp02
Arturo
Two reasons
1.You are a
porgarmmer
2.You want to
The Boy Scout Rule
Robert
C.
Martn
Uncle
Elegance
I lke
elgant
my
Cl ean
anthng
d
co
co de
de
effcentwel
to be
Simple, direct, prose
Clean
and
co
de
Clean s
w-
e
lldrec
sm e
p
l
codet
wrtte
L iterat
e
Clean
era
code
Clean d
can blt
ee r
at
code
Dave e
Care
Clean
oloks lke
by
code
t was
osmeone
al ways
wrtt en
Small, expressive, simple
Reduced
hgh
anduplcat
d early
exsm ple n
pressve
buldn
onarbstracton
esr
g ofr
What you expected
You
workng
wheknown
e
ron
ads celtuan
rns
epr
achye
ott
y
u a
e
xr
e
p
ec
et
o
cmut
deuchto
o
rutned
be
Meaningful Names
Use n
Itenton-
public List<int[]> getThem() {
Revealng Names
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
Meaningful Names
Use n
Itenton-
public List<Cell> getFlaggedCells() {
Revealng Names
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
Meaningful Names
Avod Dsnofm
int a
r aton
= l;
if (O == l)
a = O1;
else
l = 01;
Make
Mean
Meaningful Names
Use Pornounceable
class DtaRcrd102 {
Names
private Date genymdhms;
private Date
modymdhms;
private final String
pszqint = "102";
/* ... */
};
Meaningful Names
Use Pornounceable
class Customer {
Names
private Date generationTimestamp;
private Date modificationTimestamp;;
private final String recordId = "102";
/* ... */
};
Meaningful Names
Use Searchable
Names
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
Meaningful Names
Use Searchable
int realDaysPerIdealDay = 4;
Names
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] *
realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
Meaningful Names
Mem
ber Prefxes
public class Part {
private String m_dsc; // The textual description
(Avod encodngs)
}
void setName(String name) {
m_dsc = name;
Hungaran Noatton
A
(vod encodngs)
PhoneNumber phoneString;
Meaningful Names
Mem
ber Prefxes
public class Part
{ String
(Avod encodngs)
description;
void setDescription(String description) {
this.description = description;
}
}
Hungaran
Noatton A(vod encodngs)
Meaningful Names
Avod Menat l
for (a = 0; a < 10; a++)
Mappng
for (b = 0; b < 10; b++)
Cal ss Names
Manager, Processor, Data, Info
Meaningful Names
Avod Menat l
for (i = 0; i < 10; i++)
Mappng
for (j = 0; j < 10; j++)
Cal ss Names
Customer, WikiPage, Account,
AddressParser
// a class name should not be a
verb
Meaningful Names
Method Names
postPayment, deletePage, save
// methods should have verb or verb phrase names
Complex fulcrumPoint =
Complex.fromRealNumber(23.0);
// is generally better than
Complex fulcrumPoint = new
Complex(23.0);
Meaningful Names
Pck One Word
fetch, retrieve, get // as equivalent
per Concept
methods
Don’t Pun
// avoid using the same word for two purposes
Meaningful Names
Use Soluton
AccountVisitor, JobQueue
Do man Names
// people who read your code will be programmers
Add Meanngful
Conet xt
firstName, lastName, street, city, state, zipcode
// a better solution
addrFirstName, addrLastName, addrState
Meaningful Names
Don’t Add
Address
Gratutous
// is a fine name for a class
AccountAddress, CustomerAddress
// are fine names for instances of the class Address
Context
// but could be poor names for classes
Do One Thng
// FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL.
// THEY SHOULD DO IT ONLY.
Functions
One Level of
// high level of abstraction
Abstracton per
getHtml()
// intermediate level of
abstraction
Functon
String pagePathName =
PathParser.render(pagePat
h);
Readng Code
Functions
Swtch
class Employee...
Statemenst
int payAmount() {
switch
(getType()) {
case EmployeeType.ENGINEER:
return _monthlySalary;
case EmployeeType.SALESMAN:
return _monthlySalary + _commission;
case EmployeeType.MANAGER:
return _monthlySalary + _bonus;
default:
throw new
Exception("Incorrect
Employee");
}
Functions
Swtch
class EmployeeType...
Statemenst
abstract int payAmount(Employee emp);
class Salesman...
int payAmount(Employee emp) {
return emp.getMonthlySalary() + emp.getCommission();
}
class Manager...
int payAmount(Employee emp) {
return emp.getMonthlySalary() + emp.getBonus();
}
Functions
Use
testableHtml => includeSetupAndTeardownPages
Descrp
includeSetupAndTeardownPages, includeSetupPages,
includeSuiteSetupPage, includeSetupPage
// what happened to
tve
includeTeardownPages, includeSuiteTeardownPage,
includeTeardownPage
Func
Nm
aes ton A
rgu
m ent
s
// the ideal number of arguments for a function is zero
Functions
Common
// if a function is going to transform its input argument,
Monadc
// the transformation should appear as the return value
Fom
rs
void transform(StringBuffer out)
Fal g
Functions
Common
// asking a question about that argument
Monadc
boolean fileExists(“MyFile”)
Fom
rs
// event, use the argument to alter the state of the system
void passwordAttemptFailedNtimes(int attempts)
Fal g Argu
ments
renderForSuite()
renderForSingleTest()
Functions
Dyadc
writeField(name)
Functon
// is easier to understand than
writeField(outputStream, name)
// perfectly reasonable
s
Point p = new Point(0,0)
// problematic
assertEquals(expected, actual)
Trads
assertEquals(message,
expected, actual)
Functions
Argumen
Circle makeCircle(double x, double y, double radius);
t Objects
Circle makeCircle(Point center, double radius);
Verbs and
Keywodrs
write(name)
writeField(name)
assertEquals(expected, actual)
Functions
Have No
// do something or answer something, but not both
Sde
public boolean set(String attribute, String value);
setAndCheckIfExists
Eff
ects
if (attributeExists("username"))
{ setAttribute("username",
"unclebob");
...
}
Functions
Don’t
// duplication may be the root of all evil in software
R epeat
Structured Porgarmmng
Yousrelf (DRY)
// Edsger Dijkstra’s rules
//
//
one entry
one exit
// functions small
// occasional multiple return, break, or continue statement
// can sometimes even be more expressive Dijkstra’s rules
Comments
Comments Do Not
// don’t comment bad code, rewrite it!
M a
k e Up o
f r B
ad
Explan Yourself n
C o
de
Code
// Check to see if the employee is eligible for full
benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
Comments (good
)
Legal Commen
st
// Copyright (C) 2011 by Osoco. All rights reserved.
// Released under the terms of the GNU General Public
License // version 2 or later.
nIofrmatve Comments
// Returns an instance of the Responder being tested.
protected abstract Responder responderInstance();
// renaming the function: responderBeingTested
Explanaton of Intent
//This is our best attempt to get a race condition
//by creating large number of threads.
for (int i = 0; i < 25000; i++) {
WidgetBuilderThread
widgetBuilderThread =
new WidgetBuilderThread(widgetBuilder, text, failFlag);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}
Calrfcaton
assertTrue(a.compareTo(b) == -1); // a < b
assertTrue(b.compareTo(a) == 1); // b > a
Comments (good)
Warnng of
public static SimpleDateFormat makeStandardHttpDateFormat() {
Consequences
//SimpleDateFormat is not thread safe,
//so we need to create each instance independently.
SimpleDateFormat df = new SimpleDateFormat("dd MM yyyy");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
TODO Comments
//TODO-MdM these are not needed
// We expect this to go away when we do the checkout model
Comments (good
)
Amp
cfalo
tn
String listItemContent = match.group(3).trim();
// the trim is real important. It removes the starting
// spaces that could cause the item to be recognized
// as another list.
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
Javadocs n
// there is nothing quite so helpful and satisfying
Publc
// as a well-described public API
Comments (bad
)
Mumnbgl
try {
String propertiesPath = propertiesLocation + "/" +
PROPERTIES_FILE;
FileInputStream propertiesStream =
new FileInputStream(propertiesPath);
loadedProperties.load(propertiesStream);
}
catch(IOException e) {
// No properties files means all
defaults are loaded
}
Comments (bad
)
Redundant
// Utility method that returns when this.closed is true.
Commen st
// 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("MockR
esponseSender
c
o
u
Comments (bad
)
Redundant
/**
Commen st
* The processor delay for this component.
*/
protected int backgroundProcessorDelay = -1;
/**
* The lifecycle event support for this component.
*/
protected LifecycleSupport lifecycle =
new LifecycleSupport(this);
/**
* The container event listeners for this Container.
*/
protected ArrayList listeners = new ArrayList();
Comments (bad
)
Mandate
/**
d
* @param title The title of the CD
* @param author The author of the CD
* @param tracks The number of tracks on the CD
* @param durationInMinutes The duration of the CD in minutes
Comments
*/
public void addCD(String title, String author,
int tracks, int durationInMinutes) {
CD cd = new CD();
cd.ti
tle = title;
cd.author = author;
cd.tracks =
tracks;
cd.du
Comments (bad
)
Journal Commen
*
st
Changes (from 11-Oct-2001)
*
* 11-Oct-2001 : Re-organised the class and moved it to new
* package com.jrefinery.date (DG);
* 05-Nov-2001 : Added a getDescription() method, and
* eliminated NotableDate class (DG);
* 12-Nov-2001 : IBD requires setDescription() method, now
* that NotableDate class is gone (DG); Changed
* getPreviousDayOfWeek(),
* getFollowingDayOfWeek() and
* getNearestDayOfWeek() to correct bugs (DG);
* 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
* 29-May-2002 : Moved the month constants into a separate
* interface (MonthConstants) (DG);
Comments (bad
)
Nose
/**
Commen
st
* Default constructor.
*/
protected AnnualDateRule() { }
/**
* Returns the day of the
month.
* @return the day of the
month.
*/
public int getDayOfMonth() {
Comments (bad
)
Scary
/** The name. */
Nose
private String name;
Poston Markers
// Actions //////////////////////////////////
Attrbuto
/* Added by Rick */
ns and
CommenetdO
- ut Code
Bylnes
InputStreamResponse response = new InputStreamResponse();
response.setBody(formatter.getResultStream(),
formatter.getByteCount());
// InputStream resultsStream =
formatter.getResultStream();
// StreamReader reader = new
StreamReader(resultsStream);
//
response.setContent(reader.read(formatter.get
ByteCount()));
Comments (bad
)
HTML
Commesnt
/**
* Task to run fit tests.
* This task runs fitnesse tests and publishes the results.
* <p/>
* <pre>
* Usage:
* <taskdef name="execute-fitnesse-tests"
* classname="fitnesse.ant.ExecuteFitnesseTestsTask"
* classpathref="classpath" />
* OR
* <taskdef classpathref="classpath"
* resource="tasks.properties" />
* <p/>
* <execute-fitnesse-tests
Comments (bad
)
Nonolcal
/**
Infom r ato
* Port on which fitnesse would run. Defaults to <b>8082</b>.
*
* @param fitnessePort
*/
n
public void setFitnessePort(int fitnessePort)
{
this.fitnessePort = fitnessePort;
}
Comments (bad
)
o
To
/*
Much
RFC 2045 - Multipurpose Internet Mail Extensions (MIME)
Part One: Format of Internet Message Bodies section 6.8.
Base64 Content-Transfer-Encoding
The encoding process represents 24-bit groups of input bits
nIofrmaton
as output strings of 4 encoded characters. Proceeding from
left to right, a 24-bit input group is formed by
concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit
groups, each of which is translated into a single digit in
the base64 alphabet.
When encoding a bit stream via the base64 encoding, the bit
stream must be presumed to be ordered with the most-
significant-bit first.
*/
Comments (bad
)
nIobvous
/*
Connecto
* start with an array that is big enough to hold all the
* pixels (plus filter bytes), and an extra 200 bytes for
* header info
*/
n
this.pngBytes = new byte[((this.width + 1) * this.height * 3)
+ 200];
Functon Headers
// short functions don’t need much description
Comments (bad
)
Javadocs n Nonpublc
Code
// extra formality of the javadoc comments
Formatting
The
// communication
Purpose
The Newp
saper
of Fo
m
r a
ttn
Metaphor g
// high-level -> details
Vertcal
Formatting
Vertca
// vertical density implies close association
l Densty
/**
* The class name of the reporter listener
*/
private String m_className;
/**
* The properties of the reporter listener
*/
private m_properties = new ArrayList();
Formatting
Vertca
// variables
l Dsatnce
// should be declared as close to their usage as possible
// instance variables
// should be at the top of the class
declared
// dependent functions
// if one function calls another, they should be vertically
// close, and the caller should be above the called
// conceptual affinity
// certain bits of code want to be near other bits
Formatting
Horzontal
private void measureLine(String line) {
Openness
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
and
recordWidestLine(lineSize);
}
Densty
double determinant = determinant(a, b, c);
return (-b - Math.sqrt(determinant)) / (2*a);
}
Formatting
Horzonta
public class FitNesseExpediter implements ResponseSender
l
{
private Socket socket;
private InputStream input;
private OutputStream output;
Algnme
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
nt
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;
...
}
Formatting
Horzonta
public class FitNesseExpediter implements ResponseSender
l
{
private Socket socket;
private InputStream input;
private OutputStream output;
Algnme
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
nt
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;
...
}
Formatting
Breakng
public class CommentWidget extends TextWidget {
nIdentato
public static final String REGEXP =
"^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
public CommentWidget(String text) { super(text); } public
String render() throws Exception { return ""; }
n
}
Formatting
Breakng
public class CommentWidget extends TextWidget {
nIdentato
public static final String REGEXP =
"^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
n
super(text);
}
Rules
// but if he works in a team
// then the team rules
Objects and Data Structures
Data Abstracton
Concrete Point
Tran Wrecks
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
to Returnng
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
logger.log("page deleted");
} else {
Error Codes
logger.log("configKey not deleted");
}
} else {
logger.log("deleteReference from registry failed");
}
} else {
logger.log("delete failed");
return E_ERROR;
}
Error Handling
Preef r Exceptons
try {
to Returnng
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
Error Codes
catch (Exception e)
{ logger.log(e.getMessage(
));
}
Error Handling
Extract
public void delete(Page page) {
Try/Catch Bolcks
try {
deletePageAndAllReferences(
page);
} catch (Exception e) {
logError(e);
}
}
One Thng
// error handing is one thing
Nom
ral Flow
MealExpenses expenses = expenseReportDAO
.getMeals(employee.getID());
m_total += expenses.getTotal();
} catch(MealExpensesNotFound e) {
m_total += getMealPerDiem();
}
Error Handling
Defne the
MealExpenses expenses = expenseReportDAO
Nom
ral Flow
.getMeals(employee.getID());
m_total += expenses.getTotal();
Error Handling
Don’t
List<Employee> employees = getEmployees();
Return Null
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
Error Handling
Don’t
List<Employee> employees = getEmployees();
Return Null
for(Employee e : employees) {
totalPay += e.getPay();
}
Null
return (p2.x – p1.x) * 1.5;
}
Laws of
// you may not write production code until
// you have written a failing unit test
// second law
TDD
// you may not write more of a unit test
// than is sufficient to fail, and not compiling is failing
// third law
// you may not write more production code
// than is sufficient to pass the currently failing test
Unit Tests
Keepn
// test code is just as important as production code
gClean
TestsTests
Clean
// what makes a clean test? three things
// readability, readability, and readability
Unit Tests
One
// tests come to a single conclusion
Asert
// that is quick and easy to understand
Organz
// private static variables
// private instance variables
// public functions
// private utilities called by a public function right after
ato n
Cal sses Should Be Small!
// the first rule is that they should be small
// the second rule is that they should be smaller than that
Classes
The Sngle
// a class or module should have one, and only one,
Responsblty
// reason to change
Cohe
son
Prncple (SRP)
// maintaining cohesion results in many small classes
Emergence
Smple Desgn
Rule 1: Runs All
the TestsSmple
Desgn Rules
2: No
Questions?