How to write good code

Why to spend more time on writing good code

  • From my observations, most of the time the quality of new code matches the state of the present code. As a result, if we let our code rotten a little bit, then people will stop caring about the quality and it will turn into mess eventually (broken window effect).
  • It is worth to follow the rule that we leave the code better than it was by small refactorings (e.g. changing names of methods/variables to better ones), so that it will bring more pleasure to work with the code in the future.
  • Productivity of the team significantly decreases as the code gets more messy.
  • We want to keep the code clean all the time so that we don’t need to rewrite the project again.
  • What is good clean code

  • Is clearly focused on its purpose and not surrounded by extra irrelevant data. When objects or methods do no more that one thing, then objects should be divided into two or more and methods should be extracted to submethods specialized in one task.
  • Has clear and minimal API providing one way rather than many ways of doing things.
  • Is well tested by unit and acceptance tests.
  • Has no duplications.
  • Early implements tiny abstractions – e.g. piece of code that queries for objects should delegate calls to particular implementations, hidden by abstractions, to handle specific type of data store like file, db, memory etc.
  • Class, variable and method names should be self-explanatory and clearly say what the do or what they represent and they are used, e.g.

    int secondsSinceLogin;
    int elapsedTimeInHours;

    or instead method copy(int[] a, int[] b) write copy(int[] source, int[] destination).
  • Names should not introduce confussion, e.g. don’t name a variable productList when it doesn’t represent a List or even better avoid introducing names containing types, e.g. userString or userList, just call it name and users. By doing this you will avoid situations when after type refactoring you will get variable name not matching its type: e.g. User userString.
  • Choose names that you would guess their meaming without comments or javadoc, e.g. class: UserDao, method: User findById(long id). When constructor accepts two or more arguments of the same type, consider changing it to factory method having more descriptive name, e.g.:class ConnectionChecker {
    public static ConnectionChecker createWithTimeoutAndRetryIntervalInSeconds(int timeout, int retryInterval){ ... };
    }
    .
  • Don’t use names that are visually similar to each other, e.g. int mmnm; and int mnmm; Avoid using capital O and lower-case l as they are very similar to zero and one digits.
  • Agree to one naming convention, don’t use e.g. ProductInfo, ProductData at the same time. The names mean the almost the same.
  • Use names that are easy to pronounce, e.g. instead Date moddmymhs use Date modyficationTimestamp.
  • Single-letter characters like i,j,k can be used as counters only in small loops. Using them as regular variables in the code makes it has to remember what they mean. Remember, clarity is very important.
  • Use well named variables that are easy searchable.
  • Extract numbers into self-descriptive variables or constants.
  • Consider using enums to replace ints when defining types, e.g. instead public static final int MONDAY=1;
    ...
    public static final int SUNDAY=7;

    use

    enum DAY {
    MONDAY, ..., SUNDAY;
    }

  • Don’t use Hungarian Notation – don’t use member prefixes “_m” like int m_id in strongly typed languages such as Java. After some time, programmers will ignore the prefixes, what makes them useless and unnecessarily polluting the code.
  • Use small classes and short methods so you can see variables declaration an its usage on one screen.
  • Prefer the convention – don’t prefix interfaces with legacy “I” but use suffix “Impl” for interface implementation classes.
  • Try to be more specific about class names rather than suffixing them with general-purpose words like Manager, Processor, Data or Info. Use nouns for class names.
  • Use verbs or verb phrases to for method names, e.g. send(), deleteProduct() or isValid().
  • Use get, set or is prefixes for accessors and mutators according to Java Beans standard
  • Since not all IDEs support comments and/or argument names for auto-suggested methods, use names describing arguments for factory names, e.g. Circle.createFromRadius(int radius);
  • Be consistent for naming – agree to one concept – don’t use at the same time one class retrieveEmployer(), in other getCompany() and in the third – fetchPayment().
  • Don’t use the same word for different purposes, e.g. use add() for returning the sum of two numbers but insert() to add element into collection to avoid confusion.
  • Use technical names for computer science terms, algorithms and patterns, e.g. CompanyVisitor for Visitor Pattern.
  • Use names from the problem domain.
  • Place the names in the meaningful context by enclosing them in well named classes, methods or namespaces. Only if that fails, use prefix for clarity:class Person {
    String addrState
    String addrCity;
    }

    Encapsulating address details in Address is a better approach (see below) but if it not possible for some reason, then prefixing state with addr makes it clearer what Person state means.

    Address {
    String state;
    String city;
    }
    class Person {
    Address address;
    }

    Methods
    Should be very small (less that 20 lines), small functions can have more descriptive names.

    Should have maximum two level of indentation i.e. should have max two nested conditional structures (if, while, for etc …).

    For better readability conditional statement should contain just one line – a method call.

    Refactor code from:
    if (condition1 || contition2 ... ) {
    long block of code ...
    }

    to
    if (areConditionsMet(args...)){
    a call to helper method with descriptive name
    }
    private boolean areConditionsMet(args ...) {
    return condition1 || contition2;
    }

    Don’t mix methods with different levels of abstraction in one function, i.e. don’t mix high level render html method with low level method adding line break character.

    Method should do only one thing at the level of abstraction described by its name.

    Extract another method if its name is not a restatement of its implementation. It makes little sense to extract if (contition) { doSth(); } into doSthIfCondition()

    Follow the top-down order in method location in a class, e.g. if a public method m1() contains two helper methods m1.1() and m1.2(), and each of these helper methods contain a separate helper method m1.1.1() and m1.2.1() and a common helper method m1.12.1():

                m1
               /   \
           m1.1    m1.2
          /    \    /    \
    m1.1.1    m1.12.1    m1.2.1
    

    then the order of method definitions could be m1(), m1.1(), m1.1.1(), m1.2(), m1.12.1(), m1.2.1().

    Try to refactor switchcase statements which call different methods for each case into polymorphic execution (strategy pattern). The switchcase statements do more than one thing (violate Single Resposiblity Principle), tend to grow large and need to be changed whenever new behavior is added (violate Open Closed Principle – open for extension, closed for modification).

    Do as little as possible inside constructors. If you want to test a method of a class, you need to instantiate it but not necessarily you want to execute all the logic just after instantiation. Furthermore, you cannot override constructor, so you cannot skip or change this extra logic that is done along the object creation. For testing purposes, you’d better provide a default-package-access constructor with arguments of its dependencies which assign these dependencies to class fields. By doing this, that you have flexibility to configure you class under test whatever you like, e.g. you can mock some dependencies. Sometimes certain object are instantiated / wired by a framework or created by others, so try to avoid putting logic into constructors.

    Advertisements
  • Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s