CLEAN CODE A handbook of agile
software craftsmanship
THE BOOK
WHAT IS CLEAN CODE?
GOOD VS BAD?
for (int j=0; j<34; j++) {
s += (t[j]*4)/5;
}
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;
}
NAMING
1) Use intention-revealing names
2) The bigger the scope of the variable, the longer the name should
be
3) Use pronounceable and searchable names
4) Class and object names should be nouns or noun phrases
5) Method names should be verbs or verb phrases
WHAT IS THE PROBLEM?
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;
}
}
FUNCTIONS
1) Function should be small. Ask yourself can it be smaller?
2) Should do only one thing
3) Should have descriptive names
4) Optimally should have zero arguments or 1 or 2. Avoid function
with more than 2 arguments => easy to read, reason and test
5) Avoid flag arguments
6) Have no side effects
7) Arguments should be inputs not outputs:
appendFooter(report) vs report.appendFooter()
8) Prefer exceptions to returning error codes to avoid deep nested
structures and Enum class
9) Extract error handling
DO YOU NEED COMMENTS?
// Check to see if the employee is eligible
for full benefits
if ((employee.flags & HOURLY_FLAG)
&& (employee.age > 65))
if (employee.isEligibleForFullBenefits())
WHEN DO WE NEED COMMENTS
1) Legal terms (copyright, …)
2) Explanation, clarification
// format matched kk:mm:ss EEE, MMM dd, yyyy
Pattern timeMatcher = Pattern.compile("d*:d*:d* w*, w* d*, d*");
3) Warning of bad consequence
expedia engine
4) TODO comments
5) Javadocs for public APIs
FORMATTING
1) Vertical openness between concepts
2) Lines of code that are tightly related should appear vertically dense
3) Variables should be declared as close to their usage as possible
4) If one function calls another, they should be vertically close
5) Indentation based on hierarchy of scopes
python enforces it
HOW CAN YOU IMPROVE THIS
CODE?ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceResponseException e) {
reportPortError(e);
logger.log("Device response exception", e);
} catch (ATM1212UnlockedException e) {
reportPortError(e);
logger.log("Unlock exception", e);
} catch (GMXError e) {
reportPortError(e);
logger.log("Device response exception");
} finally {
…
}
ERROR HANDLING
1) Better raise exception than returning error codes
2) Provide context with the exceptions through error message or log
message
3) Define custom exceptions in terms of caller’s needs
4) Don’t return null
3 LAWS OF TDD
First Law 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 TEST
1) 1 assert per test?
2) Single concept per test
3) Unit tests should be F.I.R.S.T
Fast Tests should be fast. They should run quickly
Independent Tests should not depend on each other.
Repeatable Tests should be repeatable in any environment.
Self-Validating The tests should have a boolean output. Either they
pass or fail.
Timely The tests need to be written in a timely fashion. Unit tests
should be written just before the production code that makes them
pass.
CLASS
1) Class should be small
2) High cohesion between instance variables and methods
3) Open for extension, closed for changes
Is out FlightsTestCaseGenerator too big?

Clean code

  • 1.
    CLEAN CODE Ahandbook of agile software craftsmanship
  • 2.
  • 3.
  • 4.
    GOOD VS BAD? for(int j=0; j<34; j++) { s += (t[j]*4)/5; } 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; }
  • 5.
    NAMING 1) Use intention-revealingnames 2) The bigger the scope of the variable, the longer the name should be 3) Use pronounceable and searchable names 4) Class and object names should be nouns or noun phrases 5) Method names should be verbs or verb phrases
  • 6.
    WHAT IS THEPROBLEM? 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; } }
  • 7.
    FUNCTIONS 1) Function shouldbe small. Ask yourself can it be smaller? 2) Should do only one thing 3) Should have descriptive names 4) Optimally should have zero arguments or 1 or 2. Avoid function with more than 2 arguments => easy to read, reason and test 5) Avoid flag arguments 6) Have no side effects 7) Arguments should be inputs not outputs: appendFooter(report) vs report.appendFooter() 8) Prefer exceptions to returning error codes to avoid deep nested structures and Enum class 9) Extract error handling
  • 8.
    DO YOU NEEDCOMMENTS? // Check to see if the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) if (employee.isEligibleForFullBenefits())
  • 9.
    WHEN DO WENEED COMMENTS 1) Legal terms (copyright, …) 2) Explanation, clarification // format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher = Pattern.compile("d*:d*:d* w*, w* d*, d*"); 3) Warning of bad consequence expedia engine 4) TODO comments 5) Javadocs for public APIs
  • 10.
    FORMATTING 1) Vertical opennessbetween concepts 2) Lines of code that are tightly related should appear vertically dense 3) Variables should be declared as close to their usage as possible 4) If one function calls another, they should be vertically close 5) Indentation based on hierarchy of scopes python enforces it
  • 11.
    HOW CAN YOUIMPROVE THIS CODE?ACMEPort port = new ACMEPort(12); try { port.open(); } catch (DeviceResponseException e) { reportPortError(e); logger.log("Device response exception", e); } catch (ATM1212UnlockedException e) { reportPortError(e); logger.log("Unlock exception", e); } catch (GMXError e) { reportPortError(e); logger.log("Device response exception"); } finally { … }
  • 12.
    ERROR HANDLING 1) Betterraise exception than returning error codes 2) Provide context with the exceptions through error message or log message 3) Define custom exceptions in terms of caller’s needs 4) Don’t return null
  • 13.
    3 LAWS OFTDD First Law 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.
  • 14.
    UNIT TEST 1) 1assert per test? 2) Single concept per test 3) Unit tests should be F.I.R.S.T Fast Tests should be fast. They should run quickly Independent Tests should not depend on each other. Repeatable Tests should be repeatable in any environment. Self-Validating The tests should have a boolean output. Either they pass or fail. Timely The tests need to be written in a timely fashion. Unit tests should be written just before the production code that makes them pass.
  • 15.
    CLASS 1) Class shouldbe small 2) High cohesion between instance variables and methods 3) Open for extension, closed for changes Is out FlightsTestCaseGenerator too big?