Chapter 51. Coding and Design Guidelines

Table of Contents

51.1. Introduction
51.2. External Coding Standards
51.3. Some points that need attention
51.3.1. Java code formating
51.3.2. XML code formatting
51.3.3. Design
51.3.4. Unit tests
51.3.5. Security
51.3.6. Naming convention
51.3.7. Information hiding
51.3.8. Use modern Java features
51.3.9. Logging
51.3.10. Documentation: Comments and Javadoc
51.3.11. Deprecation
51.4. Methodology tips
51.4.1. Use the power of your IDE (and its plugins)
51.4.2. Refactor
51.5. Important references

51.1. Introduction

 

"Follow a common coding standard, so that all the code in the system looks as if it was written by a single — very competent — individual. The specifics of the standard are not important: what is important is that all the code looks familiar, in support of collective ownership."

 
 --Ron Jeffries XProgramming.com
 

Coding Standards are a good idea. Every team should adopt a coding style and standard, and stick to it. The code produced by that team should have a consistent look and feel that is devoid of individual preferences and fetishes.

 
 --"Uncle" Bob Martin ObjectMentor website

The primary goal of this chapter is to provide common conventions, as well as guidelines that aim at ensuring a high level of quality (with respect to maintainability, extensibility, modularity, security, testability, documentation, etc.) throughout the Nuxeo project.

As such, it is primarily written for the platform's developers, both "core" developers and contributors, and developers that write extension modules that will someday find a place in the Nuxeo codebase.

If you're working on your own project with no plan to contribute code to the Nuxeo platform, you will probably be still interested in reading this chapter, and adapt the conventions stated here to your company's or organization's own coding standards.

51.2. External Coding Standards

Rewriting a whole coding standard for the Nuxeo project would be a poor use of our time, since there are already several documents and books that do a fine job in this respect.

We've opted for a more pragmatic, two-pronged approach:

  1. reference reputable external guides or books, and document any difference
  2. propose default settings for common Eclipse tools (including the built-in code formatter and the CheckStyle plugin), tuned to comply to these conventions.

The official coding standard for the project is: "The Elements of Java Style" [Vermeulen2000] which is a little book that can be bought from Amazon or other book dealers.

If a PDF suits you better, you can download an earlier version of the book from here.

Note however that these guidelines have been written in 2000 (last century!) and some of the recommendations need the be updated in light of this millenium's experience.

There are also architectural guidelines that need to be followed. At this moment, they are written here (section 4 - "Guidelines")

51.3. Some points that need attention

51.3.1. Java code formating

 

Readability counts.

 
 --Tim Peters The Zen of Python

Java code should be formatted using Sun's Code Conventions for the Java Programming Language.

Regarding code formatting (which is just one small part of the book and PDF mentioned above), we'll be using the standard Eclipse default style, with a couple of minor tweaks (see this README.txt for how to configure Eclipse to support this style).

The major points are:

  • 4 spaces (no tabs!!!) indentation
  • spaces before and after = signs and most binary operators
  • spaces after ,
  • no space after ( or before )
  • regarding code block, we are using 1TBS ("One True Brace") style:

    Bad:

        if (xxx)
        {
            yyy
        }

    Good:

        if (xxx) {
            yyy
        }
  • make a block even for only one statement:

    Bad:

        if someThing() doSomething;
    
        if someThing()
            doSomething;

    Good:

        if someTest() {
            doSomething;
        }
  • Don't prefix your instance variables by "this." when it's not mandatory.

    Why? Because with modern IDEs, instance variables are typeset in a different color than local variables, hence you don't need the extra information provided by the "this." prefix to recognize which is which.)

  • etc.

51.3.2. XML code formatting

  1. XML code should also be formatted, using 2 spaces for each indent level (not 4 spaces).

    Badly formatted XML code can be reformatted using the Eclipse formatter.

    Always check that the result is better than the original, and tweak afterwards if needed.

51.3.3. Design

  1. Use interfaces every time it is possible instead of concrete classes.

    Ex: declare a variable or argument as a "Map", not as a "HashMap".

    Why? Using interfaces makes it possible to use several different implementations. Actually, interfaces are the basis of component-oriented programming.

  2. But don't overdo it if it's not necessary.

    Why? The more code we have, the more expensive maintainance is.

  3. Avoid cyclic dependencies.

    Why? This is a common design principle, called the "Acyclic Dependency Principle" or "ADP".

    How? use JDepend or a JDepend plugin for you IDE (ex: http://andrei.gmxhome.de/jdepend4eclipse/) or look at the JDepend report by Maven.

    More info:

51.3.4. Unit tests

 

If it's not tested, it's broken.

 
 --Bruce Eckel
  1. Write unit tests. A lot.

    How? Learn how to use JUnit. Use tests in existing modules as examples. Remember that well-tested modules have at least as many lines of test code than not test code.

  2. Check that your unit tests have a coverage of most of the critical parts of your code.

    How? Look at the Cobertura report by Maven, or use the TPTP or EMMA (http://www.eclemma.org/) plugins for Eclipse or use the native code-coverage function of IDEA.

  3. Design your API so as to make unit testing possible and easy.

    See API Design As If Unit Testing Mattered

Some cosmetic remarks related to writing unit tests:

  1. Use "assertEquals(constant, value)", not "assertEquals(value, constant)"

    Why? Because one has to choose a convention and this one

  2. Use "assertNull(value)", not "assertEquals(null, value)"

    Why? Because code is shorter and looks cleaner this way.

51.3.5. Security

  1. Read Graff and van Vyk's "Secure Coding" [Graff2003] book. More info on the securecoding.org website.
  2. If you don't have access to the book, read at least Secure Coding: The State of the Practice (including the Architectural Principles, the Design Ideas and the Java Tips sections) from one of the two authors.
  3. Read these slides from JavaOne 2006.

51.3.6. Naming convention

  1. Don't use underscores ("_") in variables, methods or class names, use camelCase notation instead.

    Why? Because it is the Java convention.

  2. Check some good articles on naming things, like Ottinger's Rules for Variable and Class Naming.

    It is especially important that we all use the same words (in case there is an ambiguity) to refer to the same concepts (like "fetch" vs. "retrieve", for instance).

51.3.7. Information hiding

  1. Minimize the accessibility of classes and members (for instance by making them "private" unless you have a reason to believe that they will be used from other classes, and more generally by using the weakest access modifier ), so as to keep you API clean and easy to understand for other developers.

    Reference: "Effective Java" [Bloch2001], item 12.

51.3.8. Use modern Java features

  1. Use Java 5's "foreach" construct instead of explicit iterators whenever possible (which is not always the case).
  2. Use java 5's generics.

    Why? This will improve the amount of static checks done by the compiler.

51.3.9. Logging

Follow this piece of advice from Alex Miller:

My opinion is that there are 4 log levels that matter for general program logging (specialized logs like audit and performance have their own rules). I dont care what you call them so feel free to replace these with the names of your choice.

  • ERROR - an error has occurred in the program (usually an exception). All internal or unexpected failures should be logged at ERROR level. Programmers should care about anything logged as an error. User errors (like input validation) should generally NOT be logged at ERROR level. These are expected (if invalid) inputs and you should respond to the user appropriately (another post altogether), but this is not a program error. Exceptions may be made for things like repeated invalid password attempts that are likely security problems.
  • WARNING - an anomalous condition has been detected and the program will attempt to deal with it. No action needs to be taken externally but you might be interested if things go down in flames 5 minutes later. The conditions for warnings are relatively rare but an example would be reaching a warning threshold on a connection pool or a loss of connectivity that can be repaired by reconnecting to the same or different source.
  • INFO - an interesting piece of information that helps to give context to a log, often when things are starting or stopping. INFO messages should never be printed on a per transaction (whatever that means to you) path through the code. That is, INFO messages should be 1-time or very occasional messages.
  • DEBUG - whatever your OCD programmer mind desires.

The first three levels (ERROR, WARNING, and INFO) should always be on. If your logs grow rapidly with these levels on, something is wrong. You should be able to run in production with these levels for weeks without a problem (but you should really use a rolling log writer just in case). DEBUG should be used only during development for debugging.

51.3.10. Documentation: Comments and Javadoc

 

Reuse is something that is far easier to say than to do. Doing it requires both good design and very good documentation. Even when we see good design, which is still infrequently, we won't see the components reused without good documentation.

 
 --D. L. Parnas The Mythical Man-Month: Essays on Software Engineering
  1. Always use comments to document what is not obvious.

    Why? Otherwise, it will be harder for others (even you!) to maintain or extend your code. Some people may even end up refactoring your code under wrong assumptions.

    See for instance item #28 of Bloch's "Effective Java" [Bloch2001] for more insight, including this most important principle:

    The doc comment for a method should describe succinctly the contract between the method and its client. With the exception of methods in classes designed for inheritance, the contract should say what the method does rather than how it does its job.

  2. Write javadocs according to the javadoc manual and the official Sun javadocs guidelines.

    Why? Because javadocs are compiled by a standard tool, you must conform to the syntax mandated by this tool.

  3. Common javadoc guidelines that are often forgotten include:

    • Don't include XML tags without escaping the < and > characters.
    • Remember that the first sentence (i.e. everything until the first dot) is used as a short description of the package / class / method / etc. it documents. Hence end all your sentences with a dot.
    • Use <p> for separating paragraphs, not <br> or
    • Don't use </p> in the source though as it is useless and rather bad looking.
    • If your javadoc starts with "This class" or "This methods", this is most probably wrong.
  4. Proofread carefully (including checks for spelling and grammar errors) and check that your javadocs provide useful information for third-party developers (or your teammates) by actually reading the generated doc.

    How? See either "Project -> Generate Javadocs" from Eclipse, or "mvn javadoc:javadoc" from the project root and browse the docs.

    Remember that you can see a preview of how your javadoc will look like from Eclipse by using the "Javadoc" tab in the Java perspective.

  5. Don't mix Javadoc comments with implementation comments.

    Javadocs comments are intended to be read by clients of the API, implementation comments by people who need to review you code or who will end up maintaining it (including yourself).

    For instance, don't put "TODO" markers in your javadoc because they are intended for yourself or other people co-developing or maintaining your code, not clients of the API.

  6. Start by documenting the most important and less obvious things.

    If you don't have enough time to document everything, document first the API part of your code (usually, the interfaces), because that's what third-party developers are going to use.

    Also documenting the non-obvious (like giving an overview of a package or an important class) is more important than writing for instance, that a "getTitle()" method "@returns the title".

  7. Write package-level javadocs.

    Package-level Javadoc (just package.html files in your source code) are the most important javadocs you have to write, because that's what people reading the javadoc-generated site will read first, and because that's where the information is usually the less obvious.

  8. Sign your code (in the modules headers).

    It is very important that people who will read / maintain your code know that you are the author, so that they can ask you questions, give you feedback, etc.

  9. When you've borrowed code from another open source project, always document it so that:

    • we are sure that there is no license conflict with the original code
    • we understand why the code in question doesn't follow our own coding conventions or isn't unit-tested as it should (it should anyway, but this is another story)
  10. Put markers as (inline) comments to document parts of your code that will need further work.

    • use FIXME for really serious (like, release-blocking) issues.
    • use the TODO for remaining tasks.
    • don't use XXX which is usually associated with inappropriate content.
    • use BBB to mark code used to ensure compatibility with a deprecated feature, that will be removed after a certain release.
    • do not leave TODO markers behind when they are not relevant (for instance for dummy classes used in tests and auto-generated by the IDE from an interface or an abstract class).
  11. Look critically at the javadoc-generated site and try to improve it.

    Either go to http://maven.nuxeo.com/apidocs/ and check the apidoc for your project, or run mvn javadoc:javadoc locally and browse the generated apidoc, and ask yourself the simple question: "if I was a third-party developer, would I understand how to use the API by reading this".

51.3.11. Deprecation

  1. Don't use deprecated features (= API), either from Java or third-party libraries, or from the Nuxeo framework.

    Hint: they should appear as stroked-out in your IDE.

  2. Deprecate your own API when you have to, but make sure you write comments that explain to your API's clients how to migrate from the old API to the new one. Use BBB markers (see above) if needed.
  3. Deprecated APIs should be maintained at least for 1 release cycle, at least for external clients of the APIs, but we should strive to switch to the new APIs internally in 1 release cycle.

51.4. Methodology tips

Here are a few points and tips to keep in mind.

51.4.1. Use the power of your IDE (and its plugins)

Modern IDEs (+ adequate plugins, if necessary) include many code-checking functions that help find out issues:

  1. For Eclipse, the simplest plugin to use is TPTP.

    How?

    • Use the update manager to get the TPTP plugins.
    • Right-click on your project, and select "Analysis".
    • Enable all the rules, and run the analysis on your module.
    • Fix the issues that appear serious (you still have to think).
  2. You should also use the Checkstyle and FindBugs Eclipse plugins to ensure minimal bug count and maximal coding style coherence.

    See these great slides from JavaOne 2007 for instance.

  3. Read Improving code with Eclipse plugins on developerWorks for more background information on the subject.

    From the article:

    This article covers what I consider to be the "big five" code analysis areas:

    • Coding standards
    • Code duplication
    • Code coverage
    • Dependency analysis
    • Complexity monitoring

    These analysis areas can be uncovered using a number of the following slick Eclipse plugins:

    • CheckStyle: For coding standards
    • PMD's CPD: Enables discovering code duplication
    • Coverlipse: Measures code coverage
    • JDepend: Provides dependency analysis
    • Eclipse Metrics plugin: Effectively spots complexity

    NB: Coverlipse may or may not work correctly, an alternative is EclEmma which is very similar.

51.4.2. Refactor

  1. When something looks wrong in the code ("smell"), refactor it, but make sure you don't break anything.

    How?

    • Check that the code you are refactoring is covered by some unit tests.
    • Refactor. (Tip: a modern IDE (Eclipse and IDEA for instance) has some functions that may help.)
    • Check that the code still compiles (including dependent modules) and all the unit tests are still passing, and commit.

51.5. Important references

Here is a list of useful stuff to read:

  1. Joshua Bloch's "Effective Java" [Bloch2001] book. Highly recommended. Probably the best "advanced" Java book.
  2. Joshua Bloch's "Designing Effective API" slides and video.
  3. ObjectMentor's design articles (click on "Design Principles"), the most important one being Principles and Patterns.