The main points, discussed in detail in the article but with selected quotes here, are:
- Design to evolve
The best approach is to say that once something is in the API it will stay there and it will continue to work. Tweaking the API incompatibly between revisions will result in user reactions ranging from annoyance to murderous rage. The problem is particularly severe if your API ends up being used by different modules that are part of the same application. If Module 1 uses Commons Banana 1.0 and Module 2 uses Commons Banana 2.0 then life will be a whole lot easier if 2.0 is completely compatible with 1.0. Otherwise your users risk wasting huge amounts of time tweaking classpaths in a futile endeavour to make things work. They might end up having to play mind-destroying games with class-loaders, which is a clear signal that you have failed.
- [Follow a set of] API Design goals, such as "It must be absolutely correct," "It must be easy to use," "It must be easy to learn," "It must be fast enough," and "It must be small enough," expressed in roughly the order of importance.
- Be minimalist
Because of the compatibility requirement, it's much easier to put things in than to take them out. So don't add anything to the API that you're not sure you need.
he right approach is to base the API on example code. Think of problems a user might want to solve with the API. Add just enough classes and methods to solve those problems. Code the solutions. Remove anything from the API that your examples don't need. This allows you to check that the API is useful. As a happy side-effect, it gives you some basic tests. And you can (and should) share the examples with your users.
- Interfaces are overvalued
There's a certain style of API design that's very popular in the Java world, where everything is expressed in terms of Java interfaces (as opposed to classes). Interfaces have their place, but it is basically never a good idea for an entire API to be expressed in terms of them. A type should only be an interface if you have a good reason for it to be.This is followed by a set of circumstances in which an interface is entirely justified.
- Be careful with packages
The Java language has fairly limited ways of controlling the visibility of classes and methods. In particular, if a class or method is visible outside its package, then it is visible to all code in all packages. This means that if you define your API in several packages, you have to be careful to avoid being forced to make things public just so that code in other packages in the API can access them.
The simplest solution to avoid this is to put your whole API in one package. For an API with fewer than about 30 public classes this is usually the best approach.
- Other random tips, including some well-chosen tips from Effective Java
What do you think of Eamonn's points? What would you add to the list?