Design by Contract: Part Two

WRITTEN BY Dave Nicolette

Welcome back for another dose of Design by Contract. This is part 2 of a three-part series on the subject. Part 1 is here.

In this instalment, I share my experiences in searching for simple and usable DbC libraries for several mainstream programming languages:

  • Java
  • .NET languages
  • Ruby
  • JavaScript
  • Python
  • Golang

Java: Cofoja

There have been a number of attempts to implement DbC for Java over the years. The most successful one was cofoja. The clever name stands for “contracts for Java.”

Cofoja uses Java annotations to implement the three key concepts of DbC:

  • @Requires for method preconditions
  • @Ensures for method postconditions
  • @Invariant for class and interface invariants

Apparently cofoja began as an intern’s project at Google around 2011, was formally adopted by Google and released to Open Source in 2013, generated a lot of enthusiasm until sometime in 2015, and has since languished.

There is a development team behind cofoja, but they don’t appear to be particularly interested in supporting it. The current version is incompatible with one of its own transitive dependencies (a utility class somewhere in the com.sun.xxx pile), and it doesn’t play nicely with mainstream Java IDEs or build tools.

I had quite a lot of trouble getting cofoja to do anything at all, and never was able to make it react to an invariant under any circumstances. It is easier to implement simple preconditions and postconditions by hand than it is to try and live with this tool.

I spent several hours fighting with this tool so that you won’t have to. You can thank me later. Pizza, beer, and ice cream make for excellent “thank you” gifts. In return I can share the gory details.

An unrelated bug in IntelliJ IDEA that causes the IDE to “forget” annotation processor profiles made the exercise all the more frustrating. <sarcasm>The fact this bug has been open since March of 2017 underscores the relative level of importance DbC enjoys in the industry.</sarcasm>

Apart from the practical challenges in using a tool that appears to be fading away, the design of cofoja seems to be based on the assumption that DbC is a testing technique. It requires Java code to be compiled with debug options turned on, the use of a Java Agent to process the annotations, and special classpath settings that build tools and IDEs don’t pick up automatically. It is extremely finicky, poorly documented, and not supported at a level that makes it usable in a real world environment.

…and this is the best DbC library I could find for Java. ‘Nuff said.

Java: Annotated-Contracts

Sebastian Hoss has created an annotation-based library for Java that supports a subset of DbC, namely preconditions and postconditions. Invariants are not supported. Contracts can only be specified on methods, but that is often all we need. Another compelling point is that this project does not appear to make the assumption DbC is strictly for “testing.”

Immediately after struggling with cofoja, I was intrigued to read that annotated-contracts “allows easy usage of contracts without any need for extra JVM parameters, JVM agents, special classloaders or compilers.” The project has existed for three years and has had well over 400 commits. However, there is only one contributor. Even so, the source code looks clean and it sounded like it was worth a try.

Based on an example from the Github project README, I added a @Contract annotation to the constructor of my Dictionary class:

package com.neopragma.dbcdictionary;

import com.github.sebhoss.contract.annotation.Clause;
import com.github.sebhoss.contract.annotation.Contract;

public class DbcDictionary {
    private int capacity;
    private int count = 0;

    @Contract(preconditions = {
            @Clause(value = "capacity >= 0",
                    message = "Capacity must be positive",
                    exception = IllegalStateException.class)
    })
    public DbcDictionary(int capacity) {
        this.capacity = capacity;
    }
    public int capacity() {
        return capacity;
    }
    public int count() {
        return count;
    }
}	

It received the error, '@Contract' is not applicable to constructor. According to the README, contracts can only be specified on methods. I did read that. I did not forget it. The thing is, constructors are methods. Thus, the documentation is misleading. A straightforward reading of the statement means that the annotations can’t be used on class and interface declarations; but that is not what the author meant to say.

Not wishing to give up on this project too early, I factored the initialization logic out of the constructor and into a private method, initialize(). The compiler was happy with the @Contract annotation on the private method instead of the constructor. You may or may not be willing to munge your design to work around this issue, but in case you are willing, here’s what happened.

Munged class:

package com.neopragma.dbcdictionary;

import com.github.sebhoss.contract.annotation.Clause;
import com.github.sebhoss.contract.annotation.Contract;

public class DbcDictionary2 {
    private int capacity;
    private int count = 0;

    public DbcDictionary2(int capacity) {
        initialize(capacity);
    }
    public int capacity() {
        return capacity;
    }
    public int count() {
        return count;
    }

    @Contract(preconditions = {
            @Clause(value = "capacity >= 0",
                    message = "Capacity must be positive",
                    exception = IllegalStateException.class)
    })
    private void initialize(int capacity) {
        this.capacity = capacity;
    }
}	

And the example:

    @Test
    public void dictionary_rejects_negative_capacity() {
        Executable invalidCapacity = () ->
            new DbcDictionary2(-1);
        assertThrows(IllegalStateException.class,
                invalidCapacity,
                "Capacity must be positive");
    }	

Unfortunately, the code runs the same with or without the @Contract assertion in place:

org.opentest4j.AssertionFailedError: Capacity must be positive ==> 
    Expected java.lang.IllegalStateException to be thrown, but nothing was thrown.

There are quite a few other DbC implementations for Java, but they are either incomplete, unreliable, or unsupported. Unfortunately, there appear to be no viable DbC libraries for Java at this time; just a few dead or dying projects and some non-starters. A shame.

.NET Languages

The Microsoft .NET framework supported DbC directly as the System.Diagnostics.Contracts namespace until .NET 4.0, when the company open sourced the contracts library and published it on Github. It still works with .NET languages, but you have to install it explicitly and there’s no built-in sugar for it in VisualStudio.

CodeContracts uses a combination of attributes and plain old method calls that use familiar DbC terminology — requires, ensures, and invariant in intuitive ways.

Due to assorted incompatibilities between the DotNet.Contracts package, CCRewrite, .NET Core framework versions, and compiler versions, and contradictory advice regarding the use of #define CONTRACTS_FULL, I was unable to get much of anything to work for C# using this package after several hours of searching and experimenting. Microsoft documentation is cryptic and incomplete, generally offering vague hints about configuration settings without giving enough context for the reader to guess where those settings are supposed to be specified.

At long last I was able to get Contract.Requires to throw a Precondition failed error, but this was accompanied by a mass of error message text pertaining to some sort of unexplained version incompatibility between CCRewrite and all the framework versions defined in the project file. I never got invariants to have any effect at all. This code honored preconditions (Contract.Requires) but noisily, and doesn’t react at all to ContractInvariantMethod.

This package seems to be based on an assumption that DbC is for development and testing, and won’t be included in builds targeted for production environments. Even if it worked as advertised and enjoyed strong support, this might be enough to disqualify it.

Some comments on user forums stated that the APIs were published and the compiler silently succeeded when calls were included in the code, but there was no functionality behind the APIs. Developers were using the package and expecting it to do something, but it was an empty promise.

Like Java’s cofoja, CodeContracts appears to be languishing. Both those packages may have been released to Open Source as a way for the owning companies to wash their hands of them.

Unfortunately, there appear to be no viable DbC libraries for .NET at this time.

Ruby

By this point in my investigation I was ready for some good news. As it often does, Ruby provided it. (Yes, I’m a fan.)

Rubygems.org hosts quite a few gems that seem to be related to DbC. Aditya Bhargava’s contracts gem has had over 1.5 million downloads, including almost 250,000 downloads of the latest version. As of this writing, Github shows 475 commits with the most recent on November 30, 2017.

It has had a steady stream of reported issues and a steady pace of getting them fixed and closed; a good indication that people are paying attention to it. It has 35 contributors. Looking through the source code, I found a comprehensive suite of rspec specs comprising meaningful examples, and both the specs and the production code are clean.

It looks as if this project might be actively supported and widely used. Let’s try using it to implement the Dictionary class illustrated in the Eiffel sample code.

In the interest of space, we’ll forego showing all the fine-grained TDD steps and only show key milestones. After test-driving a constructor that instantiates a Dictionary with a specified capacity, we have the following spec…

require 'rspec'
require_relative "../app/dictionary"

describe 'Dictionary: ' do

  context 'creation: ' do

    it 'creates a dictionary instance with the specified capacity: ' do
      dict = Dictionary.new 5
      expect(dict.capacity).to eq(5)
    end

  end

end

…and production code:

class Dictionary

  attr_accessor :capacity

  def initialize capacity
    @capacity = capacity
  end

end

If we specify a foolish value for capacity, the production code doesn’t care. This spec…

    it 'rejects a capacity less than zero: ' do
      expect{ Dictionary.new -1 }.to raise_error(RuntimeError)
    end	

…results in:

expected RuntimeError but nothing was raised
./spec/dictionary_spec.rb:14:in `block (3 levels) in '
-e:1:in `load'
-e:1:in `'

2 examples, 1 failure, 1 passed	

Now let’s see if the contracts gem can help us guarantee the invariant from the Eiffel example that the capacity of the Dictionary must be a positive value. (Not sure why you would want a Dictionary with a capacity of zero, but that’s how the Eiffel example is coded, so we’ll follow along.)

We add contracts to the Gemfile…

source "https://rubygems.org"

gem "rspec"
gem "contracts"	

…and run bundle install. Now we can try defining the invariant for capacity.

Between the tutorial and the source code, I learned that an invariant guard raises InvariantError

    it 'rejects a capacity less than zero: ' do
      expect{ Dictionary.new -1 }.to raise_error(InvariantError)
    end	

…and by trial and error based on the tutorial examples I discovered the code necessary to make it work in the Dictionary class:

require 'contracts'

class Dictionary
  include Contracts::Core
  include Contracts::Invariants

  invariant(:capacity) { capacity >= 0 }

  attr_accessor :capacity

  Contract Contracts::Num => Contracts::Num
  def initialize capacity
    @capacity = capacity
  end
end	

And the happy result was:

Run options: include {:full_description=>/Dictionary:\ /}
2 examples, 0 failures, 2 passed
Finished in 0.009388 seconds
Process finished with exit code 0	

There’s a lot more to cover in this post, so let’s skip the rest of the implementation. It will consist of building up more code similar to what we’ve shown here.

The bottom line is that the contracts gem appears to work quite well. That means we have good support for DbC for Ruby applications. Ruby is very well suited to microservices development, so that’s good news.

JavaScript

JavaScript and the whole Node ecosystem is coming into its own as a major player in the software industry, so this is not a language to be ignored. Mature or widely-used DbC libraries for JavaScript have not yet emerged. One interesting project is contractual, developed by a small team of developers in York, UK, that goes by the name Codemix.

The package is still in a pre-1.0 state and has had only about 100 downloads. Even so, the group have done a very professional job of presenting and documenting the package. The project has a home page that contains very good documentation, examples, and a live demo implementation that works.

Contractual follows the DbC pattern of require (pre:), ensure (post:), and invariant (invariant:). It appears to be the best bet for DbC in JavaScript as of today.

To try it out, I set up a toy project as follows:

npm init 
npm install jasmine 
node_modules/.bin/jasmine init 
npm install contractual	

Let’s take the same approach as we did with Ruby. We’ll start by driving out a constructor that takes a capacity. Specs:

describe("Dictionary", function() {
    var Dictionary = require('../lib/Dictionary');
    var dict;

    it("creates a dictionary with the specified capacity", function () {
        dict = new Dictionary(5);
        expect(dict.getCapacity()).toEqual(5);
    });
});

Code:

function Dictionary(capacity) {
    this.capacity = capacity;
}
Dictionary.prototype.getCapacity = function() {
    return this.capacity;
};

module.exports = Dictionary;	

Result of running Jasmine:

1 spec, 0 failures
Finished in 0.006 seconds

Now let’s watch the code accept a nonsensical value for capacity.

    it("rejects a capacity less than zero", function() {
        expect(function() {
            new Dictionary(-1)
        }).toThrowError("Some error message");
    });	

As we expected, the code does not catch the error:

Started
F.

Failures:
1) Dictionary rejects a capacity less than zero
  Message:
    Expected function to throw an Error.
  Stack:
    Error: Expected function to throw an Error.
        at 
        at UserContext. (/Users/dave/Documents/Projects/dbcjavascript/spec/DictionarySpec.js:13:12)
        at 

2 specs, 1 failure
Finished in 0.01 seconds	

Now let’s introduce the contractual package and see if it helps us. Following available examples, we add code to the Dictionary class to define the invariant requiring capacity to be positive:

function Dictionary(capacity) {
  invariant:
    this.capacity >= 0, 'Capacity must be positive';
  main:
    this.capacity = capacity;
}
Dictionary.prototype.getCapacity = function() {
    return this.capacity;
};
module.exports = Dictionary;

I like the way this code looks, as it very clearly calls out the contract, and it even resembles the Eiffel code. I understand that’s only a coincidental effect of using JavaScript labels, but even so it makes the intent of the code crystal clear.

At this point, I ran the specs again to be sure the addition of the contractual code hadn’t introduced a defect. The result was the same, so I continued.

Contractual is a compiler that adds code to the JavaScript modules to support DbC at runtime. The next step is to compile the Dictionary class. I took all the defaults. The compiler placed the generated JavaScript file in directory out, which it created on the fly for me.

node_modules/.bin/contractual lib/Dictionary.js

The compiled code looked like this:

var OBLIGATIONS = require('obligations');
function Dictionary(capacity) {
    OBLIGATIONS.invariant(capacity >= 0, 'Capacity must be positive');
    var __result;
    this.capacity = capacity;
    OBLIGATIONS.invariant(this.capacity >= 0, 'Capacity must be positive');
    return __result;
}
Dictionary.prototype.getCapacity = function () {
    return this.capacity;
};
module.exports = Dictionary;	

Next, I changed the require in the DictionarySpecs.js file to point to the compiled version of Dictionary.js:

    var Dictionary = require('../out/Dictionary');

Also changed the expected error message text to match that defined in the invariant. And thus, the moment of truth arrives:

Started
..
2 specs, 0 failures
Finished in 0.01 seconds	

It appears we have a usable DbC library for JavaScript as well as one for Ruby. Good!

Python

There is a Python package called PyContracts that supports preconditions and postconditions. The project has been updated as recently as late 2017, so it appears to be active.

Beyond that, there are some old and no-longer-maintained packages, as well as general advice on how to implement something resembling preconditions and postconditions using standard Python language features like decorators and docstrings, dating back several years.

PEP 316 proposes adding DbC support to the language. The PEP has not been formally rejected, but it is in “deferred” status. It was created in 2003, so it doesn’t look as if anything is going to be done with it.

In the meantime, the limited attempts to implement DbC for Python don’t support invariants (which is the tricky part of implementing this), and it’s easy enough to write standard code that provides the same functionality as preconditions and postconditions. Many in this community seem to view DbC as a testing technique, too. Explicit support for DbC may be a dead issue for Python, and we’re left to roll our own.

Golang

Go is rapidly growing in popularity, and is a good choice for developing microservices, which have grown in importance in recent years. It seems the keepers of the language have little interest in adding DbC support directly into Go. They argue that it’s possible to use conventional language constructs like conditional statements to achieve the same goal (much as we will do shortly in Java and C#).

Landon Bouma has made a start at a contracts package for Go, but doesn’t seem to have made any commits in nearly a year. Looking at the code, the solution seems to amount to nothing more than convenience methods wrapping simple conditional logic.

Unfortunately, there appear to be no viable DbC libraries for Golang at this time.

The State of DbC

I’m struck by an odd combination of factors:

  • DbC is a simple concept that’s both useful and easy to implement (except, maybe, direct support for invariants, depending on the language)
  • There have been numerous abortive attempts to implement DbC in just about every programming language
  • There are almost no well-designed and supported DbC libraries available for just about any programming language

What are we to conclude from this? I think we can say there’s a lot of interest among software developers in DbC; hence all the attempted implementations.

But there is a common misconception that DbC has to be abstracted away from the “business logic” of the application, rather than being treated as part of the functionality of the code. This has led to needlessly-complicated implementations that are difficult to learn and problematic to use. Tools with those characteristics tend to be dropped.

In the third instalment of this series, we’ll walk through the process of test-driving an implementation of DbC in Java. Hopefully, this will demonstrate that DbC is not inherently complicated and that it’s appropriate for the contracts to be visible and obvious to anyone reading the source code, rather than being abstracted away.

leave a comment

Leave a comment

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

1 comment on “Design by Contract: Part Two”

  1. Marko Ristin

    Hi,
    You might be interested into these two libraries:
    http://github.com/Parquery/icontract dbc library for python that provides informative messages, supports inheritance of contracts. There is also a linter to verify the contract arguments statically and a sphinx extension to include them automatically in the documentation

    http;//github.com/Parquery/gocontracts — dbc tool for go. The invariants are work-in-progress.

    Reply