Archive for March, 2008

Depending on abstractions: a bad idea?

Tuesday, March 4th, 2008

I have seen my share of code where everything you are dealing with is an interface. And I have seen my share of bugs in this kind of code. While it is proven practice to depend on abstraction, this is also a source of many common mistakes.

nota bene: examples use the Java syntax, but as far as I know, the issue is the same in C#, C++… (name your mainstream language)

The culprit

Consider the following interface declaration:

	public interface Executable {

		public void init(Map config);

		public String execute();

	}

Quite easy to understand, right? Any class implementing this interface can accept initialisation parameters with the init(Map) method and will be executed with the execute() method.

Wrong! This interface doesn’t tell you anything. Essentially, it would mean exactly the same if it was written as such:

	public interface XYZ {

		public void bbb(Map x);

		public String aaaa();

	}

The problem with abstractions

The contract is fuzzy

The interfaces’ contract is really loose:

  • parameters are unspecified: nothing prepevents the user to pass null or strange values to methods; in our example, what is the type of objects in our Map parameter (it can help if we are using Java5+ - e.g. Map - but it would not be a panacea)?
  • return is unspecified: should we expect nulls? is there a domain for the values (X, Y or Z)?
  • call order is unspecified: when you are implementing the interface, what guarantees you that init() will be called before aaaa()?

You can’t test an abstraction

I hate to state the bloody obvious, but, unless you provide an implementation (be it a mock one), the best you can test with an interface is its existence in the system!

Your IDE can’t help you

When following code in your IDE, each time you encounter an interface, you have to guess what is the most likely implementation to be provided at that moment.If anything, you could still run your application in debug mode to find out, but you might not have that luxury… I know that feeling! :)

Dealing with it

The issue is very clear with interfaces, but it is exactly the same with abstract or overridden classes!

Of course, I wouldn’t give away the abstraction capabilities of an OO language just because that language has a poor contract management.

The only way of dealing with it for the moment is to make your code depending on interfaces completely foolproof: expect exceptions to be thrown, expect parameters not to accept nulls, expect return values to be null or completely out of your domain… and try to mitigate the risk that the method execution order might not be respected (when you are implementing an interface).

The way forward would be to implement a contract language for interfaces (OCL anyone?)… as a matter of fact I kind of see a way of doing it in Java. I need to put more thought into it though, any suggestion welcome!

Sphere: Related Content