Support Only the Minimum
2 min read

Support Only the Minimum

TL;DR: Keep your APIs as minimal as possible.

API design is hard. But this is arguably the best tip I can give. Don’t add bells and whistles, let the clients do that themselves.

This is a programming language agnostic concept, but I’ll be using Java to demonstrate my point.

In my experience, interface creation often leads to the most existential debates I have with myself.

For example:

public interface Collection<T> {
 boolean isEmpty();
 int getSize();
}

One of these methods is redundant. Is an isEmpty method really necessary here when one can write:

if (collection.getSize() == 0)

instead of:

if (collection.isEmpty())

There are two valid reasons to add keep the isEmpty method:

  1. You’re just being extra nice to your clients by helping them keep the code simple to read and write.
  2. You want to make some distinct guarantees about the semantics or complexity of each method.

I’ll just say that #1 is invalid. First, forget about making the code simple to write, it will probably be read far more often than it’s written. Second, making it simple to read without adding extra burden to those that are implementing your interface is silly. You can simply offer a static utility class that will never change:

public final class Collections {
 public static <T> boolean isEmpty(Collection<T> c) {
 return c.getSize() != 0;
 }
}

Now the code is as simple as:

if (Collections.isEmpty(collection))

#2, on the other hand, is rather valid if your interface wants to make some guarantees. For example, perhaps isEmpty() is guaranteed to be a constant operation while getSize() may not be. This is valid, but must be documented and explained to your users, potentially increasing complexity.

Such a debate raged long ago regarding the size() and empty() methods of C++’s Standard Template Library (STL). For what it’s worth, most standard containers support both.


Accessibility

Whenever you find yourself exposing a method or field that is not private (including package-private), you are essentially stating that you plan to support the functionality for the foreseeable future. That will only make refactoring harder, leaving you with a clunky API.

When you work on versioned software that is statically shipped to your clients (e.g., an SDK of some form) you learn some very hard lessons very quickly. Every single change to a public API that you make is a burden to your clients to upgrading.

If you ever find yourself in an existential debate where you are attempting to predict the future on how a client will use a particular API, step back and ask yourself if it’s really necessary. Do not simply implement what you think they might need. Only add what you know they will need.

Deprecating or obsoleting functionality is at least an order of magnitude harder than creating it in the first place when you know it’s needed. Especially when you cannot be certain how your clients are using the code.

Enjoying these posts? Subscribe for more