Four Rules for APIs

Java's Date and Calendar API is awful. Even when a quick date calculation is required, you have to stop the flow of your coding to go through the GregorianCalendar gyrations. It is impossible to simply express the intent with these defunct classes.

I've decided to use this as an learning exercise. What is it about Date and Calendar that makes it so difficult to use? What can we do to avoid these difficulties when designing our own classes? Fortunately, there is an alternative that gets it right. When comparing java.util to Joda, the problems become quite apparent.

The first problem is that the Date class has no useful methods. In order to use a Date, one must almost always put it into a GregorianCalendar. Most of us writing in Java are working on business applications, and business uses the Gregorian calendar. Different countries have different names for the days of the week and the months of the year, but we all have days, weeks, months, and years. The Date class should expose those concepts directly.

The second problem is that method calls cannot be chained. OK, I've accepted the fact that to work with a Date, I have to construct a GregorianCalendar. So I start to type something like this:

int day = new GregorianCalendar(date).get(Calendar.DAY);

But, no, GregorianCalendar has no constructor that takes a Date. I have to construct and initialize it in two separate steps. And then, to make matters worse, the method that initializes the GregorianCalendar is void. So I can't even chain this call with the get. I have to do in three lines what I would like to do in one.

The third problem is that the API provides one generic getter and setter for all fields of a Calendar. A Calendar is a collection of fields identified by constants. But I don't care how you represent a Calendar, I just want to know what day it is.
The fourth problem is that there is no distinction between a date (October 17, 2006), a time of day (10:11 pm), and a moment in time (October 17, 2006 at 10:11 pm). These different concepts need to be treated differently. When working with dates, for example, you don't apply time zones or daylight savings rules. The span between October 29 and October 30 is still 1 day, even though the span between midnight on those two days may be 25 hours (depending upon where you live).

Joda solves all of these problems. It is easy to use right where you need it without breaking stride. Do yourself a favor and start using it now, even if you are right in the middle of a project. You'll never want to be without it.

But the point of this post is not to plug Joda, but to codify four rules for creating good APIs:

  1. Put the useful methods on the most used classes. Don't force your audience to bring in objects that they don't already need.
  2. Promote method chaining. This is accomplished in two ways. First, all methods should return something, even if it is "this". And second, provide all necessary conversions. Overload constructors, or better yet have a good set of static methods (GregorianCalendar.fromDate() would have been nice).
  3. Break down the abstraction the way your audience will use it. Don't design the API based on implementation.
  4. Create a different type for each useful distinct idea, even if it appears to be a special case of another. Remember, a circle is not an ellipse, no matter what you learned in geometry.

While you are working on the API, remember the golden rule Necessary and Sufficient. Don't go crazy with the convenience methods or you will only sow confusion.

Leave a Reply

You must be logged in to post a comment.