Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Clean Code

Clean Code

Slides for presentation I gave at Equal Experts client in New York.

anildigital

April 11, 2016
Tweet

More Decks by anildigital

Other Decks in Programming

Transcript

  1. – Martin Fowler “Any fool can write code that a

    computer can understand. Good programmers write code that humans can understand.”
  2. Kent Beck’s Design Rules • Runs all the tests •

    Expresses all the design ideas that are in the system / Reveals intention • Contains no duplication • Minimises the number of entities such as classes, methods, functions, and the like / Fewest elements (Remove anything that doesn’t follow fi rst 3) http://martinfowler.com/bliki/BeckDesignRules.html
  3. Names • Use intention revealing names 
 int d; //

    elapsed time in day s • Instead use 
 int elapsedTimeInDays;
  4. Use Intention revealing names • See this 
 // BAD

    public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1; ‚Àè } • After changing names and magic numbers 
 // GOOD public List<Cell> getFlaggedCells() { List<Cell> fl aggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) fl aggedCells.add(cell); return fl aggedCells; }
  5. Use pronounceable names • If you can’t pronounce it, you

    can’t discuss it 
 class DtaRcrd102 { private Date genymdhms; private Date modymdhms; private fi nal String pszqint = "102"; /* ... */ } ; • better this way 
 class Customer { private Date generationTimestamp; private Date modi fi cationTimestamp;; private fi nal String recordId = "102"; /* ... */ };

  6. Use searchable names • Make this searchable • MAX_CLASSES_PER_STUDENT is

    more searchable than 7 • Avoid encoding • AccountImpl • IShapeFactory • Do not add unnecessary pre fi xes, like pre fi xing name of the project before every class
  7. Naming consistency • Classes and objects should be nouns •

    Manager, Generator, Processor • Method names should start with verbs • isValid(), getUsername();
  8. Naming consistency • Pick one word per concept (No synonyms)

    • Don’t mix concepts • Don’t be cute • Don’t pun • Use Solution Domain Names (Programmer friendly) • Use Problem Domain Names (Domain friendly)
  9. Scope Rule • Smaller the scope of the variable smaller

    the name • Larger the scope of the variable larger the name.
  10. Small functions • Functions should be small • 4 to

    5 lines are good. • More than 10 lines is big. • Smaller functions are easy to understand. • Large functions are less reusable. • Large functions may include functionality that belong in different classes. • Large functions may hide the classes. • Smaller well named functions in well named classes will make it easier to navigate the code
  11. Small functions • Instead of adding a comment on a

    code block, extract it into a method with name same as the comment. • Minimise number of local variables. • Minimise indentations in a method. • Do one thing.
  12. Same level of abstraction • All the statements in a

    function should be at one level of abstraction 
 void compute() { input(); fl ags|= 0x0080; output(); } • If the statements are not at one level of abstraction extract them in functions with meaningful names. • Functions having one abstraction level are likely to do one thing.
  13. Function arguments • Keep the function arguments to the minimum.

    Usually less than 3 variables. 
 Circle makeCircle(double x, double y, double radius); Circle makeCircle(Point center, double radius) ; • Avoid boolean parameters. 
 doMakeResponse(context, request, true ) • Avoid passing in nulls or returning nulls. • Use objects or maps when you need many arguments.
  14. Argument objects Circle makeCircle(double x, double y, double radius) ;

    Circle makeCircle(Point center, double radius);
  15. Switch cases • Functions with switch statements are likely to

    do N things. • Switch cases are likely to get scattered throughout the code. • Open ended switch violates OCP.
  16. Example • Consider this method of Bird class: 
 double

    getSpeed() { switch(type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * numberOfCoconuts; case NORWEGIAN_BLUE: return (isNailed) ? 0 : getBaseSpeed(voltage); } }
  17. Polymorphism abstract class Bird { abstract double getSpeed() } class

    European extends Bird { double getSpeed() { return getBaseSpeed(); } } class African extends Bird { double getSpeed() { return getBaseSpeed() - getLoadFactor() * numberOfCoconuts; } } class NorwegianBlue extend Bird { double getSpeed() { return (isNailed) ? 0 : getBaseSpeed(voltage); } } Bird European African Norwegian Blue
  18. When switch statements are harmless • When there is no

    possibility of more cases. • When switch is used for creation of Polymorphic objects. Like in a Factory. • When switch cases are managed locally and can not scatter throughout the system.
  19. Objects • Objects should hide their internal structure. • Follow

    ‘Tell Don’t Ask’ (Law of Demeter). • Avoid train wrecks - Don’t ask. 
 ((EditSaveCustomizer) master.getModelisable() .getDockablePanel() .getCustomizer()) .getSaveItem().setEnabled(Boolean.FALSE.booleanValue()) ; • Instead tell the object to perform task 
 master.allowSavingOfCustomisations();
  20. Classes • Classes should be small. • Small classes follow

    Single Responsibility Principle (SRP). • Avoid God classes. (Avoid doing everything with single class) • The class should be cohesive.
  21. Cohesion • Classes should have a small number of instance

    variables. • More variables a method manipulates the more cohesive that method is to its class. • The more cohesive the methods are the more cohesive the class will be. • We want the classes to have high cohesion. • When classes lose cohesion, split them!
  22. SOLID Principles • SRP — Single Responsibility Principle • OCP

    — Open Closed Principle • LSP — Liskov’s Substitution Principle • ISP — Interface Segregation Principle • DIP — Dependency Inversion Principle
  23. Comments • Explain yourself in code 
 // Check to

    see if the employee is eligible for full bene fi ts
 if ((employee. fl ags & HOURLY_FLAG) && (employee.age > 65)) // or this? if (employee.isEligibleForFullBene fi ts())
  24. Comments • Comments represent bad code. • If you need

    comments to understand what the code is doing then the code is poorly written
  25. Accepted comments, but not always! • Legal comments • Informative

    comments e.g. warning comments 
 // format matched kk:mm:ss EEE, MMM dd, yyyy Pattern timeMatcher = Pattern.compile ( "\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d* ” ) ; • TODO comments • Javadocs in Public API • For ampli fi cation
  26. Good comments • Explanation of intent 
 public void testConcurrentAddWidgets()

    throws Exception { … //This is our best attempt to get a race condition //by creating large number of threads. for (int i = 0; i < 25000; i++) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, parent); Thread thread = new Thread(widgetBuilderThread); thread.start(); } … } •
  27. Bad comments • Mumbling 
 public void loadProperties() { try

    { String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE; FileInputStream propertiesStream = new FileInputStream(propertiesPath); loadedProperties.load(propertiesStream); } catch(IOException e) { // No properties fi les means all defaults are loaded } } •
  28. Formatting • Good formatting code is important • Follow code

    style of your organisation. If not present, create one.
  29. Exception handling • Use exceptions instead of returning error codes.

    • Use unchecked exceptions • Provide context with exceptions. • Don’t return null • Don’t pass null Clean code is readable, but it must also be robust.
  30. Code smells • Long method • solution - Extract method

    into many smaller auxiliary methods • Large class • solution - Apply single responsibility principle • Duplicate code • Too many parameters • Comments • …
  31. Clean tests • One Assert per Test • Single Concept

    per Test 
 public void testAddMonths(){ SerialDate d1 = SerialDate.createInstance(31, 5, 2004); SerialDate d2 = SerialDate.addMonths(1, d1); assertEquals(30, d2.getDayOfMonth()); assertEquals(6, d2.getMonth()); assertEquals(2004, d2.getYYYY()); }
  32. Clean Tests - FIRST • Fast • Run quickly •

    Independent • should not depend on each other • Repeatable • ability to run tests in any environment • Self-validating • should have boolean output, either pass or fail • No need to manually check the logs • Timely • Unit tests should be written just before the production code that makes them pass
  33. Refactoring • Don’t afraid of changing code to make it

    better • Always leave the campground cleaner than you found it. — The Boy Scout Rule • Refactor when tests are green (Apply TDD) • Follow DRY