Clean code

1,239 views
979 views

Published on

My talk about Robert C. Martin's book "Clean Code: A Handbook of Agile Software Craftsmanship".

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,239
On SlideShare
0
From Embeds
0
Number of Embeds
16
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Clean code

  1. 1. Clean CodeBe a little more careful with the code you write!Ana Cortés Corbalán05.02.2013
  2. 2. What? Why? How?05.02.2013 2 www.consol.com
  3. 3. The only valid measurement of code quality: WTFs/minute05.02.2013 3 www.consol.com
  4. 4. What is Clean Code?§  Simple §  Efficient§  No duplications §  Elegant§  Direct §  Focused§  With tests §  Minimal dependencies§  It was written by someone who cares§  ...§  Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler05.02.2013 4 www.consol.com
  5. 5. Why is clean code so important?§  Easier to read§  Easier to understand§  Easier to change §  Add new features §  Find and fix bugs§  Cheaper to maintain§  Code quality is part of software quality05.02.2013 5 www.consol.com
  6. 6. Use Intention-Revealing Names§  int d;!§  int days;!§  int days; //days since creation!§  int daysSinceCreation;!05.02.2013 6 www.consol.com
  7. 7. Use Intention-Revealing Names§  What is the purpose? public List<int[]> getValues() {! List<int[]> list1 = new ArrayList<int[]>();! for (int[] x : theList)! if (x[0] == 4) list1.add(x);! return list1;! }!05.02.2013 7 www.consol.com
  8. 8. Use Intention-Revealing Names§  Better? ! public List<Cell> getFlaggedCells() {! List<Cell> flaggedCells = new ArrayList<Cell>();! for (Cell cell : gameBoard) ! if (cell.isFlagged()) flaggedCells.add(cell);! return flaggedCells;! }! !05.02.2013 8 www.consol.com
  9. 9. Don´t talk in code – Use Pronounceable Names class DtaRcrd102 {
 private Date genymdhms;
 private Date modymdhms;
 private final String pszqint = "102"; /* ... */ ! }!§  Better? class Customer {
 private Date generationTimestamp; ! private Date modificationTimestamp; ! private final String recordId = "102"; /* ... */ ! }!05.02.2013 9 www.consol.com
  10. 10. More recommendations...§  Class names Customer, Account, AddressParser, ...§  Method names postPayment, deletePage, ....§  When constructors are overloaded... new Complex(23.0);! Complex.fromRealNumber(23.0); !§  Pick one word per concept get, fetch, retrieve...§  Don´t be cute. Jokes out of the code. public void saveTheUniverse() {...}05.02.2013 10 www.consol.com
  11. 11. Bad Comments§  Redundant, noise, irrelevant, obsolet, „funny“ comments /**! * Returns the day of the month. *! * @return the day of the month. */! public int getDayOfMonth() {! return dayOfMonth;! }! ! /** Always return true. **/! public boolean isAvailable() {! !return false;! }! ! //Magic. Do not touch ! /* Added by Ana Cortés (4-4-2008) */!05.02.2013 11 www.consol.com
  12. 12. Bad Comments /** ! * Dear maintainer:! * ! * Once you are done trying to optimize this routine,! * and have realized what a terrible mistake that was,! * please increment the following counter as a warning! * to the next guy:! * ! * total_hours_wasted_here = 42! **/!§  Commented-Out Code InputStreamResponse response = new InputStreamResponse();! response.setBody(formatter.getResultStream(), ft.getByteCount()); ! //  InputStream resultsStream = formatter.getResultStream(); ! //  StreamReader reader = new StreamReader(resultsStream); ! //  response.setContent(reader.read(formatter.getByteCount())); !05.02.2013 12 www.consol.com
  13. 13. Good Comments§  Legal comments // Copyright (C) 2003 by Object Mentor, Inc. All rights reserved.
 // Released under the terms of the GNU General Public License version 2 or later. !§  Informative, clarification comments // format matched kk:mm:ss EEE, MMM dd, yyyy ! Pattern timeMatcher = Pattern.compile("d*:d*:d* w*, w* d*, d*"); !§  Amplification comments String listItemContent = match.group(3).trim(); ! // the trim is real important. It removes the starting ! // spaces that could cause the item to be recognized
 // as another list.
§  TODO comments§  Javadocs in Public APIs05.02.2013 13 www.consol.com
  14. 14. Functions - Small!!public static String testableHtml( PageData pageData,booleanincludeSuiteSetup) throws Exception {
 WikiPage wikiPage = pageData.getWikiPage();! StringBuffer buffer = new StringBuffer();! if (pageData.hasAttribute("Test")) {! if (includeSuiteSetup) {! WikiPage suiteSetup =PageCrawlerImpl.getInheritedPage( SuiteResponder. SETUP_NAME, wikiPage);
 ! if (suiteSetup != null) {! WikiPagePath pagePath =suiteSetup.getPageCrawler().getFullPath(suiteSetup);! String pagePathName = PathParser.render(pagePath); ! buffer.append("!include -setup .").append(pagePathName).append("n");! } ! }! WikiPage setup = PageCrawlerImpl.getInheritedPage("SetUp",wikiPage);!... 40 lines more!05.02.2013 14 www.consol.com
  15. 15. Functions - Small!!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(); !}!!!§  Better?!public static String renderPageWithSetupsAndTeardowns (PageData pageData,boolean isSuite) throws Exception { ! if (isTestPage(pageData)) ! includeSetupAndTeardownPages(pageData, isSuite); ! return pageData.getHtml(); !} ! !05.02.2013 www.consol.com! 15
  16. 16. Command query separation§  What does it mean? public boolean set(String attribute, String value);!! if (set("username", "unclebob")) { ... } !
!§  Better? if (attributeExists("username")) { ! setAttribute("username", "unclebob"); ! } !05.02.2013 16 www.consol.com
  17. 17. Don´t return null§  Throw exceptions or return special case object! List<Employee> employees = getEmployees(); ! if (employees != null) { ! for(Employee e : employees) { ! totalPay += e.getPay(); ! } ! } !!§  How to remove != null in the code? public List<Employee> getEmployees() { ! if( .. there are no employees .. ) ! return Collections.emptyList(); ! } !!!05.02.2013 17 www.consol.com
  18. 18. Don´t return nullpublic void registerItem(Item item) { ! if (item != null) { ! ItemRegistry registry = persistentStore.getItemRegistry();! if (registry != null) { ! Item existing = registry.getItem(item.getID());
 if (existing.getBillingPeriod().hasRetailOwner()) { ! existing.register(item); ! } ! } ! } !} !!05.02.2013 18 www.consol.com
  19. 19. Have no side effects§  Where is the side effect?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; !} !05.02.2013 19 www.consol.com
  20. 20. Prefer exceptions to returning error codesif (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; !} !!!public enum error {! OK, INVALID, NO_SUCH, LOCKED, OUT_OF_RESOURCES;!}!05.02.2013 20 www.consol.com
  21. 21. Prefer exceptions to returning error codes§  Better?public void delete(Page page) { ! try { ! !deletePageAndAllReferences(page); ! } ! catch (Exception e) {! logError(e); ! } !} !!private void deletePageAndAllReferences(Page page) throws Exception { ! deletePage(page);
 registry.deleteReference(page.getName()); ! configKeys.deleteKey(page.getKey()); !}!!private void logError(Exception e) {! logger.log(e.getMessage());!}!05.02.2013 21 www.consol.com!
  22. 22. Keeping tests cleanpublic void testGetPageHierarchyAsXml() throws Exception { ! crawler.addPage(root, PathParser.parse("PageOne")); ! crawler.addPage(root, PathParser.parse("PageOne.ChildOne")); crawler.addPage(root, PathParser.parse("PageTwo")); ! request.setResource("root"); ! request.addInput("type", "pages");
 Responder responder = new SerializedPageResponder(); ! SimpleResponse response = ! (SimpleResponse) responder.makeResponse( new FitNesseContext(root), request); ! String xml = response.getContent(); ! assertEquals("text/xml", response.getContentType()); assertSubString("<name>PageOne</name>", xml); assertSubString("<name>PageTwo</name>", xml); assertSubString("<name>ChildOne</name>", xml); !} !!05.02.2013 22 www.consol.com
  23. 23. Keeping tests clean§  Better?! public void testGetPageHierarchyAsXml() throws Exception { ! makePages("PageOne", "PageOne.ChildOne", "PageTwo");! ! submitRequest("root", "type:pages"); ! ! assertResponseIsXML(); ! assertResponseContains( ! "<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>" ); ! } !!05.02.2013 23 www.consol.com
  24. 24. Summary§  Read „Clean Code“ book.§  Be a little more careful with the code you write §  Write with the „audience“ in mind§  Follow the „Boy Scout Rule“ §  Leave the campground cleaner than you found it §  Use tools that help you cleaning up§  Write Clean Tests05.02.2013 24 www.consol.com
  25. 25. Thank you! Danke! Gracias! !05.02.2013 25 www.consol.com

×