What is good API design?

Some say that API design is one of the hardest things in programming. A few even go as far as to say you should have at least 10 years of experience to even attempt it. While I think this process can be sped up almost an order of magnitude by good mentorship, at one time or another we’ve all suffered under the API of an inexperienced programmer. Though, this does raise the question: what exactly is it about building libraries that can take up to 10 years to learn?

I was lucky in that I got a strict API education early on. Right out of college I joined Atalasoft, a company for which the API was the product and so was under the strictest of scrutiny. My mentor was Steve Hawley, a man who has spent much of his life solving difficult problems and wrapping them up in nice little packages. Steve had little patience for babysitting as he always had a lot on his plate and so under him I was forced to learn very quickly.

His philosophy, which was never explicitly stated, I call 90-9-.9. For 90% of the users you want the problem solved out of the box with just a couple of lines of code that can be cut and pasted. Here defaults matter the most. For the next 9% you’re aiming for simple configuration; something that can be easily figured out from the documentation or resolved in just a few minutes by the support team. Then there’s the .9% who will want to bend your libraries in all kinds of twisted ways, sometimes for performance or and other times some wacky (but workable) use case you never thought of. It’s completely fine to sacrifice the experience of the .9% for the sake of everyone else, just make sure it’s possible to get what they want done and that your documentation will show them the way.

Finally, there’s the unmentioned .1% who you’ll never make happy because they’re mistaken about the capabilities of your product. Better to either ignore them, or do market research to see if they’re worth the cost of extending your library to pull them in.

A great example of this is Atalasoft’s barcode product. A lot of effort went into carefully tuning it to preprocess most scanned documents without issue. After preprocessing it will by default go whole hog and try every kind of possible barcode type that you have a license for. This is still quite fast, fast enough for anyone with a small time scanning operation. Sometimes for folks doing large scale batch scanning on expensive equipment it’s just not fast enough though, so they can configure which barcode scanners are used by changing a simple enumeration property. Once in a while they get folks doing things that are a bit more difficult, like for example maybe trying to scan a barcode wrapped around a banana. For this there are events that let you interrupt, tweak and replace whole chunks of the barcode engine. But the guy who wants to read the barcodes he hand shaved into the side of the dogs in his pet store? Sorry pal, you’re better off finding another product.

When I first saw this it seemed like bad design. The whole component is like a frickin’ monolithic program with an event based do-it-yourself plugin system! You see though, aesthetic beauty as judged by an architecture astronaut isn’t what Atalasoft is optimizing for. They’re optimizing for reduction of the customer support burden. As much as I dislike object oriented programming for writing the internals of libraries like these, I think there’s no better paradigm for exposing a single simple interface that allows for manipulation at all of these levels.

Now, for the past two years I’ve been in charge of the APIs at Bayard Rock, a completely different kind of company. We do research and development primarily for anti-money laundering. This means lots of little experiments and the occasional medium-scale project which will later be integrated into our sister company’s larger infrastructure. In the vast majority of cases Atalasoft-style monolithic black-boxing wouldn’t be helpful at all. We only have one customer and we work with them to tailor our external APIs directly to their needs.

However, code reuse at a fine grained level is much more important at Bayard Rock than it was at Atalasoft. In this context what matters most is the construction of large libraries full of many small categorized functions which we can first use to put together experiments quickly (that is, through simple composition and without comprehensive unit tests) but later still feel confident about shipping in our product. We’re optimizing for experimentation and the rapid development of components that we trust enough to ship. It should come as no surprise that here typed functional programming wins hands down.

So, what is good API design? It depends, and that’s why it’s so hard.

Enjoy this post? Continue the conversation with me on twitter.

Tags: , , , , , , , ,


  1. Nice short post! I would like to add that the overall performance of the API is affected by how you design it based on your priorities.

    There are many ways to implement a feature in an API. Some ways will make the lives of developers easier at the cost of performance. And some are the opposite.

    There’s a good balance for this but that depends on how your API will be used and what are your API’s priorities.


    • This is quite true. At Atalasoft many of the algorithms by default ran in unmanaged code and operated on the unmanaged memory the images were stored in. This allowed everything to be quite fast, while still having an easy to use API. Even better, no worries about large object heap fragmentation which can be a real pain in the butt for images.

      Even more impressive though (and a testament to Steve’s great ability as a software architect) is that the algorithm and memory model are abstract enough to provide both managed memory images and algorithms when needed for fully “safe” deployments.

  2. I love your article! I spent the last couple years doing API design for a big startup, where most of our customers were actually internal engineers. 90-9-0.9 is spot on. One of the most ignored parts of designing a good API is knowing when and where a firm “no” is appropriate, and more importantly knowing when you’re wrong about that.

    • Thanks! You know, I’m running into a lot more trouble with that these days as it’s so hard to explain the intricacies of machine learning to the decision makers. Sometimes I have to fight hard against the idea that a given algorithm is just magic powder you can sprinkle into any situation and get great results. Thankfully my boss knows his stuff and is very well respected in the company and so can back me up when needed.

  3. Nice Article. I’m writing yet another API with the “customer” being mobile phones – which puts a slightly different slant on things than other API’s I’ve written. In short, the note about defaults being important is a nice one.

    I think it’s important to make one API call capable of as many permutations that perform the same basic task as possible: This allows for less API calls, eases the learning curve, is slightly more work up front while making managing the code later straightforward, and when possible return error info that is helpful. You can make errors even more helpful to developers and speed up development time for the API consumer by returning everything they did wrong on a given call (where you can) versus returning just the first problem you encounter; just like when you compile a program you get a list of errors as long as the compiler can create for that situation.

    Sorry my sentences run long.

    Good Job!

    • I agree that some variety can be good, but it also carries with it a maintenance and testing burden. For every back end change you make, you need to ensure it’s compatible with each and every public API you’ve provided. Also, if an update requires extending the API, the larger the surface area the more expensive that update will be for the company. For this reason it’s best to strike a balance, permuting only where it will increase sales.

      On the internal API side, I think it’s best to provide composable little parts that the user can turn into any kind of API they want. This type of composition is one of the great features of functional programming.

  4. Good points, just a note; in my (very very humble) opinion, whenever designing an API, always ensure to build it so that it may be wrapped inside some “custom code” and extended; this way, if one is unhappy with the default API, (s)he may just write a wrapper and add whatever functionality; also, you forget to mention another factor which should be important when dealing with APIs… SPEED :) yes, speed sometimes makes the difference; someone may just want all the bells and whistles and don’t care about speed, someone else instead, may just want bare speed and add own functionalities if/when needed, so, another good idea may be exposing both the “bare” (and fast) API and some more “elaborated” ones, leaving to the end “user” (developer) to choose which one to use… as long as they’re interoperable (to a certain level); this alone makes quite a difference (imVVHo again).

    • There is another practical reason to ship monolithic black box APIs which I didn’t mention: Once a customer uses an API it becomes sacred. Changing a popular API pretty much guarantees an influx of support calls. This is both very expensive for the company and carries the risk of raising the ire of your customers.

      For this reason it’s always advisable to have at least one level of indirection between the API you ship and your internal representation. Of course, this isn’t really a problem for small scale internal APIs.

  5. I have been helping people to design good APIs for a while. For a discussion about the must-have for a good API, you may want to check http://www.ocoudert.com/blog/2009/10/08/api-design-101/

    • Seems like a reasonable set of suggestions for non garbage collected object oriented API design. No-GC OO isn’t the end-all be-all of programming though. It’s a big world out there and some problems are much better solved in other ways. That’s pretty much the point of this whole post: It depends.

  6. […] What is good API design? – In a similar vein, Richard Minerich discusses what makes a good API design, sharing some of the lessons he learned early on in his career about designing APIs for consumption by different types of user. […]

  7. […] What is good API design? « Inviting Epiphany – what exactly is it about building libraries that can take up to 10 years to learn? […]

Leave a comment