How to design a good API and why it matters

October 26, 2006

...

The most useful talk I have been to thus far at OOPSLA, was Joshua Bloch’s talk about designing APIs. I believe that many of the examples of do’s and don’ts that he went through is a gold mine for most programmers, whether or not they will ever create a public API. APIs are basically interfaces, and good interfaces are key to having a good modularity in the code.
The points he made include:

  • When in doubt, leave it out. If you are in doubt whether a feature should be included in the API, leave it out. It’s better to add it later if you need it, rather than having functionality that you would like to remove, but cannot because others have started using it.
  • Boilerplate code. A clean API will not force you to create a lot of boilerplate code. My interpretation of this, is that you should avoid inappropriate intimacy between your code and the client code.
  • Don’t violate the principle of least astonishment. Your functionality, behaviour and conventions should always be the ones that astonishes your users least.
  • Fail fast. Report errors to the programmer as soon as possible
  • Avoid fragile base class problem. If you allow users to extend your classes, document well how your methods are related. If extending the classes in the API is not something that you don’t want the users to do, make the classes final.
  • Overload with care
  • Do not use floating point to represent monetary values. The thing here, is that you will often not get the values and behaviour you expect.
  • Never use strings if a better option exists.
  • Use builder pattern to reduce number of method arguments. A method should have three or less arguments. A higher number makes you forget what they are. Create a builder to gather the arguments into a holder class and pass that to the method.
  • Return empty objects instead of null. For instance, take a method that returns a set of objects. If a method is unable to do this, return an empty set object instead of a null pointer. This way, you avoid having your caller always have to check for null before using the return value.
  • Don’t use exceptions for flow control. This is a personal “favorite” of mine. I have seen this on several occasions, and it upsets me every time.
  • Only use checked exceptions if there are any way to recover. If the system cannot recover from the error, there is no point spending time to try to catch the exception in your code. It just clutters your code.

Profile picture

Written by Vidar Kongsli who is a software professional living in Oslo, Norway. Works as a consultant, system architect and developer at Bredvid. You should follow him on Twitter