Showing posts with label DbC. Show all posts
Showing posts with label DbC. Show all posts

Sunday, January 22, 2012

Writing good static argument validation methods

Before we get into the NullObjectProxy class there is one more prerequisite to get out of the way.
How many times did you have to write the following kind of code:
// Example (1)
if (parameter > limit)
    {
    throw new IllegalArgumentException (
            "'parameter' is too large: " + parameter + " > " + limit);
    }
I decided that I had enough of this and that I wanted to be able to write something like:
// Example (2)
validate (parameter > limit, "'parameter' is too large: " + parameter + ">" + limit);
However, a little thinking made me realize that this form is not really appropriate and would have annoying side effects. In this specific case a bunch of Strings would be allocated and concatenated each time the method is called and that is not good since it would make calling the method very different from the initial code. I did a little more thinking and I came up with:
// Example 3
validate (parameter > limit, "'parameter' is too large: &1 > &2", parameter, limit);
The implementation for this is shown below:
Here is the getFormattedMessage(..) method:
Now with this version what you have on each call is that a few arguments are pushed on the stack. You still have annoying side effects though. You still get an Object[] allocated and filled on each call. Also, if you have primitive arguments you get autoboxing of those into primitive wrapper classes (Integer, FLoat, ...). Of course you can further optimize this by having different versions of the method with different primitive arguments. Fortunately it is easy to define such methods for the most common cases. Here is an example with two int arguments:
public static final void validate (boolean condition, String formatString, 
              int firstValue, int secondValue)
Those methods are defined in a static utility class called Verification and this class contains one and two arguments versions for all primitive number types. Now, the validationFailure(String, Object ...) is called only if the condition fails and so objects are allocated only on failures. We at last have something close enough to the original construct that we can use on a routine basis.
I was so pleased with this that I added a validateNotNull(boolean, String, Object ...) method:
// Example (4a)
public static <T> T validateNotNull (T value, String formatString, Object ... arguments)
This is a generic method that will handle any type of reference and return the correct type (no cast needed). I also have a short form for this:
// Example (4b)
public static <T> T validateNotNull (T value, String parameterName)
This short form will print a predefined message:
parameterName should not be null
You can use those methods like this (short form):
// Example (5)
SomeType localVariable = validateNotNull (parameterOfSomeType, "parameterOfSomeType");
The verification class also contains a number of expect(boolean, String), expect(boolean, String, Object ...) and expectNotNull(Object, String) methods. Those are used to test other conditions that would normally throw IllegalStateExceptions.
Ok, now your thinking "that's a lot of trouble for an assert mechanism". The reason I don't use the Java assert mechanism for this is that:
1) I don't want it to be possible to disable those verifications and I want them enabled by default.
2) My Verification class methods have a very usefull trace mechanism build-in. When activated this trace will always get printed even if exceptions are thrown away or lost (handled improperly in thread, ...).
I really like those little methods and I use them a lot. They make it really easy to build meaningful error information reporting into the code.
Of course I will use them in my next blog about my new NullObjectProxy class.

Sunday, November 1, 2009

In a previous blog I mentioned using DbC as a technique on a project. I forgot to mention one important element that is very important in DbC and that's invariants. Since I did not use any fancy tools to work with DbC I had to find a way to define invariants. I choose to simply define a private method called invariants and added a call to this method in a conditional compile block at the beginning and end of every public methods. Like I said in my previous discussion this simple way of using DbC adds a bit of clutter to the code but this is a small cost to pay to get the benefit of DbC.
Invariants are assertions about a class that are always true. For a linked list for example:

first != null || size == 0

Combined with preconditions and postconditions the impact on code correctness is just amazing. Thinking about the assertions just get you there faster.
On my next project I just might use Microsoft's Contract tool. The only annoying thing is that I probably won't be able to use this with MONO.

Sunday, October 4, 2009

Design by Contract and Containers classes

I had to write a special ordered linked list class for a project at work. Since I have seen a lot of example of applications of Design by contract for this type of code I decided to give it a try. For the DbC preconditions and postconditions I did not use anything fancy I just wrote a class with static methods that all look like this:


public static void precondition (string description, bool assertion)
{
#if DEBUG
if (!assertion)
{
throw new AssertionException (
"Precondition error: " + description);
}
#endif
}



When not running in debug mode the method becomes empty and if you decide not to put them in a conditional compilation block the overhead is very small. In my case because the ordered linked list is used in a very performance critical part of the program all use of the precondition and postcondition are in a #if DEBUG/#endif block. This clutters the code but considering the gains it is not so bad. (Microsoft has something available that is somewhat cleaner but when I last checked you needed the Team Edition of VS to use it).
Anyway, I found that for something like a container DbC is really great. Along with DbC I also wrote a good suite of unit tests for my class. Turns out the DbC checks detected a few errors in my code that would have gone undetected with my initial batch of tests. The DbC failure gave me a really good hint about the kind of tests I had to add so in the end with the DbC checks and the updated test suite I was really confident about my new class (I eventually got 80% coverage in my test and I plan to write the one or two missing tests I need to get to 100%). I felt that comming up with and writing the preconditions, postconditions and invariant really helped me quickly get to fully working solution.
I will not hesitate to use this again despite the clutter for any class I feel will benefit from DbC.