4. Clean code
Introduction to Raya Guide
There will be a code
Code Quality Measurement
Bad Code
The Boy Scout Rule
Our Attitude
We are Authors
Clean CodeRaya Software
6. There will be a code
Generated code, only?
If so let the customer generate the
program for him self
New languages & technologies may get
closer to requirements, but:
We will never get rid of code
Clean CodeRaya Software
8. Bad Code
Rush + “Later” = Mess (of Bad Code)
Rush: it is a market nature; we can’t get rid of
“Later”: enhancing it will enhance the formula
Challenge is:
“A working mess is better than nothing”
Can’t fully disagree, but look at team
productivity if we insist on saying so:
Clean CodeRaya Software
9. Bad Code
With “Later” team productivity will be:
So keep in mind LeBlanc’s law:
“Later Equals Never”
Clean CodeRaya Software
10. The Boy Scout Rule
We may face Bad Code in:
Projects written by others
Projects we wrote in a rush
So there always be a Bad Code
The Solution is The Boy Scout Rule:
“Leave the campground cleaner than you found it ”
Which means: check in cleaner code than
you checked it out
Imagine working in a project where code
simply got better
Clean CodeRaya Software
11. Our Attitude
Clean Code is a matter of attitude more than
being a matter of knowledge
Managers passion? Delivery time
Customers passion? Requirement & Cost
Our passion? ……...
[Mess = Miss ] Delivery time
[Mess = Miss ] Requirement
[Mess = Miss ] Team Productivity
Clean CodeRaya Software
Clean Code
12. We are Authors
@author field of a Javadoc is pointing at us
The author is writing for …….. Reader
No way to write code without read
the ratio of time spent reading vs. writing is
well over 10:1
Making it easy to read makes it easier to write
Professionals choose Paperback Model not
the Academic Model
Clean CodeRaya Software
14. Meaningful Names
Introduction
Rule #1: Use Intention-Revealing Names
Rule #2: Avoid Disinformation
Rule #3: Make Meaningful Distinction
Rule #4: Use Pronounceable Names
Rule #5: Use Searchable Names
Rule #6: Avoid Encodings
Rule #7: Avoid Mental Mapping
Rule #8: Don’t be Cute
Rule #9: Pick One Word per Concept
Rule #12: Don’t Add Extra-free Context
Conclusion
Meaningful NamesRaya Software
15. Introduction
Names are everywhere
We name our:
Variables
Methods
Arguments
Classes
Packages
Source files
Directories
Jar files
WAR & EAR files
Meaningful NamesRaya Software
16. Rule #1
Use Intention-Revealing Names
Meaningful NamesRaya Software
int d; // elapsed time in days Very Bad
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
Good
Motive:
If a name requires a comment, then the name
does not reveal its intent.
17. Rule #2
Avoid Disinformation
Meaningful NamesRaya Software
Variable name Motive
accountList Don’t use this name unless
it is already a List object
XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings
how long will it take to see
the difference between them
Karakter will never be found when the
programmer searches for
character
int a = l;
if ( O == l )
a = O1;
else
l = 01;
uppercase ‘O’ or just Zero ?
lower case ‘L’ or just one ?
- liar if you answer it
without changing the code
font
18. Rule #3
Make Meaningful Distinction
Meaningful NamesRaya Software
public static void copyChars(char a1[]
, char a2[]) {
for (int i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
Bad
public static void copyChars(char[] source
, char[] destination) {
for (int i = 0; i < source.length; i++) {
destination[i] = source[i];
}
}
Good
Motive:
Number-series names are not only disinformative but
they are noninformative at all
19. Rule #4
Use Pronounceable Names
Try to read the following variable
“genymdhms”
Now we sounds like Idiots
So seriously the reason for this rule is not to being
an idiot
Meaningful NamesRaya Software
20. Rule #5
Use Searchable Names
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
Meaningful NamesRaya Software
7
e
Very Bad
DAYS_PER_WEEK
week
Good
Motive:
Single-letter names and numeric constants are
not easy to locate across a body of text.
There can be no worse reason for using the name
c than because a and b were already taken.
22. Rule #6
Avoid Encodings
Interfaces & Implementation
Meaningful NamesRaya Software
Interface IShapeFactory {...}
Class ShapeFactory implements IShapeFactory {...}
Very Bad
Interface ShapeFactory {...}
Class ShapeFactoryImp implements ShapeFactory {...}
Good
Motive:
If I must encode either the interface or the implementation, I
choose the implementation. I don’t want my users knowing that
I’m handing them an interface. I just want them to know that
it’s a ShapeFactory.
23. Rule #7
Avoid Mental Mapping
Like using r instead of url
− So don’t be Smart, but Be Professional
When to Use Solution Domain Names
− When it is more close to patterns of computer science
concepts
When to Use Problem Domain Names
− When it is more close to business
Meaningful NamesRaya Software
24. Rule #8
Don’t Be Cute
Like using HolyHandGrenade() instead of
DeleteItems()
− Names based on cultural base or sense of humor will only
be remembered by people who know it
Meaningful NamesRaya Software
25. Rule #9
Pick One Word per Concept
Like using fetch(), retrieve(), and get() in the
same layer
− How on earth should the caller know which method to
call ? !!!
Meaningful NamesRaya Software
26. Rule #12
Don’t Add Extra-free Context
In a “Gas Station Deluxe” application, it is a bad
idea to prefix every class with GSD
Meaningful NamesRaya Software
27. Conclusion
Don’t be afraid of renaming things
People will be grateful if you do so
Let Refactoring Tools Help you
Believe me, it will pay off in the short run and
continue to pay in the long run
Meaningful NamesRaya Software
30. Methods
Introduction
Rule #1: Small
Rule #2: Do One Thing
Rule #3: One Level of Abstraction per Method
Rule #4: Avoid Switch Statements
Rule #5: Use Descriptive Names
Rule #6: Minimize Method Arguments
Rule #7: Have No Side Effects
Rule #9: Separate Command from Query
Some Structured Programming Concepts
Don’t Repeat Yourself (DRY)
MethodsRaya Software
31. Introduction
Please, read this method and see how much sense
you can get of it in 3 minutes
Now see the coming refactored version of it
MethodsRaya Software
32. Introduction
Surprise, isn’t it?, So how we can do it ?
MethodsRaya Software
HtmlUtil.java (Refactored)
public static String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite
) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent,
isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
33. Rule #1: Small
First: methods should be small
Second: they should be smaller than that
I’m not kidding
They should be a Screen-Full
Or should hardly ever be 20 lines long
After applying this on the refactored version,
look on the re-refactored one:
MethodsRaya Software
34. Rule #1: Small
Again, s-u-r-p-r-i-s-e
MethodsRaya Software
HtmlUtil.java (re-Refactored)
public static String
renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite) throws
Exception {
if (isTestPage(pageData))
includeSetupAndTeardownPages(pageData,
isSuite);
return pageData.getHtml();
}
35. Rule #2: Do One Thing
“FUNCTIONS SHOULD DO ONE THING. THEY
SHOULD DO IT WELL. THEY SHOULD DO IT
ONLY.”
Look at the refactored version, it’s doing 3
things:
Determining whether the page is a test page.
If so, including setups and teardowns.
Rendering the page in HTML.
Which just violates our rule
MethodsRaya Software
36. Rule #3: One Level of Abstraction per
Method
mixing levels of abstraction within a method
is always confusing
Readers may not be able to tell whether a
particular expression is an essential concept
or a detail !!!
MethodsRaya Software
37. Rule #4: Avoid Switch Statements
First of all it violates the “Do One Thing” rule
As a work around:
Bury the switch statement in the basement of an
ABSTRACT FACTORY (GOF pattern)
Sometimes we can’t get rid of it, but we
should try
MethodsRaya Software
38. Rule #5: Use Descriptive Names
As covered in the last section
Don’t be afraid to make a name long.
Don’t be afraid to spend time choosing a
name.
MethodsRaya Software
39. Rule #6: Minimize Method Arguments
From the Guide
MethodsRaya Software
40. Rule #7: Have No Side Effects
Try to spot any side effect in the following
MethodsRaya Software
UserValidator.java
public class UserValidator {
private Cryptographer cryptographer;
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;
}
}
41. Rule #7: Have No Side Effects
It’s name implies checking the password
But it also initializing the session !!!!!!!!
Which may cause data lose if someone call it
without knowing this
Solution: if we can’t divide it, then just tell the
caller that you are doing so and rename it:
checkPasswordAndInitializeSession()
MethodsRaya Software
42. Rule #9: Separate Command from Query
Methods should either do something or
answer something
MethodsRaya Software
if (set("username", "unclebob"))... Bad
if (attributeExists("username")) {
setAttribute("username", "unclebob");
...
}
Good
Motive:
Is it asking whether the “username” attribute was previously set to “unclebob”?
Or is it asking whether the “username” attribute was successfully set to
“unclebob”?
Solution:
You can rename it setAndCheckIfExists, but that doesn’t much help the
readability of the if statement.
But the real solution is to separate the command from the query so that the
ambiguity cannot occur.
43. Some Structured Programming Concepts
Edsger Dijkstra said that every function, and
every block within a function, should have
one entry and one exit.
Only one return statement in a method.
No break or continue statements in a loop.
And never, ever, any goto statements.
MethodsRaya Software
44. Don’t Repeat Yourself (DRY)
Duplication may be the root of all evil in
software
In our method the following was repeated 4
times through it:
SetUp
SuiteSetUp
TearDown
SuiteTearDown
Now look at the final version
MethodsRaya Software
46. Error Handling
Introduction
Rule #1: Prefer exceptions to Returning Error Codes
Rule #11: Extract Try/Catch Blocks
Rule #3: Use Unchecked Exceptions
Rule #4: Don’t Eat the Exception
Rule #5: Resist Temptation to write a Single Catchall
Rule #6: Always use Catchall after handling known
ones
Rule #8: Don’t Return NULL
Rule #9: Don’t Pass Null
Error HandlingRaya Software
47. Introduction
It might seem odd to have a section about
Error Handling when talking about readability
Some Programs are dominated by Error
Handling
“Error handling is important, but if it covers
the logic, then it’s wrong.”
Error HandlingRaya Software
48. Rule #1: Prefer exceptions to
Returning Error Codes
Error HandlingRaya Software
if (deletePage(page) == E_OK) {
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;
}
Bad
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e) {
logger.log(e.getMessage());
}
Good
Motive: Error Codes awful nested IFs
But using Exceptions now, we can read the normal flow
49. Rule #11:Extract Try/Catch Blocks
Error HandlingRaya Software
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e) {
logger.log(e.getMessage());
}
Not so good
public void delete(Page page) {
try {
deletePageAndAllReferences(page);
}
catch (Exception e) {
logError(e);
}
}
private void deletePageAndAllReferences(Page page) throws Exception {….}
private void logError(Exception e) {….}
Good
Motive:
The delete is all about error processing
deletePageAndAllReferences is all about the processes of
deleting a page,
which provides a nice separation that makes the code easier to
understand and modify.
50. Rule #3: Use Unchecked Exceptions
“The debate is over” !!!!!!
Why not using Checked Exceptions
Increasing error handling in many parts of our
system
Breaking or better said destroying Encapsulation
When to use Checked Exceptions:
If the caller knows & wants how to handle it
When dealing with Critical Systems or libraries
Error HandlingRaya Software
51. Rule #4: Don’t Eat the Exception
Error HandlingRaya Software
try {
callBadMethod();
} catch (Exception ex) { }
bad
try {
callBadMethod();
} catch (Exception ex) {
ex.printStackTrace();
}
Good
Motive:
At least use the printStackTrace method or
you will never know anything about it.
Moreover to do is logging it.
52. Rule #5: Resist Temptation to write a
Single Catchall
Exception handlers that trap many errors at
once will probably reduce the reliability of
your program
More probably the an exception will be
caught and the handler will not know about
it.
Error HandlingRaya Software
53. Rule #6: Always use Catchall after
handling known ones
You can’t be sure that the exceptions you
handled is the only ones
So append them by the default catchall to
protect your system.
Error HandlingRaya Software
54. Rule #8: Don’t Return NULL
Look how NULL makes code awful:
Solution:
Returning a special case object.
Wrapping our method with another that throws exception.
“The only method that returns NULL is the one
you didn’t implement”
Error HandlingRaya Software
UserValidator.java
public void registerItem(Item item) {
if (item != null) {
ItemRegistry registry = peristentStore.getItemRegistry();
if (registry != null) {
Item existing = registry.getItem(item.getID());
if (existing.getBillingPeriod().hasRetailOwner()) {
existing.register(item);
}
}
}
}
55. Rule #9: Don’t Pass NULL
If returning null from methods is bad, then
passing null into methods is far worse
Passing NULL should be handled inside the
method or NullPointerException will be
thrown
Unless the used API is passing NULL, you
should avoid it whenever possible
Error HandlingRaya Software