CLEAN CODE
The lecture is based on
 “Clean Code”, A Handbook of Agile Software Craftsmanship by
  Robert C. Martin
 Software Craftsmanship in Israel group meetings.




                                               Coby Sternlicht
                                                    Feb 2012
Agenda

1   • Why?

2   • Guidelines

3   • Good Methods

4   • Design Principles

5   • Code Smells
Why Clean Code?
Why clean code
•   Does what my customer needs
•   Is error free
•   Performs well
•   Is easy to change
•   Is as simple as possible
•   Maintainable
•   The psychological element

                      4
Clean Code definition




                5
Guidelines
• You are the author, writing for readers
• Keep clean over time
• “Leave the campground cleaner than you
  found it”




                                            6
How to write a

Good Method
The newspaper paradigm

Title

Summary


Details

http://www.heraldsun.com.au/news/breaking-news/apple-seeks-us-injunction-against-samsungs-galaxy-nexus/story-e6frf7jx-1226269183958
A “long” method - HtmlUtil.java /FitNesse
• Do you understand the function after three
  minutes of study?
  – Probably not




                        9
A “long” method - refactored
• What did I do?
  – method extractions
  – some renaming
  – A little restructuring


• Can you understand what the code does?



                             10
Writing a good method


    Principles
1. Smaller than a screenful
• Small, Small, Small
• Minimum lines of code
• Maximal nesting level of 2




                      12
2. Do one thing - do it well, do it only.
• The original code is:
  –   Creating buffers
  –   Fetching pages
  –   Searching for inherited pages
  –   Rendering paths
  –   Appending arcane strings
  –   Generating HTML…
• The re-factored code is:
  – including setups and teardowns into test pages



                              13
3. Choose Good Names
• Use intention-revealing, pronounceable, searchable
  names
   – bad: int d; // elapsed time in days
   – Good: int elapsedTimeInDays;
• Don’t use Hungarian Notation
   – // name not changed when type changed!
   – PhoneNumber   stPhone;
• Don’t be afraid to make a name long
• Don’t be afraid to spend time choosing a name
• Remember, if you can’t choose a descriptive name
   – Your function is probably too big
   – And does more than ONE THING
                                   14
4. Minimize the use of arguments
• Which is easier to understand?
   – includeSetupPage()
   – includeSetupPageInto(newPageContent)
• Arguments are hard
   – They take a lot of conceptual power.
   – They are at a different level of abstraction than the
     function name
   – Output arguments are difficult to understand
   – They are even harder from a testing point of view


                               15
5. Avoid flag arguments
• Passing a boolean into a function is bad practice
   – It complicates the signature of the method
   – This function does more than one thing
• Example:
   – render(true) is just plain confusing to a poor reader
       • Your IDE tells you that it is render(boolean isSuite)
       • Helps a little, but not that much
   – We should have split the function into two:
       • renderForSuite() and renderForSingleTest()




                                      16
6. No more than 3 arguments

• Zero arguments is ideal (niladic)
• Next comes one (monadic)
• Followed closely by two (dyadic)
• Three arguments (triadic) should be avoided where
  possible
• More than three (polyadic) requires very special
  justification



                         17
Dyadic functions
• A function with two arguments is harder to understand

• Example: Frequency.cs (GetNextDate)
• As a general rule, Dyadic aren’t that bad and sometimes
  necessary:
   – Point centerPosition = new Point(x, y);




                              18
Three arguments (Triads)
• Significantly harder to understand
   – Argument ordering
   – Pausing when reading
   – Ignoring unimportant details
• Example - assertEquals:
   – assertEquals(message, expected, actual)
   – Is first argument message or expected?
   – You do a double-take and then learn to ignore the message




                                    19
7. Side-effects are lies
• A function also does other hidden things
   – to the variables of it’s own class
   – to the parameters passed into the function
   – to system globals
• Creates temporal couplings and order dependencies
• If you must have a temporal coupling, you should make it
  clear in the name of the function
• Example:
   – checkPasswordAndInitializeSession
   – Obviously this does more than one thing




                                  20
7. Side-effects are lies
• Command and Query separation
• Example:
  public boolean set(String attribute, String value);

• This leads to:
     if (set("username", “unclebob"))...
• What does that mean?
   – Is it asking whether the “username” attribute was
       • previously set to “unclebob”?
       • successfully set to “unclebob”?
   – Is “set” a verb or an adjective


                                       21
7. Side-effects are lies – continued
• Renaming to checkIfAttributeExistsAndSet
   – helps a bit
• The real solution is to separate the command from the query

   if (attributeExists("username"))
   {
     setAttribute("username", "unclebob");
     ...
   }



                              22
8. Use exceptions and not error codes
• Error codes are a violation of command query
  separation
• Create lots of if statements
  – if (deletePage(page) == E_OK)
• Deeply nested structures
• The caller must deal with the error
  immediately


                       23
8. Use exceptions – Bad example
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;
}



                              24
8. Use exceptions – Good example
try {
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e) {
  logger.log(e.getMessage());
}


• Happy-path is easy to read
• Error processing code is separated


                           25
9. Don’t comment bad code—rewrite it

•   Failure to express ourselves in code
•   Not maintained
•   Don’t comment messy code, clean it!
•   Don’t comment-out code – DELETE IT
•   Example:
    // Check to see if the employee is eligible for full benefits
    if ((employee.flags & HOURLY_FLAG) &&
        (employee.age > 65))


• Instead - descriptive Method Name

     if (employee.isEligibleForFullBenefits())

                                 26
THREE SIMPLE DESIGN PRINCIPLES
1. DRY – Don’t repeat yourself
• Clone and modify programming
  – Creates Rogue Tile: bugs show up again and again
• When writing “DRY”:
  – Modification of any single element of a system does
    not change other logically-unrelated elements
  – All elements that are logically related, change
    predictably and uniformly




                            28
2. YAGNI - You aint gonna need it
• Maybe in the future…
• Disadvantages:
   – The time spent
   – Must be debugged, documented, and supported
   – May prevent implementing a necessary feature in the future due
     to constraints
   – Difficult to fully define when not needed
   – Code bloat
   – May not be known to programmers when they need it
   – Snowball effect – “Featuritis Crawleritis”
• Must be balanced: upcoming vital features, team
  expectations, part-time expert assistance, and logical
  completeness
                                 29
3. KISS - keep it short and simple
• Simplicity should be a key goal in design
• Unnecessary complexity should be avoided




                         30
CODE SMELLS
Code smells
• A symptom in a program that possibly
  indicates a deeper problem




                      32
Code smells - Comments
• Comments:
  –   Obsolete
  –   Redundant
  –   Poorly written
  –   Commented out code




                           33
Code smells - Methods
• Methods:
  –   Long
  –   Too many arguments
  –   Flags
  –   Dead Code




                           34
Code smells - DRY
• Code Duplication




                     35
Code smells - Obscured Intent
• Obscured Intent
• Code should be as expressive as possible
 public int m_otCalc()
  {
      return iThsWkd * iThsRte +
      (int) Math.round(0.5 * iThsRte *
      Math.max(0, iThsWkd – 400));
  }


                       36
Resources




                 Robert C.Martin



• Software Craftsmanship in Israel – a LinkedIn
  group.
Questions?




             38

Clean code, Feb 2012

  • 1.
    CLEAN CODE The lectureis based on  “Clean Code”, A Handbook of Agile Software Craftsmanship by Robert C. Martin  Software Craftsmanship in Israel group meetings. Coby Sternlicht Feb 2012
  • 2.
    Agenda 1 • Why? 2 • Guidelines 3 • Good Methods 4 • Design Principles 5 • Code Smells
  • 3.
  • 4.
    Why clean code • Does what my customer needs • Is error free • Performs well • Is easy to change • Is as simple as possible • Maintainable • The psychological element 4
  • 5.
  • 6.
    Guidelines • You arethe author, writing for readers • Keep clean over time • “Leave the campground cleaner than you found it” 6
  • 7.
    How to writea Good Method
  • 8.
  • 9.
    A “long” method- HtmlUtil.java /FitNesse • Do you understand the function after three minutes of study? – Probably not 9
  • 10.
    A “long” method- refactored • What did I do? – method extractions – some renaming – A little restructuring • Can you understand what the code does? 10
  • 11.
    Writing a goodmethod Principles
  • 12.
    1. Smaller thana screenful • Small, Small, Small • Minimum lines of code • Maximal nesting level of 2 12
  • 13.
    2. Do onething - do it well, do it only. • The original code is: – Creating buffers – Fetching pages – Searching for inherited pages – Rendering paths – Appending arcane strings – Generating HTML… • The re-factored code is: – including setups and teardowns into test pages 13
  • 14.
    3. Choose GoodNames • Use intention-revealing, pronounceable, searchable names – bad: int d; // elapsed time in days – Good: int elapsedTimeInDays; • Don’t use Hungarian Notation – // name not changed when type changed! – PhoneNumber stPhone; • Don’t be afraid to make a name long • Don’t be afraid to spend time choosing a name • Remember, if you can’t choose a descriptive name – Your function is probably too big – And does more than ONE THING 14
  • 15.
    4. Minimize theuse of arguments • Which is easier to understand? – includeSetupPage() – includeSetupPageInto(newPageContent) • Arguments are hard – They take a lot of conceptual power. – They are at a different level of abstraction than the function name – Output arguments are difficult to understand – They are even harder from a testing point of view 15
  • 16.
    5. Avoid flagarguments • Passing a boolean into a function is bad practice – It complicates the signature of the method – This function does more than one thing • Example: – render(true) is just plain confusing to a poor reader • Your IDE tells you that it is render(boolean isSuite) • Helps a little, but not that much – We should have split the function into two: • renderForSuite() and renderForSingleTest() 16
  • 17.
    6. No morethan 3 arguments • Zero arguments is ideal (niladic) • Next comes one (monadic) • Followed closely by two (dyadic) • Three arguments (triadic) should be avoided where possible • More than three (polyadic) requires very special justification 17
  • 18.
    Dyadic functions • Afunction with two arguments is harder to understand • Example: Frequency.cs (GetNextDate) • As a general rule, Dyadic aren’t that bad and sometimes necessary: – Point centerPosition = new Point(x, y); 18
  • 19.
    Three arguments (Triads) •Significantly harder to understand – Argument ordering – Pausing when reading – Ignoring unimportant details • Example - assertEquals: – assertEquals(message, expected, actual) – Is first argument message or expected? – You do a double-take and then learn to ignore the message 19
  • 20.
    7. Side-effects arelies • A function also does other hidden things – to the variables of it’s own class – to the parameters passed into the function – to system globals • Creates temporal couplings and order dependencies • If you must have a temporal coupling, you should make it clear in the name of the function • Example: – checkPasswordAndInitializeSession – Obviously this does more than one thing 20
  • 21.
    7. Side-effects arelies • Command and Query separation • Example: public boolean set(String attribute, String value); • This leads to: if (set("username", “unclebob"))... • What does that mean? – Is it asking whether the “username” attribute was • previously set to “unclebob”? • successfully set to “unclebob”? – Is “set” a verb or an adjective 21
  • 22.
    7. Side-effects arelies – continued • Renaming to checkIfAttributeExistsAndSet – helps a bit • The real solution is to separate the command from the query if (attributeExists("username")) { setAttribute("username", "unclebob"); ... } 22
  • 23.
    8. Use exceptionsand not error codes • Error codes are a violation of command query separation • Create lots of if statements – if (deletePage(page) == E_OK) • Deeply nested structures • The caller must deal with the error immediately 23
  • 24.
    8. Use exceptions– Bad example 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; } 24
  • 25.
    8. Use exceptions– Good example try { deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey()); } catch (Exception e) { logger.log(e.getMessage()); } • Happy-path is easy to read • Error processing code is separated 25
  • 26.
    9. Don’t commentbad code—rewrite it • Failure to express ourselves in code • Not maintained • Don’t comment messy code, clean it! • Don’t comment-out code – DELETE IT • Example: // Check to see if the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) • Instead - descriptive Method Name if (employee.isEligibleForFullBenefits()) 26
  • 27.
  • 28.
    1. DRY –Don’t repeat yourself • Clone and modify programming – Creates Rogue Tile: bugs show up again and again • When writing “DRY”: – Modification of any single element of a system does not change other logically-unrelated elements – All elements that are logically related, change predictably and uniformly 28
  • 29.
    2. YAGNI -You aint gonna need it • Maybe in the future… • Disadvantages: – The time spent – Must be debugged, documented, and supported – May prevent implementing a necessary feature in the future due to constraints – Difficult to fully define when not needed – Code bloat – May not be known to programmers when they need it – Snowball effect – “Featuritis Crawleritis” • Must be balanced: upcoming vital features, team expectations, part-time expert assistance, and logical completeness 29
  • 30.
    3. KISS -keep it short and simple • Simplicity should be a key goal in design • Unnecessary complexity should be avoided 30
  • 31.
  • 32.
    Code smells • Asymptom in a program that possibly indicates a deeper problem 32
  • 33.
    Code smells -Comments • Comments: – Obsolete – Redundant – Poorly written – Commented out code 33
  • 34.
    Code smells -Methods • Methods: – Long – Too many arguments – Flags – Dead Code 34
  • 35.
    Code smells -DRY • Code Duplication 35
  • 36.
    Code smells -Obscured Intent • Obscured Intent • Code should be as expressive as possible public int m_otCalc() { return iThsWkd * iThsRte + (int) Math.round(0.5 * iThsRte * Math.max(0, iThsWkd – 400)); } 36
  • 37.
    Resources Robert C.Martin • Software Craftsmanship in Israel – a LinkedIn group.
  • 38.

Editor's Notes

  • #6 There is no clear definitionA result of experience
  • #13 Functions should hardly ever be 20 lines long
  • #15 Don’t be afraid to spend time choosing a name - Modern IDEs make it easy to rename.