3. Meaningful Names
• Avoid Mental Mapping
A single-letter name is a poor choice; it’s just a place holder that the reader
must mentally map to the actual concept. There can be no worse reason for
using the name “c” than because “a” and “b” were already taken.
• Method names
Methods should have verb or verb phrase names like postPayment,
deletePage, or save. Accessors, mutators, and predicates should be named
for their value and prefixed with get…, set…, and is…
4. Meaningful Names
• Use Searchable Names
const int WORK_DAYS_PER_WEEK = 5;
int realDaysPerIdealDay = 4;
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;
}
for (int j = 0; j < 34; j++) {
s += (t [ j ] * 4) / 5;
}
Single-letter names can ONLY be
used as local variables inside short
methods.
The length of a name should
correspond to the size of its scope
5. Meaningful Names
• Use Intention-Revealing Names
If a name requires a comment, then the name does not reveal its intent.
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
6. Meaningful Names
• Use Pronounceable Names
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
}
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
}
If you can’t pronounce it, you can’t
discuss it without sounding like an idiot.
8. Meaningful Names
• Class Names
Customer, WikiPage, Account,
AddressParser.
Classes and objects should have noun or
noun phrase names and not include
indistinct noise words:
Manager, Processor, Data, Info.
9. Functions
• Small!
The first rule of functions is that they should be small.
Functions should hardly ever be ??? lines long.
Blocks within if statements, else statements, while statements, and so on
should be ??? long.
10. Functions
• Small!
The first rule of functions is that they should be small.
Functions should hardly ever be 20 lines long.
Blocks within if statements, else statements, while statements, and so on
should be one line long. Probably that line should be a function call.
• Do One Thing
To know that a function is doing more than “one thing” is if you can extract
another function from it with a name that is not merely a restatement of its
implementation.
11. Functions
• One Level of Abstraction per Function
We want the code to read like a top-down narrative.
We want every function to be followed by those at the next level of abstraction
so that we can read the program, descending one level of abstraction at a time
as we read down the list of functions.
public String render() throws Exception {
StringBuffer html = new StringBuffer(“<hr");
if(size > 0)
html.append(" size="")
.append(size + 1).append(“”");
html.append(">");
return html.toString();
}
public String render() throws Exception {
HtmlTag hr = new HtmlTag(“hr");
if (extraDashes > 0)
hr.addAttribute(“size", hrSize(extraDashes));
return hr.html();
}
private String hrSize(int height) {
int hrSize = height + 1;
return String.format("%d", hrSize);
}
12. Functions
• Use Descriptive Names
Don’t be afraid to make a name long. A long descriptive name is better than
a short enigmatic name. A long descriptive name is better than a long
descriptive comment.
• Dependent Functions.
If one function calls another, they should be vertically close, and the caller
should be above the callee, if at all possible.
14. Functions
• Function Arguments
The ideal number of arguments for
a function is zero (niladic). Next
comes one (monadic), followed
closely by two (dyadic). Three
arguments (triadic) should be
avoided where possible.
includeSetupPage()
includeSetupPageInto(newPageContent)
15. Functions
• Flag Arguments
Flag arguments are ugly. Passing a
boolean into a function is a truly
terrible practice. It immediately
complicates the signature of the
method, loudly proclaiming that this
function does more than one thing. It
does one thing if the flag is true and
another if the flag is false!
render(boolean isSuite)
renderForSuite()
renderForSingleTest()
16. Functions
• Have No Side Effects
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}
17. Functions
• Have No Side Effects
Side effects are lies.
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}
checkPasswordAndInitializeSession
18. Functions
• Output Arguments
For example:
appendFooter(s);
Does this function append “s” as the
footer to something? Or does it
append some footer to “s”? Is “s” an
input or an output? It doesn’t take
long to look at the function
signature and see, but anything that
forces you to check the function
signature is equivalent to a double-
take. It’s a cognitive break and
should be avoided.
public void appendFooter(StringBuffer report)
report.appendFooter();
19. Comments
// Check to see if the employee is eligible
// for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
or
20. Comments
• Explain Yourself in Code
Only the code can truly tell you
what it does.
Comments are, at best, a
necessary evil.
Rather than spend your time writing
the comments that explain the
mess you’ve made, spend it
cleaning that mess.
Inaccurate comments are far worse
than no comments at all.
if (employee.isEligibleForFullBenefits())
// Check to see if the employee is eligible
// for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
21. Comments
• Legal Comments
Sometimes our corporate
coding standards force us to
write certain comments for
legal reasons.
// Copyright (C) 2003,2004,2005 by Object
// Mentor, Inc. All rights reserved.
// Released under the terms of the GNU
// General Public License version 2 or later.
• Explanation of Intent
Sometimes a comment goes
beyond just useful information
about the implementation and
provides the intent behind a
decision.
// 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, parent, failFlag);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}
22. Comments
• Warning of Consequences
Sometimes it is useful to warn
other programmers about
certain consequences.
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;
}
• TODO Comments
Nowadays, most good IDEs
provide special gestures and
features to locate all the //TODO
comments, so it’s not likely that
they will get lost.
//TODO-MdM these are not needed
// We expect this to go away when we do the
// checkout model
protected VersionInfo makeVersion() throws Exception{
return null;
}
23. Comments
• Amplification
A comment may be used to
amplify the importance of
something that may otherwise
seem inconsequential.
String listItemContent = match.group(3).trim();
// the trim is real important. It removes the starting
// spaces that could cause the item to be recognised
// as another list.
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
• Public APIs
There is nothing quite so helpful
and satisfying as a well-
described public API. It would
be difficult, at best, to write
programs without them.
/// dart doc comment
/**
* JavaDoc comment
*/
24. Comments
• Commented-Out Code
We’ve had good source code
control systems for a very long
time now. Those systems will
remember the code for us. We
don’t have to comment it out any
more. Just delete the code.
• Position Markers
In general they are clutter that
should be eliminated—
especially the noisy train of
slashes at the end. If you
overuse banners, they’ll fall into
the background noise and be
ignored.
// Actions //////////////////////////////////
InputStreamResponse response = new InputStreamResponse();
response.setBody(formatter.getResultStream(),
formatter.getByteCount());
// InputStream resultsStream = formatter.getResultStream();
// StreamReader reader = new StreamReader(resultsStream);
// response.setContent(reader.read(formatter.getByteCount()));
25. Error Handling
• Don’t Return Null
When we return null, we are
essentially creating work for
ourselves and foisting problems
upon our callers. All it takes is one
missing null check to send an
application spinning out of control.
List<Employee> employees = getEmployees();
if (employees != null) {
for (Employee e : employees) {
totalPay += e.getPay();
}
}
public List<Employee> getEmployees() {
if ( .. there are no employees .. )
return Collections.emptyList();
}
26. Error Handling
• Don’t Pass Null
In most programming languages
there is no way to deal with
a null that is passed by a caller
accidentally. Because this is the
case, the rational approach is to
forbid passing null by default. When
you do, you can code with the
knowledge that a null in an
argument list is an indication of a
problem, and end up with far fewer
careless mistakes.
calculator.xProjection(null, new Point(12, 13));
27. Classes
• Classes Should Be Small!
With functions we measured size by counting physical lines. With classes we use a
different measure. We count ???.
28. Classes
• Classes Should Be Small!
With functions we measured size by counting physical lines. With classes we use a
different measure. We count responsibilities.
The Single Responsibility Principle (SRP) states that a class or module should have
one, and only one, reason to change.
The name of a class should describe what responsibilities it fulfills. The more
ambiguous the class name, the more likely it has too many responsibilities.
The problem is that too many of us think that we are done once the program works.
We move on to the next problem rather than going back and breaking the
overstuffed classes into decoupled units with single responsibilities.
29. Classes
public class SuperDashboard extends JFrame implements MetaDataUser
public String getCustomizerLanguagePath()
public void setSystemConfigPath(String systemConfigPath)
public String getSystemConfigDocument()
public void setSystemConfigDocument(String systemConfigDocument)
public boolean getGuruState()
public boolean getNoviceState()
public boolean getOpenSourceState()
public void showObject(MetaObject object)
public void showProgress(String s)
public void setACowDragging(boolean allowDragging)
public boolean allowDragging()
public boolean isCustomizing()
public void setTitle(String title)
public IdeMenuBar getIdeMenuBar()
public void showHelper(MetaObject metaObject, String propertyName)
// ... many non-public methods follow ...
}
public class Version {
public int getMajorVersionNumber()
public int getMinorVersionNumber()
public int getBuildNumber()
}
30. Environment
• Build Requires More Than One Step
Building a project should be a single
trivial operation. You should not have to
check many little pieces out from source
code control. You should be able to
check out the system with one simple
command and then issue one other
simple command to build it.
svn get mySystem
cd mySystem
ant all
• Tests Require More Than One Step
You should be able to run all the unit tests with just one command. In the best
case you can run all the tests by clicking on one button in your IDE.
31. General
• Artificial Coupling
In general an artificial coupling is a coupling between two modules that serves no
direct purpose. It is a result of putting a variable, constant, or function in a temporarily
convenient, though inappropriate, location.
For example, general enumsshould not be contained within more specific classes
because this forces the whole application to know about these more specific classes.
The same goes for general purpose static functions being declared in specific
classes.
• Prefer Polymorphism to If/Else or Switch/Case
There may be no more than one switch statement for a given type of selection. The
cases in that switch statement must create polymorphic objects that take the place of
other such switch statements in the rest of the system.
32. General
• Replace Magic Numbers with Named Constants
In general it is a bad idea to have raw numbers in your code. You should hide them
behind well-named constants. The term “Magic Number” does not apply only to
numbers. It applies to any token that has a value that is not self-describing.
assertEquals(7777, Employee.find(“John Doe”).employeeNumber());
assertEquals(
HOURLY_EMPLOYEE_ID,
Employee.find(HOURLY_EMPLOYEE_NAME).employeeNumber());
33. General
• Encapsulate
Conditionals
Boolean logic is hard enough to
understand without having to
see it in the context of an if or
while statement. Extract
functions that explain the intent
of the conditional.
if (shouldBeDeleted(timer))
if (timer.hasExpired() &&
!timer.isRecurrent())
• Avoid Negative
Conditionals
Negatives are just a bit harder to
understand than positives. So,
when possible, conditionals
should be expressed as
positives.
if (buffer.shouldCompact())
if (!buffer.shouldNotCompact())
34. General
• Encapsulate Boundary Conditions
Boundary conditions are hard to keep track of. Put the processing for them in one
place.
if (level + 1 < tags.length) {
parts = new Parse(body, tags, level + 1, offset + endTag);
body = null;
}
int nextLevel = level + 1;
if (nextLevel < tags.length) {
parts = new Parse(body, tags, nextLevel, offset + endTag);
body = null;
}
35. General
• Constants versus Enums
Don’t keep using the old trick of public static final ints. Enums can
have methods and fields. This makes them very powerful tools that allow much
more expression and flexibility.
public enum HourlyPayGrade {
APPRENTICE {
public double rate() {
return 1.0;
}
},
MASTER {
public double rate() {
return 2.0;
}
};
public abstract double rate();
}
public class HourlyEmployee extends Employee {
private int tenthsWorked;
HourlyPayGrade grade;
public Money calculatePay() {
int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK);
int overTime = tenthsWorked - straightTime;
return new Money(
grade.rate() * (tenthsWorked + OVERTIME_RATE * overTime)
);
}
/…
}