Personal tools
You are here: Home gvSIG Projects gvSIG Desktop Documentation Developers documentation gvSIG devel guide gvSIG 2.0. Developers guide Coding and Development Standards
gvSIG Desktop
gvSIG Desktop

Cached time 11/21/13 16:58:54 Clear cache and reload

 


Coding conventions

Forewords

This document describes a list of coding conventions that are required for code submissions to the project. By default, the coding conventions for most Open Source Projects should follow the existing coding conventions in the code that you are working on. For example, if the bracket is on the same line as the if statement, then you should write all your code to have that convention.

If you commit code that does not follow these conventions and you are caught, you are responsible for also fixing your own code.

Below is a list of coding conventions that are specific to gvSIG, everything else not specificially mentioned here should follow the official Sun Java Coding Conventions

Why code conventions

As explained in the Sun Java Coding Conventions:

Code conventions are important to programmers for a number of reasons:

  • 80% of the lifetime cost of a piece of software goes to maintenance.
  • Hardly any software is maintained for its whole life by the original author.
  • Code conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly.
  • If you ship your source code as a product, you need to make sure it is as well packaged and clean as any other product you create.

How to apply?

Having coding conventions is nice but having a way to ensure they are applied is even better ... :-)

The gvSIG maven configuration has a checkstyle target which performs coding conventions using the Checkstyle tool.

Please run this target before committing any code.

Also the eclipse configuration needed to format the source code taking into account the code conventions defined in the current document will be available in the org.gvsig.maven.base.build project, from the gvsig-tools OSOR project.

If the project you are working with has a prepare-workspace.xml file which you have used to configure your workspace, you will have those files already downloaded and available into the folder:

WORKSPACE/org.gvsig.maven.base.build/eclipse-configs

Otherwise, you may download all the files through the repository URL:

https://devel.gvsig.org/svn/gvsig-tools/org.gvsig.maven.base/trunk/org.gvsig.maven.base/org.gvsig.maven.base.build/src/main/resources/org.gvsig.maven.base.build/eclipse-configs/

To import those configurations perform the following:

  1. Clean up:
    • Go to Window > Preferences > Java > Code Style > Clean Up and click the button Import.
    • In the file system explorer, select the clean_up.xml file.
images/clean_up_optim.png
  1. Code templates:
    • Go to Window > Preferences > Java > Code Style > Code Templates and click the button Import.
    • In the file system explorer, select the code_templates.xml file.
    • Activate the option Automatically add comments for new methods and types.
images/code_templates_optim.png
  1. Formatter:
    • Go to Window > Preferences > Java > Code Style > Formatter and click the button Import.
    • In the file system explorer, select the formatter.xml file.
images/formatter_optim.png
  1. Organize imports:
    • Go to Window > Preferences > Java > Code Style > Organize Imports and click the button Import.
    • In the file system explorer, select the organize_imports.importorder file.
images/organize_imports_optim.png

gvSIG specific coding conventions

Mandatory conventions
  1. Headers

    Look at the Headers document for more information.

  2. Indentations

    4 spaces. NO tabs.

  3. Javadoc

    All API interfaces and classes must be fully documented through javadocs comments at interface/class, method and package level.

    When you inherit or extend from another interface or class which is already documented, and implement or rewrite one of the parent methods, don't write any javadoc comments, as they are also inherited since java 1.4.

  4. Brackets

    All brackets should begin at the end of the line that begins the statement, and end on a new line indented to the beginning of the statement. Example:

    AVOID:

    public class MyClass 
    {
    
        public void someMethod() 
        {
            if (...) { // Do something }
    }
    }
    

    RIGHT:

    public class MyClass {
    
        public void someMethod() {
            if (...) {
              // Do something
            }
        }
    }
    

    Brackets are mandatory even for single line statements:

    if (expression)       // AVOID!
        // some code
    
    if (expression) {     // RIGHT
        // some code
    }
    
  5. Blank Spaces

    Keywords followed by a parenthesis should be separated by a space. Example:

    while (true) {
        // some code
    }
    

    Blank space should appear after commas in argument lists. Binary operators should be separated from their operands by spaces:

    a += c + d;
    a = (a + b) / (c * d);
    
    while (d++ = s++) {
        n++;
    }
    
    printSize("size is " + foo + "\n");
    
  6. Class variables

    Class variables should not have any prefix or suffix related to its data type or scope. Example:

    String nameString;   // AVOID!
    
    String name;         // RIGHT
    
  7. Parameter names

    Method parameters should be prefixed by "the" for differentiating them from inner variables, when there is an inner variable with the same name or use. For example:

    public void someMethod(String theClassName) {
        String className; // inner variable
    }
    
  8. Line length

    Avoid lines longer than 80 characters for Code, comments, ...

  9. Versioning

    All .java files should have a @version tag like the one below into the class javadoc comment:

    @version $Id$
    
  10. Logging

    Do not use System.out to log. Instead, use the SLF4J logging API. For example:

    private static final Logger LOG = 
        LoggerFactory.getLogger(MyClass.class);
    
    public void someMethod() {
        LOG.debug("some debug text");
    }
    

    For more information on SLF4J usage, you can read the Logging document.

  11. Exception handling

    Managing exceptions correctly requires experience. This is not supposed to be a guide on managing exceptions, simply a few best practices.

    • Rule 1: Try to catch exceptions as much as possible and rethrow higher level exceptions (meaning hiding the low level detailed and putting a message that is more related to the function of your code).
    • Rule 2: It is important not to loose the stack trace which contains important information. Use chained exceptions for that.
    • Rule 3: Always log the exception at the higher level (ie. where it is handled and not rethrown).
    • Rule 4: Try to avoid catching Throwable or Exception and catch specific exceptions instead.
    • Rule 5: Create one parent Exception for each API library, so methods of the API that throw any exception use that parent exception or one of the child ones.
    • Rule 6: If you have an exception or an error which can't be handled or resolved by code, throw or rethrow a BaseRuntimeException subclass.

    An example:

    public void getTestClass() {
        try {
            Class responseClass =
                Class.forName("some.package.MyClass");
        } catch (ClassNotFoundException cnfe) {
            String message = "Cannot instantiate test class";
            LOG.error(message, ex);
            throw new ChainedRuntimeException(message, e);
        }
    }
    
  12. Qualified imports

    All import statements should containing the full class name of classes to import and should not use the "*" notation: An example:

    // AVOID!
    import java.util.*;
    import java.net.*;
    
    // RIGHT
    import java.util.Date;
    import java.net.HttpURLConnection;
    
  13. Use interfaces in the declaration of methods and variables.

    By example, if you need a variable x that is a list, declare it as List instead an ArrayList:

    // AVOID!
    ArrayList x = new ArrayList();
    HashMap y = new HashMap();
    
    public HashMap create(ArrayList keys, ArrarList values) {
        ...
    }
    
    // RIGHT
    List x = new ArrayList();
    Map y = new HashMap();
    
    public Map create(List keys, List values) {
        ...
    }
    
  14. API packages

    Usually, API interfaces and classes will belong to the library's main root package. If you create subpackages, use them to group by functionality, not by type.

  15. How to name packages

    All packages must begin with org.gvsig.

    For more information on this convention, you can read the How to name packages document.

Advised conventions
  1. How to name interfaces and classes

Attention!

TODO

For more information on this convention, you can read the How to name interfaces and classes document.

Nomenclature for classes and interfaces

Introduction

This document defines rules for naming classes and interfaces that allow a common style for gvSIG components to be maintained.

The importance of consistency in naming is obvious if one considers a complete Javadoc implementation. From the point of view of the reader, using a variety of naming conventions would create confusion and complicate the understanding of the component.

Criteria to follow

Use of prefixes and suffixes in general

The use of prefixes and/or suffixes in the names of classes and interfaces is usually a means of providing information about their nature and/or task. For example they can be used to denote a pattern, or a role within a pattern (eg the suffix Factory). At other times, it is necessary to use them if the appropriate name has already been assigned. This is the case of the prefixes and suffixes that are described below.

As a general rule:

  • Only use a prefix or suffix when you can't use the simple name (usually because it is being used by another class or interface).
Using the prefix "Abstract"
  • Only to be used for classes, not interfaces.
  • The class must be abstract and implement an interface.
  • Only used when the interface being implemented has the same name.

Example:

public interface List {}
public abstract class AbstractList extends AbstractCollection implements List {}
Using the prefix "I"
  • It is recommended that this prefix not be used.

    Typically, the interfaces are the visible part of a component model. They usually represent entities and concepts from the business or domain and therefore it is recommended that the same names be used as in the business.

Using the prefix "Default"
  • Can't be an abstract class.
  • A default implementation of an interface or an abstract class.
  • The implementation should be sufficient, but not necessarily complete.
  • There may be alternative implementations of this class.

Example:

public interface ListModel {}
public abstract class AbstractListModel implements ListModel, Serializable {}
public class DefaultListModel extends AbstractListModel {}
Using the prefix "Base"
  • Not an abstract class.
  • Provides a "base" implementation of an interface or an abstract class.
  • The class can be instantiated and not used any more, but is designed for the user of the extended component.
  • Do not use this prefix if no interface or parent abstract class exists.

Example:

public abstract class StreamRequestHandler {}
public class BaseHTTPRequestHandler extends StreamRequestHandler {}
Using the suffix "Impl"
  • It is a class instance and therefore can't be abstract
  • It is a complete implementation of an interface or abstract class, generally referred to as the class without the "impl".
  • Other classes should not be extended from it.
  • Do not use this suffix unless the class name conflicts with the name of the interface or abstract class being implemented.
  • If this is the default implementation of part of the API and does not conflict with other parts of the project, the prefix Default is preferred.

Example:

public interface Plane {}
public abstract class AbstractPlane implements Plane {}
 
// Both are correct (but not equal)
public class PlaneImpl implements Plane {} 
public class PlaneImpl extends AbstractPlane {}

Application Conditions

This criterion is applicable to new developments undertaken for gvSIG 2.0 and will be part of the official gvSIG distribution as well as for all developments financed in whole or in part by the CIT.

Names of packages used in gvSIG

Preliminary considerations

Due to the variability and lack of unity in the names of packages used in gvSIG 1.X, it has been decided to standardize these, thereby giving the project an identity that over-rides that of the company doing the development.

Criteria to follow

When creating java packages that will be part of an official gvSIG release, or that will carry the official endorsement of the gvSIG project, the following package is appended:

org.gvsig

No mention is made in the package of the company doing the development.

Normally, the package name org.gvsig is followed by a package name identifying the logical or functional block that it contains.

Application Conditions

These criteria will be applied to new developments to be made to gvSIG 2.0, and will be part of the official gvSIG distribution as well as for all developments financed in whole or in part by the CIT.

Logging

In gvSIG the SLF4J library is used as a logging API.

The Simple Logging Facade SLF4J is a framework that is designed to abstract the underlying logging system. As Log4j is the most popular logging system in use, the framework's API is very similar to simply removing the direct dependence of this system. This framework is therefore an abstraction layer of the logging system and will allow us to change the underlying components without having to undertake major recoding of the application.

Features of SLF4J

  • SLF4J is an abstraction layer independent of any actual logging system.
  • Allows the end user to attach the desired implementation at deployment time.
  • Allows gradual migration from Jakarta Commons Logging (JCL), because it has a JCL API wrapper in its own API.
  • There is a parameterized logging system that reduces the overhead of assessing the message strings, especially when debug messages are enabled.
// Those lines produce the same results. The second one has parameters that reduce the overhead when debugging is disabled
LOG.debug("The new entry is "+entry+"."); 
LOG.debug("The new entry is {}.", entry);
  • Support for Mapped Diagnostic Context (MDC), if the logging system operating under SLF4J supports it. At the moment only Log4j and logback do so.
  • Logging systems may choose to implement the SLF4J interface directly as logback and SimpleLogger, or write SLF4J adapters for a given implementation as in the cases of Log4jLoggerAdapter and JDK14LoggerAdapter.
  • Does not delegate to a specific class loading system (class loader) for delegating to a specific logging system, ie statically configured at compile time, only allowed to use one and only one logging system. Simply add the logging system API's jar to the CLASSPATH, together with slf4j-api.jar. This avoids the problems of class loading and memory loss suffered by Jakarta JCL.
  • SLF4J also has an interface very similar to the JCL and Log4j APIs currently in use, so the implementation effort is significantly reduced.
  • gvSIG continues to use the same logging toolkit (Log4j) so there will be practically no changes at run time.
  • You gain in flexibility, robustness and efficiency through the ability to change the logging component without modifying the gvSIG source code, either for all versions of gvSIG or for specific versions.
  • It's the standard that has been collected in OSGI projects because projects that are already using commons-logging can be adapted easily due to the popularity that this framework has gained.

Using SLF4J in gvSIG

gvSIG 2.0 is ready to work with SLF4J, using LOG4J as implementation, and can be used directly from any gvSIG extension.

To use SLF4J from a Java class just include the following statements:

1.- Import the necessary classes:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

2.- Declare and initialize the Logger:

public class MyClass
{
    private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
    ...

3.- We use the Logger within the code of the class when we want to display a log message, depending on the type: error, warning, information, debug or trace:

LOG.warn(String message);
LOG.warn(String message,Object arg1);
LOG.warn(String message,Object[] arg1);
LOG.warn(String message, Throwable arg1);
LOG.info(String message);
LOG.info(String message,Object arg1);
LOG.info(String message,Object[] arg1);
LOG.info(String message, Throwable arg1);
LOG.error(String message);
LOG.error(String message,Object arg1);
LOG.error(String message,Object[] arg1);
LOG.error(String message, Throwable arg1);
LOG.debug(String message);
LOG.debug(String message,Object arg1);
LOG.debug(String message,Object[] arg1);
LOG.debug(String message, Throwable arg1);
LOG.trace(String message);
LOG.trace(String message,Object arg1);
LOG.trace(String message,Object[] arg1);
LOG.trace(String message, Throwable arg1);

The following methods are provided to check the activation of messages for each level:

LOG.isErrorEnabled();
LOG.isWarnEnabled();
LOG.isInfoEnabled();
LOG.isDebugEnabled();
LOG.isTraceEnabled();

In addition, the messages can also be customized in SLF4J by inserting variables into the String of the log message, as in the following example:

private Integer temperature;

public void setTemperature(Integer temperature) {

    LOG.debug("Setting temperature to {}. Old temperature was {}.", temperature, this.temperature);

    this.temperature = temperature;

    if(temperature.intValue() > 50) {
      LOG.info("Temperature has risen above 50 degrees.");
    }
}

This stops us from having to concatenate Strings, which reduces the cost of using the instructions for logging. This is because, although the log level that we are using is disabled (for example, debug), the method call will be made anyway, including the concatenation of strings to build the message, if any.

However, if the obtaining of any of the parameters to be passed to the message log proves costly, it is convenient to use the consultation methods to avoid such implementation. For example:

private Integer temperature;

public void setTemperature(Integer temperature) {

    LOG.debug("Setting temperature to {}. Old temperature was {}.", temperature, this.temperature);

    this.temperature = temperature;
    addToTemperatureLog(temperature);

    if (LOG.isDebugEnabled()) {
        LOG.debug("The current average temperature is {} Celsius", calculateAverageTemperature());
    }
}

Headers


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: