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. Clean Code
    Anil Wadghule

    View Slide

  2. – Martin Fowler
    “Any fool can write code that a computer can
    understand. Good programmers write code that
    humans can understand.”

    View Slide

  3. View Slide

  4. 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

    View Slide

  5. Software Entropy
    • The Broken Window


    • Don’t leave code with broken windows.

    View Slide

  6. Clean Code: A Handbook of Agile Software Craftsmanshi
    p

    by Robert C. Martin

    View Slide

  7. Naming

    View Slide

  8. Names
    • Use intention revealing names



    int d; // elapsed time in day
    s

    • Instead use



    int elapsedTimeInDays;

    View Slide

  9. Use Intention revealing
    names
    • See this

    // BAD
    public List getThem() {
    List list1 = new ArrayList();
    for (int[] x : theList)
    if (x[0] == 4) list1.add(x);
    return list1; ‚Àè
    }
    • After changing names and magic numbers

    // GOOD
    public List getFlaggedCells() {
    List
    fl
    aggedCells = new ArrayList();
    for (Cell cell : gameBoard)
    if (cell.isFlagged())
    fl
    aggedCells.add(cell);
    return
    fl
    aggedCells;
    }

    View Slide

  10. 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";
    /* ... */
    };


    View Slide

  11. 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

    View Slide

  12. Naming consistency
    • Classes and objects should be nouns


    • Manager, Generator, Processor


    • Method names should start with verbs


    • isValid(), getUsername();

    View Slide

  13. 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)

    View Slide

  14. Scope Rule
    • Smaller the scope of the variable smaller the
    name


    • Larger the scope of the variable larger the
    name.

    View Slide

  15. Functions

    View Slide

  16. 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

    View Slide

  17. 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.

    View Slide

  18. 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.


    View Slide

  19. Command Query Separation
    • Function should either do something or answer
    something, doing both is confusing

    View Slide

  20. 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.

    View Slide

  21. Argument objects
    Circle makeCircle(double x, double y, double radius)
    ;

    Circle makeCircle(Point center, double radius);

    View Slide

  22. The Stepdown Rule
    • Reading code from Top to Bottom


    • Follow Stepdown rule

    View Slide

  23. Switch cases

    View Slide

  24. 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.

    View Slide

  25. 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);


    }
    }

    View Slide

  26. 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

    View Slide

  27. 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.

    View Slide

  28. Class / Object

    View Slide

  29. 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();

    View Slide

  30. 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.

    View Slide

  31. 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!

    View Slide

  32. SOLID Principles
    • SRP — Single Responsibility Principle


    • OCP — Open Closed Principle


    • LSP — Liskov’s Substitution Principle


    • ISP — Interface Segregation Principle


    • DIP — Dependency Inversion Principle

    View Slide

  33. Single Responsibility
    Principle
    • A class should have only one reason for change

    View Slide

  34. Open Closed Principle
    • A class should be easy to extend without
    changes

    View Slide

  35. Liskov’s Substitution
    Principle
    • Subclasses mustn’t change expected behaviour

    View Slide

  36. Interface Segregation
    Principle
    • Interfaces shouldn’t force classes to implement
    useless methods

    View Slide

  37. Dependency Inversion
    Principle
    • High level and low level code should depend on
    abstractions.

    View Slide

  38. Comments

    View Slide

  39. 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())

    View Slide

  40. Comments
    • Comments represent bad code.


    • If you need comments to understand what the
    code is doing then the code is poorly written

    View Slide

  41. — Brian W. Kernighan and P. J. Plaugher
    “Don’t comment bad code—rewrite it.”

    View Slide

  42. 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

    View Slide

  43. 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();


    }

    }

    View Slide

  44. 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
    }
    }

    View Slide

  45. Formatting
    • Good formatting code is important


    • Follow code style of your organisation. If not
    present, create one.

    View Slide

  46. 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.


    View Slide

  47. 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


    • …

    View Slide

  48. 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());


    }

    View Slide

  49. 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

    View Slide

  50. 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

    View Slide