December 20, 2014
Hot Topics:

Can IDEs Do More to Improve Code Quality? Part II

  • April 28, 2004
  • By Charles-Philip Bentley and Baudouin Le Charlier
  • Send Email »
  • More Articles »

Not so long ago, when you wanted to do a task such as renaming a class or a variable identifier, you had to do it manually. That was error-prone and time consuming. Today, one should use refactoring operations that enforce code and comments synchronization. In Eclipse, when the insertion point is on an identifier, one may rename it with the action "Refactor-> Rename". The IDE automatically updates the source code in all relevant files.

Nevertheless, Eclipse does not synchronize references in comments. It is a hard problem indeed to solve with the current comment language. Here is a simple illustration of the problem:

/** The car's name is now name
 */
public void setName(String name) {
       _carNameString = name;
}

In the preceding Javadoc comment, how can the IDE know which occurrence of "name" refers to the parameter? Our brain knows it because it understands a complex language. In "The car's name is now name", Eclipse sees text with no special meaning. String equality as a criterion is not acceptable, because comment text could then become "The car's aliceName is now aliceName". One has to use a syntactic construct that enables the IDE to distinguish between template text and normal text. In the Javadoc paradigm, one could define an inline Javadoc tag for variables.

/** The car's name is now {@var name}
 */
public void setName(String name) {
       _carNameString = name;
}

With the extended Javadoc definition, the refactoring tools are now able to synchronize comments correctly. Nevertheless, such new syntactic conventions can be tedious to use. Eventually, there is a need for designing ergonomic tools that diminish the overhead generated by those notational conventions. As discussed in Part I, the overhead generated by the {@var } construct can be diminished with the Code Completion feature.

The inline @var tag is not officially supported. One needs an IDE supporting custom Javadoc tags.

Custom Javadoc Tags for Better Code

A few IDEs fully support custom Javadoc tags. The current Eclipse milestone is not among those. One can expect custom tags support in the near future, though.

Custom tags enable developers to more tightly integrate the use of design by contract concepts; the most important ones are pre conditions, post conditions, and class invariants.

Pre-conditions and post-conditions

A condition is an expression whose result is a Boolean value. Conditions are applied to Java methods in the following way:

  • Pre-conditions are a set of conditions one has to comply with before using the method protected by the pre-conditions.
  • Post-conditions are a set of conditions that must hold when the method returns.

In the current official Javadoc tool, there are no pre-condition and post-condition tags. That information, if not missing, is often spread over the whole Javadoc comment. In the official setup, one can write anything because there are no templates to follow after the tag name. The IDE is a possible place for defining an extended documentation language and enforce its syntax rules.

The main benefit of extending the documentation language is a better specification structure that:

  • Enables tools to compute things in background and inform the developer of any results or errors.
  • Allows one to find relevant information more quickly.

Invariants

Class invariants express general consistency constraints that apply to each instance as a whole. Invariants are conditions that must hold:

  • after a constructor returns.
  • before a method call.
  • after a method returns.

Possible use of invariants: case study

This section describes a mechanism that can reduce occurrences of the ubiquitous NullPointerException in Java. The following code defines the Car class implementing the IWeighable interface.

/**
 * Defines a Car
 * @author Charles-Philip Bentley
 */
public class Car implements IWeighable {
   /**
    * Constant to use for null owner names
    */
   public static final String NULL_OWNER = "NOBODY";
   /**
    * @def the name of the car owner
    * @inv _ownerName!=null use {@link Car#NULL_OWNER} for
    *                  creating a car without an owner
    */

One can see two custom tags. The @def tag gives a natural language description of the _ownerName field. The @inv tag defines a class invariant on the _ownerName field. Provided the IDE is aware of the meaning of those tags, it can take charge of many tasks and automatically report problems to the user. If one declares the following constructor:

public Car(String ownerName) {
   _ownerName = ownerName;
}

An IDE is able to generate a rich skeleton:

/**
 * @pre ownerName!=null use {@link Car#NULL_OWNER} for
 *                 creating a car without an owner
 * @param ownerName the name of the car owner
 */
public Car(String ownerName) {
       _ownerName = ownerName;
}

Let's further illustrate with the following method:

public void setOwnerName(String newOwnerName) {
       _ownerName = newOwnerName;
   }

Again, most of the documenting job can be automated and the IDE will write the following skeleton:

/**
 * @pre newOwnerName!=null use {@link Car#NULL_OWNER} for
 *                    creating a car without an owner
 * @param newOwnerName the name of the car owner
 * @post true the name of the car owner is set
 *       to {var newOwnerName}
 */
public void setOwnerName(String newOwnerName) {
       _ownerName = newOwnerName;
}

The real useful feature kicks in when one is using the Car class as shown here:

/** Gives examples of uses for the Car class
 * @author Charles-Philip Bentley
 */
public class ExampleCar {
   public static void main(String[] args) {
      Car car = new Car("Bob");
      String name = null;
      car.setOwnerName(name);
   }
}

This code snippet above compiles normally without errors. It also runs without any exception being thrown. Indeed, that's normal from the Java Language Specification (see the Resources section). However, from the designer viewpoint, the programmer is making an error; he is breaking a pre-condition by calling the setOwnerName method with a null value. It is thus desirable for the IDE to generate an error and warn the user. One could use an Exception scheme, throwing a ConditionNotMetException when pre-conditions are not respected. But that would only offer runtime error checking and still generate those custom exceptions defined by the scheme. Error reporting at compile time is much better.





Page 2 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel