‘Design by Contract’ is good, right? It’s supposed to be, but you always have to deal with that one question: what do you do when a precondition fails in production? In some systems you can throw an exception, or abort processing. But, what do you do when you’re committed? When failure is unacceptable?

There are many answers to this question, but the one that I don’t hear often enough is that you can, in many cases, design away preconditions. Here’s a simplified example. Suppose that we need to do work using a date range. We can define a DateRange class and give it a constructor which takes two dates: the starting and ending dates of the interval:

new DateRange(start, end);

That works, but it lets us fumble our arguments like this:

new DateRange(end, start);

Sure, we can have a precondition that tells us that the start must be less than or equal to the end, but it’s still a shame that our interface allows the error. Can we make a better interface? We could have a DateRange constructor that accepts a starting date and an extent in days:

new DateRange(start, 4);

That’s better, but we still have a precondition. The number of days should be positive. Is there any way around that? Well, we could create a date range at a particular date and “inflate” it afterward:

DateRange vacation = new DateRange(startingDate);

vacation.addWeek();

vacation.addDay();

No more preconditions.

Is the interface a little funky? In this case, definitely. But the point is we don’t have to take preconditions as given. They aren’t always inevitable. In many cases, we can systematically reduce them with a bit of redesign.

Are there preconditions you can remove by redesigning your interfaces? Is the interface change worth it?