Monday, November 17, 2008

Hard Contracts vs Soft Contracts

So I've been thinking about different kinds of contracts your software can have, hard contracts and soft contracts. If I look at the javadoc for List, it tells me what's expected of me if I implement a List.

add(int index, Object element)
          Inserts the specified element at the specified position in this list (optional operation).
Great, I implement a List, BsList - and pass it off to you. Technically I did everything Java cared about, there's no compile errors, I implement List and provided all the proper methods. But there's nothing that verifies if I followed the intent of the List interface. The only thing you could do if you wanted to know if I did a good job would be write some unit tests. This is a soft contract. I implemented some interface and you assumed because I did that, my code follows the expected behavior of List.

Now imagine another world. Where Sun not only released the List interface with some Javadoc, but also provided developers with a set of tests. How much more confident would you be in BsList if you could run a Sun approved unit test suite?

Most interfaces talk not only about a syntactic contract (you implemented the interface), but have an expectation about how the implementation should behave. The problem is, that's only captured in javadoc. I think interfaces need harder contracts bundled with them, they need unit tests. And seriously, you can't tell me you wouldn't love implementing an interface that had a set of tests with it. The List interface is big, 23 methods, how do you know you got it right? And why should those tests ever be coded up more than once?

Who knows, maybe it would be a bad idea for Sun to do something like that, but I know I'll be providing unit tests with my interfaces.

Thursday, November 13, 2008

Testing Interface Implementations

I've been working on some library code recently, and working on a few implementations of an interface. I wrote and tested my first implementation, then started on the second one. I didn't think about it in advance but of course about 90% of the tests needed to be the same. I realized I needed to verify that every implementation adhered to the API spec I laid out.

I ended up moving all the shared "API" tests into an abstract base class, with one abstract method, create(). So far so good, it feels a little weird to have an abstract class doing testing, but it's also kind of cool. Instead of having Javadoc describing your API there is a clean set of tests that you can look at. Also if you want to implement the interface, now not only do you have access to the minimum set of behavioral requirements but, it's also easy to run the tests against your implementation.

I wish every API I had to implement had a hard contract of tests that I had to pass, that would make life so much easier.

Javadoc = soft contract
Tests = hard contract

Web Statistics