• Save
Clean code, Feb 2012
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,182
On Slideshare
1,064
From Embeds
118
Number of Embeds
3

Actions

Shares
Downloads
0
Comments
0
Likes
1

Embeds 118

http://www.linkedin.com 95
http://www.scoop.it 12
https://www.linkedin.com 11

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • There is no clear definitionA result of experience
  • Functions should hardly ever be 20 lines long
  • Don’t be afraid to spend time choosing a name - Modern IDEs make it easy to rename.

Transcript

  • 1. CLEAN CODEThe 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
  • 2. Agenda1 • Why?2 • Guidelines3 • Good Methods4 • Design Principles5 • Code Smells
  • 3. Why Clean Code?
  • 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. Clean Code definition 5
  • 6. Guidelines• You are the author, writing for readers• Keep clean over time• “Leave the campground cleaner than you found it” 6
  • 7. How to write aGood Method
  • 8. The newspaper paradigmTitleSummaryDetailshttp://www.heraldsun.com.au/news/breaking-news/apple-seeks-us-injunction-against-samsungs-galaxy-nexus/story-e6frf7jx-1226269183958
  • 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 good method Principles
  • 12. 1. Smaller than a screenful• Small, Small, Small• Minimum lines of code• Maximal nesting level of 2 12
  • 13. 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
  • 14. 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
  • 15. 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
  • 16. 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
  • 17. 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
  • 18. 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
  • 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 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
  • 21. 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
  • 22. 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
  • 23. 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
  • 24. 8. Use exceptions – Bad exampleif (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 exampletry { 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 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
  • 27. THREE SIMPLE DESIGN PRINCIPLES
  • 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. CODE SMELLS
  • 32. Code smells• A symptom 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. Questions? 38