Friday, July 31, 2009

Boiler Plate Kills (Good design)

There have been a number of blogs and and even a report or two about the cost of boiler plate code.

I concur... but not because of the easily refuted claim that it takes time to write all this extra code. That is a poor reason offset by the power of any modern IDE. Rather the problem is that the resulting software suffers from poor design caused by the avoiding boiler plate.

Now one might ask, why are people avoiding boiler plate if the IDE writes it all for you. The problem is not one of time, rather it is an issue of psychological weight: 25 lines "feels heavier" than 3 lines of "clever" code. This happens to all developers but especially the more junior programmers.

Here are a few common examples where this happens in Java:

Example 1:
I am writing a method that needs to return a string, integer and a boolean.

The correct way to do this is the make an object for the return value. And often this will be done. However, I have seen some creative solutions like returning Object[] and treating it like a tuple. Or creating a Tuple implementations that is used in many situations (guilty). Tuples are not bad but they do not offer contextual information so full objects should be preferred over Tuples in most cases, especially API.

In a language like Scala creating a simple class for this purpose is as light as a single line. In Java you have to specify all the fields the constructor and most likely getters and/or setters resulting in around 12 lines without getters and setters and around 60 lines with getters/setters and equals/hashcode. The psychological weight of 60 lines must not be discounted. Even then the work required to do that with Eclipse is nearly half-again that with a normal text-editor and Scala.

Example 2:
You want to transform a Sequence like list or array.

This is a really painful scenario using the standard java.util collections because unlike the Google collections library the collections do not have methods for passing in functions to perform the transformation/calculation. But even with Google collections the amount of code required will often cause a developer to attempt a "clever" (read "bad") solution to the problem.

Example 3:
You have a custom data structure and want to create multiple strategies for performing calculations based on the data structure.

As we all know the right thing to do is to create an interface and the various implementations for each calculation. Unfortunately I have observed several cases where developers have actually avoided creating the interface and implementations and instead directly accessed the getters and setters to traverse the data structure and perform the calculation.

The main point here is that extra code creates a mental/psychological weight that developers will work very hard to avoid. It a the long-term/short-term compromise comparable to what has happened and is happening with our economy. Making a clever work around feels nice on the micro level but over time it will make the system much harder to understand and maintain. Try to go back to a call to "doSomething" that returns a Object[]. The danger of making a mistake parsing the list and the difficulty of trying to understand what it does cannot be understated.

No comments: