Archive for September 15th, 2005

Re: The Black Art of Good Design

The latest BileBlog from Hani strangely resonated with me today:

So what’s the acid test for a good design? I have no idea. The closest I could come up with is A good design allows your code to do things you never expected it to have to do. It’s not about ‘oh I’ll add an interface here so I can plop in different implementations’ when there’s no sane reason you’d ever need more than one implementation, for example. […] For example, there are interfaces for simple objects that have both getters and setters specified, which makes creating a read-only implementation pretty unpleasant. I’d also argue that putting getter+setter style methods in an interface is an implementation leak anyway, mind you.

I just started working on a new project and the colleague I’m working with on it insists on putting interfaces on everything, even on beans which are mostly just containers for properties. And of course, getters and setters are specified in the interface.

I think getters and setters are indeed evil, but they are a necessary evil when your objects are used as containers for data to be shipped back and forth between a GUI and a database. They do not certainly belong to the interface, though.

I’d also argue that specifying an interface for these kind of (pseudo) objects is way overkill. The problem is he is also heavily into TDD, which I heartily applaud, but somehow thinks it’s necessary to test everything via mock objects, which requires having interfaces.

This goes to the point of mocking an OrderItem implementation to test that Order.getTotalAmount will call OrderItem.getQuantity and OrderItem.getPrice once for each OrderItem, which I find a bit too extreme.

Personally, I find this type of test to be:

  • Overspecified, as it does not just test that the correct amount is computed, but also that it is done following a specific algorithm.
  • Brittle, as the algorithm might change and we couldn’t care less as long as the correct result is computed, but we would be forced to rewrite the test.
  • An abuse of mock objects, which IMHO should be used to avoid dependencies on concrete implementations of external APIs. The same test, assuming it made sense, could be implemented in the traditional way without mock objects.
  • Much less readable than a traditional test.

I’m afraid all this TDD stuff, which is certainly valuable if done sensibly, is becoming to be abused as a means for avoiding to have to think about a proper design beforehand, as Hani hints to in hist post.

On the other hand, I will readily admit of being way too lazy in writing proper test cases, so I’ll concede the benefit of doubt. Maybe we can find a comfortable middle ground and I can start being more test-infected, which would be good.

What do you think?