Pre-conditions and post-conditions

Going back to the tax calculation example, we need to reflect on pre-conditions that the method needs to function properly, as well as its post-conditions: what the method guarantees as outcomes. We already mentioned a pre-condition: the method does not accept negative numbers. A possible post-condition of this method is that it also does not return negative numbers.

Once the method’s pre- and post-conditions are established, it is time to add them to the source code. Doing so can be as simple as an if instruction, as shown in the following listing.

Listing 4.1 TaxCalculator with pre- and post-conditions

public class TaxCalculator {
  public double calculateTax(double value) {
 
    if(value < 0) {                                            ❶
      throw new RuntimeException("Value cannot be negative.");
    }
 
    double taxValue = 0;
 
    // some complex business rule here...
    // final value goes to 'taxValue'
 
    if(taxValue < 0) {                                         ❷
      throw new RuntimeException("Calculated tax value
      ➥ cannot be negative.");
    }
 
    return taxValue;
  }
}

❶ The pre-condition: a simple if ensuring that no invalid values pass

❷ The post-condition is also implemented as a simple if. If something goes wrong, we throw an exception, alerting the consumer that the post-condition does not hold.

NOTE You may be wondering what value, the input parameter of the calculateTax method, represents. Also, how is the tax rate set? In real life, the requirements and implementation of a tax calculator would be much more complex—this simple code lets you focus on the technique. Bear with me!

Note that the pre- and post-conditions ensure different things. Pre-conditions (in this case, a single pre-condition) ensure that the input values received by a method adhere to what it requires. Post-conditions ensure that the method returns what it promises to other methods.

You may be wondering, “How can I have a value that breaks the post-condition if I am coding the implementation of this method?” In this example, you hope that your implementation will never return a negative number. But in very complex implementations, a bug may slip in! If bugs did not exist, there would be no reason. The post-condition check ensures that if there is a bug in the implementation, the method will throw an exception instead of returning an invalid value. An exception will make your program halt—and halting is often much better than continuing with an incorrect value.

Making your pre- and post-conditions clear in the documentation is also fundamental and very much recommended. Let’s do that in the next listing.

Listing 4.2 Javadoc of the calculateTax method describing its contract

/**
 * Calculates the tax according to (some
 * explanation here...)
 *
 * @param value the base value for tax calculation. Value has
 *              to be a positive number.
 * @return the calculated tax. The tax is always a positive number.
 */
public double calculateTax(double value) { ... }

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *