We had an intense two weeks in the Hibernate Search team (well, especially Hardy) while designing the Faceting API. Hardy worked hard one the implementation (not a trivial piece of code in and of itself) but the harder part was the iterative process we did to refine the API:
- to be as user friendly as possible
- to be powerful enough
- to stay consistent with the rest of the Hibernate Search API
An important goal in Hibernate Search and other Hibernate and JBoss products is ease of use and we work hard on our APIs and configuration to make it a reality.
A good API should be:
- made for humans not machines nor klingons nor IDE wizard screens
- be usable by beginners and experts (make simple use cases easy, offer advanced features to advanced users)
- be easy to use, be easier to read
- avoid or limit the potential mistakes someone can fall in when using the API
The API should expose the natural path to use the feature and not simply expose some concepts with no real glue nor guide in between. In a way, your API tells a story, that's what makes it readable. By guiding you, the API limits the amount of errors you can possibly make.
The these goals have a price.
We often work on a first version of the API and its implementation to get the feel of it and then the refinement process happens. We look at the major use cases (simple or complex) and check how the API behaves. It's critically important to write code with the new API to see where it sucks. I can hear a few
of course but you would be surprised by how many people skip this step. Frankly I don't blame them, it's hard and long.
In the faceting API example, we looked at Amazon.com and literally reimplemented their faceting features to see:
- what was missing in the API (feature-wise)
- what steps where clumsy or too verbose when implementing the website
Based on the feedback, we refine or trash the API entirely and start again.
Another trick is to write a how-to style documentation or even better a book. A few of Hibernate Search APIs and features have been improved when I was writing Hibernate Search in Action. There were a few reasons:
- when writing examples, I've found the API or configuration too clumsy (=>fix it)
- when writing about a feature, I could not find a decent use case to illustrate it (=>trash it)
- when writing examples, I needed to write infrastructure code that should belong to the framework (=>add it)
I call this approach Book Driven Development ;) Note that (good) documentation is not a substitute for a bad API. You need both. Ideally, a user starts to use the API and go to the documentation to learn more advanced use cases.
Try and treat APIs as being forever cast in stone before you release them and use Josh Bloch's mantra,
When in doubt, leave it out.
This whole iterative process is very painful, we massively changed the faceting API three or four time. I'm sure at times, Hardy wished he hadn't volunteered to implement this feature :) Some say that a good developer does 50% impl and 50% test. I'd say a good library developer does 25% impl, 25% test and 50% API (of course to do the API you need to write tests but you get the idea).
We use peer reviewing (via GitHub's pull request mode) extensively. All the code that goes into Hibernate Search is reviewed by another member of the team. That's were the other pair of eyes catches:
- bugs or conceptual errors
- laziness (missing JavaDoc, interface vs implementation etc - the kind of minor changes you tend to leave for later)
- potential missing use cases or API improvements
These systematic peer review have really improved the quality of our software and doc. It hurts when we need to back to the drawing board but the end result is worthwhile.
Note that Hibernate Search is not the only project around taking good care of its APIs. At JBoss, there is a general trend. Just a few examples:
- Seam 3
They all have easy to write and easier to read APIs. Of course that's not limited to JBoss, many projects and specifications treat their APIs with better care these days. That comes from several factors I think:
- people get more mature on Java
- RoR's influence went by
- Java new features like generics and annotations opened up possibilities
- challengers pushed dusty Java APIs to everyone and improve
I wholeheartedly recommend Effective Java by Josh Bloch as well as his talk on how to design a good API and why it matters. By the way, I am not claiming my APIs are necessarily great but you know I try hard to. And like in snowboarding:
if you don't fall you don't make progress
I made a lot of progress :)