Coding Convention

From Developer Documents
Revision as of 11:34, 13 October 2010 by Toni Kalajainen (talk | contribs)
Jump to navigation Jump to search

Simantics coding conventions are gathered in this document. These rules apply to all org.simantics projects and are recommended for anyone developing with Java. By following a common set of rules, a huge load of debugging hours are avoided.

Argument Assumption

  • All method arguments are non-null unless explicitely stated otherwise in documentation.

The default assumption is that an argument is non-null. This applies to undocumented methods too.

<syntaxhighlight lang="java">

   /**
     * Read the object from a file.
     *
     * @param file 
     */
   void read(File file);
   // and
   void read(File file);

</syntaxhighlight>


A null possibility must be explicitely stated.

<syntaxhighlight lang="java">

   /**
     * Write or remove existing value.
     *
     * @param newValue new value or null</t> to remove the existing value
     */
   void setValue(Object newValue);

</syntaxhighlight>



Return value assumption

  • All return values are non-null unless explicitely stated otherwise in documentation.

The thumb rule is that the return value is non-null. It applies to undocumented methods aswell.

<syntaxhighlight lang="java">

   /**
     * Get the value
     *
     * @return the value
     */
   Object get();
   // and
   Object get();

</syntaxhighlight>


Null option as return value is always explicitely documented.

<syntaxhighlight lang="java">

   /**
     * Get possibly existing value
     *
     * @return the value is exists, otherwise null
     */
   Object get();

</syntaxhighlight>



Trust your assumptions

  • You have a code of conduct - give it a chance.

The callee can trust the caller.

<syntaxhighlight lang="java">

   BigInteger multiply(BigInteger a, BigInteger b) throw IOException {
       return a.multiply(b);
   }

</syntaxhighlight>

And the caller the callee.

<syntaxhighlight lang="java">

   System.out.println( multiply(a, b) );

</syntaxhighlight>


In most cases there is no good reason to do redundant checking, especially at run-time.

<syntaxhighlight lang="java">

   BigInteger multiply(BigInteger a, BigInteger b) throw IOException {
       if ( a == null || b == null ) throw IllegalArgumentException("Non-null argument is expected");
       return a.multiply(b);
   } 

</syntaxhighlight>

Nor caller.

<syntaxhighlight lang="java">

   Object x = multiply( a, b );
   if ( x != null ) System.out.println( x );

</syntaxhighlight>



Use assertions if you must. Checking still improves quality a bit and helps in early detection of problems. Assertion is not considered as run-time checking as they can be disabled from the VM.

<syntaxhighlight lang="java" style="background: #dfd;">

   BigInteger multiply(BigInteger a, BigInteger b) throw IOException {
       assert( a != null && b != null );
       return a.multiply(b);
   }

</syntaxhighlight>


Maintenance and migration

These rules apply to code that is published and in wide use.

  • API doesn't change between minor releases.

In case of faulty design, old methods are preserved and are marked @Deprecated. They can be removed in the next major version release.

<syntaxhighlight lang="java">

   @Deprecated
   Object getValue(Object newValue);

</syntaxhighlight>

  • Documentation is correct, the implementation is faulty.

In case there is a mismatch between the documentation and the implementation, then the documentation prevails and the fault is in the implementation.


In this example the method returns an unexpected null.

<syntaxhighlight lang="java">

   /**
    * Deserialize an object from an input stream.
    *
    * @param is source stream
    * @return the object
    **/
   Object deserialize(InputStream is) {
       try {
           int x = is.read();
           ...
           return result;
       } catch (IOException e) {
          return null;
       }
   }

</syntaxhighlight>

The assumptions that can be derived from the documentation is unchanged and the implementation is corrected.

<syntaxhighlight lang="java">

   /**
    * Deserialize an object from an input stream.
    *
    * @deprecated use deserialize2, it has better error control
    * @param is source stream
    * @return the object
    * @throws RuntimeIOException in case of IO problems
    **/
   Object deserialize(InputStream is) throws RuntimeIOException
   {
       try {
           int x = is.read();
           ...
           return result;
       } catch (IOException e) {            
           throw new RuntimeIOException( e );
       }
   }

</syntaxhighlight>

It can be replaced with correct method in the next major version release.

<syntaxhighlight lang="java">

   /**
    * Deserialize an object from an input stream.
    *
    * @param is source stream
    * @return an object
    * @throws IOException in case of problems
    **/
   Object deserialize(InputStream is) throws IOException
   {
       int x = is.read();
       return result;
   }

</syntaxhighlight>