Friday, February 8, 2008

How To Quickly Frustrate Future Developers

Simply put, if you want to frustrate your teammates, let your abstractions leak.

Have a production implementation of an interface with stubbed calls? How about a subclass that neuters parent-class functionality? If you do, you may be well on your way to setting a trap for future developers (quite possibly your future-self).

Interfaces
If you really don't need all the methods on an interface, then the interface is too big and should be broken out. Here's a contrived example. Consider what an IDaddy interface might look like:


interface IDaddy {
public void changeDiaper(Baby baby);
public void procreate(IMommy mommy);
//More methods, but significantly less than the IMommy interface.
}

This interface had better have a singleton production interface. Otherwise, other implementations of IDaddy that implement the procreate(IMommy) will have some serious 'splaining to do! (IMommy better be a singleton as well, or the IDaddy is in big trouble...).

Anyway, there are certainly uses for having someone other than Daddy change the baby diaper. Perhaps a better set of interfaces would be:

interface IBabySitter {
public void changeDiaper(Baby baby);
}

interface IDaddy extends IBabySitter {
public void procreate(IMommy mommy);
}

Now we can have several implementations that can change the baby diaper without creating family strife!

Subclasses
Just ran into this class today:

public class UnknownColumnNameException extends RuntimeException {

private static final long serialVersionUID = 1L;

String strColumnName;

public UnknownColumnNameException(String colName) {
strColumnName = colName;
}

public String toString() {
return super.toString() + " ColumnName = " + strColumnName;
}

public void printStackTrace() {
System.err.println(" ColumnName = " + strColumnName);
super.printStackTrace();
}

public String getColumnName() {
return strColumnName;
}

For those of you not completely familiar with Java's exceptions, you may not notice what is missing. In the top level processing, we have a generic, last-ditch catch of all Throwable so that we can dump log files, etc. This exception has not set any message. So, when I do an ex.getMessage() in the top-level catch, all I get is null. Thanks for nuthin'.

The user has to know about this specific exception type in order to get the useful information back out of it. Bad, Bad, Bad! If this pattern was extended, then we'd have to put a catch for each type of exception that just might happen, and pull the specialized information out of each one. Forget it!

The fix? Simply set the message in the subclass. In this case, this can be done by leaning on the superclass constructor as follows:

public class UnknownColumnNameException extends RuntimeException {
...
public UnknownColumnNameException(String colName) {
super("Could not find column with name '" + colName + "'.");
strColumnName = colName;
}


Simple fix. Great improvement in usability. Perhaps next time, I won't have to resort to the debugger to know that the input file has a problem.

What kind of abstraction leaks have you found?

No comments: