Josh Bloch's Google Tech Talk video
How To Design A Good API and Why it Matters is about an hour long, and well worth your time. It's focused on OOP, but has lots of good principles that can be followed elsewhere.
In case you don't have an hour right now, here's a summary/index kind of thing that points out the bits I thought were most important.
- 6:27: Characteristics of a good API:
- Easy to learn
- Easy to use, even without documentation
- Hard to misuse
- Easy to read and maintain code that uses it
- Sufficiently powerful to satisfy requirements
- Easy to evolve
- Appropriate to audience
- 7:52: Gather requirements, but differentiate between true requirements (which should take the form of use cases) and proposed solutions.
- 10:02: Start with a short spec; one page is ideal.
- Agility trumps completeness at this point.
- Get as many spec reviews from as many audiences as possible, modify according to feedback.
- Flesh the spec out as you gain confidence.
- 15:10: Write to your API early and often
- Start writing to your API before you've implemented it, or even specified it properly.
- Continue writing to your API as you flesh it out.
- Your code will live on in examples and unit tests.
- 17:32: Write to SPI [Service Provider Interface]
- Write at least three plugins before your release.
- Application in Clojure-land: Not sure...
- 19:35: Maintain realistic expectations.
- You won't please everyone.
- Aim to displease everyone equally.
- Expect to make mistakes and evolve the API in the future.
- 22:01: API should do one thing and do it well.
- Functionality should be easy to explain.
- If it's hard to name, that's a bad sign.
- Example of bad name that I can't leave out of this summary: OMGVMCID
- 24:32: API should be as small as possible but no smaller
- "When in doubt, leave it out." You can always add stuff, but you can't ever remove anything you've included. (The speaker calls this out as his most important point.)
- 26:27: Implementation should not impact API.
- Do not over-specify. For example, nobody needs to know how your hash function works, unless the hashes are persistent.
- Don't leak implementation details such as SQL exceptions!
- 29:36: Minimize accessibility of everything.
- Don't let API callers see stuff you don't want to be public, and that includes anything you might want to change in the future.
- 30:39: Names matter: API is a little language.
- Make names self-explanatory.
- Be consistent.
- Strive for symmetry. (If you can GET a monkey-uncle, make sure you can PUT a monkey-uncle, too.)
- 32:32: Documentation matters.
- Document parameter units! ("Length of banana in centimeters")
- 35:41: Consider performance consequences of API design decisions.
- Bad decisions can limit performance -- and this is permanent.
- Do not warp your API to gain performance -- the slow thing you avoided can be fixed and get faster, but your warped API will be permanent.
- Good design usually coincides with good performance.
- 40:00: Minimize mutability
- Make everything immutable unless there's a reason to do otherwise.
- 45:31: Don't make the caller do anything your code should do.
- If there are common use cases that require stringing a bunch of your stuff together in a boilerplate way, that's a bad sign.
- 48:36: Don't violate the principle of least astonishment
- Make sure your API callers are never surprised by what the API does.
- 50:03: Report errors as soon as possible after they occur.
- 52:00: Provide programmatic access to all data that is available in string form.
- Rich Hickey makes a similar point here.
- 56:15: Use consistent parameter ordering across methods.
- Here's a bad example:
- char *strncpy (char *dst, char *src, size_t n);
- void bcopy (void *src, void *dst, size_t n);
- 57:15: Avoid long parameter lists.
- 58:21: Avoid return values that demand exceptional processing.
- Example: return an empty list instead of nil/null.