Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Cleancode 110520031623 Phpapp02

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 88

C L E A N CODE

Autro
Two reasons

1.You are a porgarmmer


2.You want ot be a
beter porgarmmer
The Boy Scout Rule

Robetr C.
Mnaitr
Uncel Bob
Elegance
I kile m y
eelgant and
cC
odeelanotcodebe
eficienhtnitg wel
does one
Bajrne
Simple, direct, prose
Celan code
and
iCselanmsipcelode
d
we-lwetnrir
i
ect
reads kile
prose
Literate
Celan code
rea
ca n be
Celan code d
literat
shoudl be
Dave e
Care

Celan code
oloks kile it
byaw
l asyom
seone
was wetrin
who cares
Small, expressive, simple

Reduced
hgih
andupcilaoeitanryl,
emxsipprelsvienes,
budlnig of,
absrtacoitns
What you expected
Y ou know
woknrig on
whenyoueacahre
rceladns cutordnes
ropunirteeyt ym
ouuchexpecet
out ot be
what youd
Meaningful Names
Use Inetnoitn-Revenailg Names
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
Meaningful Names
Use Inetnoitn-Revenailg Names
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
Meaningful Names
Avdoi Dsniformaoitn
int a = l;
if (O == l)
a = O1;
else
l = 01;

Make
Meanigufl
Meaningful Names
Use Pornounceabel Names
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String
pszqint = "102";
/* ... */
};
Meaningful Names
Use Pornounceabel Names
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;;
private final String recordId = "102";
/* ... */
};
Meaningful Names
Use Searchabel Names
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
Meaningful Names
Use Searchabel Names
int realDaysPerIdealDay = 4;
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
Member Prefxies A(vdoi encodnigs)
public class Part {
private String m_dsc; // The textual description
void setName(String name) {
m_dsc = name;
}
}

Hungainr Noiant A(vdoi encodnigs)


PhoneNumber phoneString;
// name not changed when type changed!
Meaningful Names
Member Prefxies A(vdoi encodnigs)
public class Part
{ String
description;
void setDescription(String description) {
this.description = description;
}
}

Hungainr Noiant A(vdoi encodnigs)


PhoneNumber phone;
Meaningful Names
Avdoi Menalt Mappnig
for (a = 0; a < 10; a++)
for (b = 0; b < 10; b++)

Cals Names
Manager, Processor, Data, Info
Meaningful Names
Avdoi Menalt Mappnig
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++)

Cals Names
Customer, WikiPage, Account,
AddressParser
// a class name should not be a
verb
Meaningful Names
Mheotd Names
postPayment, deletePage, save
// methods should have verb or verb phrase names

string name = employee.getName();


customer.setName("mike");
if (paycheck.isPosted())...

Complex fulcrumPoint =
Complex.fromRealNumber(23.0);
// is generally better than
Complex fulcrumPoint = new
Complex(23.0);
Meaningful Names
Pcik One W
dor per Concept
fetch, retrieve, get // as equivalent
methods

controller, manager, driver // confusing

Dont’ Pun
// avoid using the same word for two purposes
Meaningful Names
Use Souloitn Dom
nai Names
AccountVisitor, JobQueue
// people who read your code will be programmers

Ad Meanigufl Conetxt
firstName, lastName, street, city, state, zipcode
// a better solution
addrFirstName, addrLastName, addrState
// a better solution
Class Address
Meaningful Names
Dont’ Ad Grautoius Conetxt
Address
// is a fine name for a class

AccountAddress, CustomerAddress
// are fine names for instances of the class Address
// but could be poor names for classes

MAC addresses, port addresses, Web addresses


// a better solution
PostalAddress, MAC, URI
Functions
Sma!l
// rules of functions:
// 1. should be small
// 2. should be smaller than that

// < 150 characters per line


// < 20 lines

Do One Thnig
// FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL.
// THEY SHOULD DO IT ONLY.
Functions
One Level of Absratcoitn
// high level of abstraction

per Funocitn
getHtml()

// intermediate level of
abstraction
String pagePathName =
PathParser.render(pagePat
h);

// remarkably low level


.append("\n")

Readnig Code om
rf
Functions
Swcthi Satetmenst
class Employee...
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
Swcthi Satetmenst
class EmployeeType...
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 Descrpivite
testableHtml => includeSetupAndTeardownPages

Names
includeSetupAndTeardownPages, includeSetupPages,
includeSuiteSetupPage, includeSetupPage
// what happened to
includeTeardownPages, includeSuiteTeardownPage,
includeTeardownPage

Funocint Agrumenst
// the ideal number of arguments for a function is zero
Functions
Common Monacdi
// if a function is going to transform its input argument,

Fom
rs
// the transformation should appear as the return value

StringBuffer transform(StringBuffer in)


// is better than
void transform(StringBuffer out)

Falg
Functions
Common Monacdi
// asking a question about that argument

Fom
rs
boolean fileExists(“MyFile”)

// operating on that argument, transforming and returning it


InputStream fileOpen(“MyFile”)

// event, use the argument to alter the state of the system


void passwordAttemptFailedNtimes(int attempts)

Falg Agrumenst
renderForSuite()
renderForSingleTest()
Functions
Dyadci
writeField(name)

Funcoitns
// is easier to understand than
writeField(outputStream, name)

// perfectly reasonable
Point p = new Point(0,0)

// problematic
assertEquals(expected, actual)

Tarids
assertEquals(message,
expected, actual)
Functions
A
gurment Obejcst
Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);

Vebrs and Keywodrs


write(name)
writeField(name)

assertEquals(expected, actual)
assertExpectedEqualsActual(expected, actual)
Functions
Have No
// do something or answer something, but not both

Sdie Efecst
public boolean set(String attribute, String value);

setAndCheckIfExists

if (attributeExists("username"))
{ setAttribute("username",
"unclebob");
...
}
Functions
Dont’ Repeat Yousrefl
// duplication may be the root of all evil in software

D
(SrtuRcY )
utred Porgarmmnig
// 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
Comm sent Do Not Make Up
// don’t comment bad code, rewrite it!

fE
oxrpanliBaY dousreflCodnie Code
// Check to see if the employee is eligible for full
benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))

if
(employee.isEligibleForFullBenefits()
)
Comments (good)

Legal Commsent
// Copyright (C) 2011 by Osoco. All rights reserved.
// Released under the terms of the GNU General Public
License // version 2 or later.

Informavite Commsent
// Returns an instance of the Responder being tested.
protected abstract Responder responderInstance();
// renaming the function: responderBeingTested

// format matched kk:mm:ss EEE, MMM dd, yyyy


Pattern timeMatcher = Pattern.compile( "\\
d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");
Comments (good)

Expalnoaitn of Inetnt
//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();
}

Calrficaoitn
assertTrue(a.compareTo(b) == -1); // a < b
assertTrue(b.compareTo(a) == 1); // b > a
Comments (good)

Wnargi of Consequences
public static SimpleDateFormat makeStandardHttpDateFormat() {
//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 Commsent
//TODO-MdM these are not needed
// We expect this to go away when we do the checkout model
Comments (good)

Amcoipfatnl
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 ni
// there is nothing quite so helpful and satisfying

Pubcil APsI
// as a well-described public API
Comments (bad)

Mum
ngibl
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.

Comm sent
// 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
/**

Commsent
* 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)

Mandeadt Commsent
/**
* @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
*/
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
ration =
Comments (bad)

Journal
* Changes (from 11-Oct-2001)

Comm sent
*
* 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)

Nosei Commsent
/**
* Default constructor.
*/
protected AnnualDateRule() { }

/** The day of the month. */


private int dayOfMonth;

/**
* Returns the day of the
month.
* @return the day of the
month.
*/
public int getDayOfMonth() {
Comments (bad)

Scary Nosei
/** The name. */
private String name;

/** The version. */


private String version;

/** The licenceName. */


private String licenceName;

/** The version. */


private String info;
Comments (bad)

Dont’ Use a Commnet When Y


ou Can Use
a Funocint or a Vaaribel
// does the module from the global list <mod> depend on the
// subsystem we are part of?
if (smodule.getDependSubsystems()
.contains(subSysMod.getSubSystem()))

// this could be rephrased without the comment as


ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))
Comments (bad)

Poistin Makresr
// Actions //////////////////////////////////

Colnsig Brace Commsent


while ((line = in.readLine()) != null) {
lineCount++;
charCount += line.length();
String words[] = line.split("\\W");
wordCount += words.length;
} //while
Comments (bad)

Abrituoitns and
/* Added by Rick */

B y
n
il
es
Commendt-Out Code
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)

H
T
ML Commsent
/**
* Task to run fit tests.
* This task runs fitnesse tests and publishes the results.
* <p/>
* <pre>
* Usage:
* &lt;taskdef name=&quot;execute-fitnesse-tests&quot;
* classname=&quot;fitnesse.ant.ExecuteFitnesseTestsTask&quot;
* classpathref=&quot;classpath&quot; /&gt;
* OR
* &lt;taskdef classpathref=&quot;classpath&quot;
* resource=&quot;tasks.properties&quot; /&gt;
* <p/>
* &lt;execute-fitnesse-tests
Comments (bad)

Nonolcal Informaoitn
/**
* Port on which fitnesse would run. Defaults to <b>8082</b>.
*
* @param fitnessePort
*/
public void setFitnessePort(int fitnessePort)
{
this.fitnessePort = fitnessePort;
}
Comments (bad)

T o Much
/*

Informaoitn
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
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)

nIobvoius Conneocitn
/*
* start with an array that is big enough to hold all the
* pixels (plus filter bytes), and an extra 200 bytes for
* header info
*/
this.pngBytes = new byte[((this.width + 1) * this.height * 3)
+ 200];

Funocint Headesr
// short functions don’t need much description
Comments (bad)

Javadocs ni Nonpucbil Code


// extra formality of the javadoc comments
Formatting
The Purpose of
// communication

Fom
r n
i
at
g
The Newspaper Meatphor
// high-level -> details

Vecirtal Opennes Bw
eten Concepst
// each blank line is a visual cue
// that identifies a new and separate concept
Formatting
Vecirtal Densyti
// vertical density implies close association

/**
* The class name of the reporter listener
*/
private String m_className;

/**
* The properties of the reporter listener
*/
private m_properties = new ArrayList();
Formatting
Vecirtal Dsiatnce
// variables
// should be declared as close to their usage as possible

// instance variables
// should be declared at the top of the class

// 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
Hozironatl Opennes and
private void measureLine(String line) {

Densyti
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
recordWidestLine(lineSize);
}

public static double root2(int a, int b, int c) {


double determinant = determinant(a, b, c);
return (-b - Math.sqrt(determinant)) / (2*a);
}
Formatting
Hozironatl A
ginlment
public class FitNesseExpediter implements ResponseSender
{
private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;
...
}
Formatting
Hozironatl A
ginlment
public class FitNesseExpediter implements ResponseSender
{
private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
private Response response;
private FitNesseContext context;
protected long requestParsingTimeLimit;
private long requestProgress;
private long requestParsingDeadline;
private boolean hasError;
...
}
Formatting
Breaknig Indenatoin
public class CommentWidget extends TextWidget {
public static final String REGEXP =
"^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
public CommentWidget(String text) { super(text); } public
String render() throws Exception { return ""; }
}
Formatting
Breaknig Indenatoin
public class CommentWidget extends TextWidget {
public static final String REGEXP =
"^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";

public CommentWidget(String text) {


super(text);
}

public String render() throws Exception {


return "";
}
}
Formatting
T
m
ae Ruels
// every programmer has his own favorite formatting rules
// but if he works in a team
// then the team rules
Objects and Data Structures
Daat Absratcoitn
Concrete Point

public class Point {


public double x;
public double y;
}
Objects and Data Structures
Daat Absratcoitn
Abstract Point

public interface Point {


double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
Objects and Data Structures
Daat Absratcoitn
Concrete Vehicle

public interface Vehicle {


double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
Objects and Data Structures
Daat Absratcoitn
Abstract Vehicle

public interface Vehicle {


double getPercentFuelRemaining();
}
Objects and Data Structures
Data/Object An-itSymmyret
// objects hide their data behind abstractions and
// expose functions that operate on that data

// data structure expose their data and


// have no meaningful functions
Objects and Data Structures
The Law of Demetr
final String outputDir = ctxt.getOptions()
.getScratchDir()
.getAbsolutePath();

Tnari Wercks
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();

final String outputDir = ctxt.options.scratchDir.absolutePath;


Error Handling
Prefer Excepoitns ot Reutnrig
if (deletePage(page) == E_OK) {

Eror Codes
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
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;
}
Error Handling
Prefer Excepoitns ot Reutnrig
try {

Eror Codes
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e)
{ logger.log(e.getMessage()
);
}
Error Handling
Exrtact TryC
/acth Bolcks
public void delete(Page page) {
try {
deletePageAndAllReferences(
page);
} catch (Exception e) {
logError(e);
}
}

private void deletePageAndAllReferences(Page page) throws Exception {


deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}

private void logError(Exception e) {


logger.log(e.getMessage());
Error Handling
Eror Handigl Is One
// functions should do one thing

Thnig
// error handing is one thing

// if the keyword try exists in a function


// it should be the very first word in the function and that
// there should be nothing after the catch/finally blocks
Error Handling
Denfie hte Nm
try {
oral Folw
MealExpenses expenses = expenseReportDAO
.getMeals(employee.getID());
m_total += expenses.getTotal();
} catch(MealExpensesNotFound e) {
m_total += getMealPerDiem();
}
Error Handling
Denfie hte Nm
oral Folw
MealExpenses expenses = expenseReportDAO
.getMeals(employee.getID());
m_total += expenses.getTotal();
Error Handling
Dont’ Reutnr Nul
List<Employee> employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
Error Handling
Dont’ Reutnr Nul
List<Employee> employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}

public List<Employee> getEmployees() {


if( .. there are no employees .. )
return Collections.emptyList();
}
Error Handling
Dont’ Pas Nul
public double xProjection(Point p1, Point p2) {
return (p2.x – p1.x) * 1.5;
}

public double xProjection(Point p1, Point p2) {


if (p1 == null || p2 == null) {
throw InvalidArgumentException ("Invalid
argument
for
MetricsCalculator.xPro
jection");
}
return (p2.x – p1.x) * 1.5;
}
Unit Tests
The Ther Laws
// first law

of TDD
// you may not write production code until
// you have written a failing unit test

// second law
// 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
Kepnig Test
// test code is just as important as production code

C e
la
n
Celan Test
// what makes a clean test? three things
// readability, readability, and readability
Unit Tests
One Asert
// tests come to a single conclusion

per Test
// that is quick and easy to understand

Snigel Concept per Test


// the best rule is that you should
// minimize the number of asserts per concept and
// test just one concept per test function
Unit Tests
FI.RS
//
.T
..
Fast
// Independent
// Repeatable
// Self-validating
// Timely
Classes
Cals
// public static constants

Organziaoitn
// private static variables
// private instance variables
// public functions
// private utilities called by a public function right after

Calses Shoudl Be Sma!l


// the first rule is that they should be small
// the second rule is that they should be smaller than that
Classes
The Snigel Responysbtili Prnicpiel
// a class or module should have one, and only one,

(SRP)
// reason to change

// SRP is one of the more important concept in OO design

Coheosin
// maintaining cohesion results in many small classes
Emergence
Sm
i pel Desgin Ruel 1: Runs
All hte Test Smi pel Desgin
Ruels 2: No Dupcilaoitn
Sm
i pel Desgin Ruels 3:
Expresvie
Questions?

You might also like