Skip to content

API Design Kata

by on February 10, 2014

For our fortnightly coding dojo I recently suggested to focus on API design instead of implementation – at least for one session. The idea was that APIs live much longer than API implementations and that consequently flaws in the API design hurt much more than flaws in the actual algorithms. And because developers code much more often than they design APIs, the need for practice should be expected to be much more urgent.

The Task

Our goal was to design a generic caching API. Some use cases were given:

  • Lookup a value from the cache.
  • Compute a value that is not currently cached.
  • Let a value computation register dependencies. A dependency is a representation of a mutable entity.
  • Invalidate a dependency. All values whose computation registered that dependency must be removed from the cache.
  • Configure a maximum cache size.
  • Let one cache be responsible for fundamentally different classes of value at the same time.

The approach was to write the API, only, and to provide test cases simply to evaluate how a client would use the API. No implementation of the actual API was allowed, just implementation of callback interfaces that are normally provided by clients of the cache.

Under this assumption the tests would not run, but the test code was using the API and had to look natural and understandable. Of course, the crucial aspect was to make the API convenient for clients. API documentation snippets were written only as far as absolutely necessary.

Our Experience

We decided to work on a single laptop connected to a beamer to allow all participants to comment and implement improvements alternatingly. It turned out that it is surprisingly difficult to build an API without building the implementation. There is the temptation to let the intended internal data structure shine through in the API (“But how are dependencies stored after all?”) when the client of the API couldn’t care less.

There is also the tendency to skip the ‘test-driven’ design and write down the cache interface immediately when in fact the tests given you a good feeling which information has to be provided to the cache somehow.

It was observed that some upfront drawing would have helped a lot. It wouldn’t have to be proper UML, but an overview of the entities involved and their relationships would have given us a quicker start. Caching is more complex than the above use cases might suggest.

Java generics were a recurring topic. While we are all used to instantiating generic classes, actually defining the right type parameters for an interface is different matter.

We talked a bit about code style. The @Nonnull annotation sparked the most intense discussion.

Your Turn

If you decide to repeat the kata, also think (after the API is done) about possible performance implications of the design choices. Look for further missing features. On the other hand, look for redundant features that only make the API harder to understand.

From → Coding Dojo

  1. Did you design a real world api or just practicing.

    The idea of creating an api without implementation sounds to me a bit like waterfall,
    from my experience most problems with api´s occur during implementation or tests.

    On the other hand this might disciplinate of really seperate the api from implementation on both sites.
    For a topic like cache framework were you have quite defined functional requirments it might be doable.

    For complex requirments i would prefere the other way around, extracting the api from the implementations.

    • okummer permalink

      As with all katas, this was just practice.

      You are absolutely right about many problems becoming apparent during API implementation. You are also right that this smells a little like waterfall. I did not want to advocate designing an API and announcing it to the world without implementing it first. An API benefits a lot from having an implementation and indeed, if possible, many implementations.

      But on the other hand, APIs are waterfally and a lot. You can design and redesign and tweak an API as you like up to the point where you release it into the wild. At that point it becomes awfully hard (or impossible) to refactor the API while keeping compatibility.

      When you build an API and an implementation, it is easy to get drawn to the API that is easiest to implement. But that might not be the API that is the easiest to use. And that’s just why practicing this aspect of API design might be quite valuable.

  2. apiusabilitytesting permalink

    It seems that conducting such studies is a very important part of modern API design process, especially if the API is intended to be used by wide range of different developers. If an API isn’t possible to use, then no matter how elegant and clean the API’s internal structure.
    From my experience in conducting such studies I learned that we should consider asking developers not only to write implementation for use cases, but also to write unit tests for the implementation because sometimes it is easy to consume an API, but it is difficult to create unit tests for the code that consumes the API, so such API design probably is not good and should be fixed. Some time ago I discovered that the similar concept is called “The Golden Rule of API Design” (introduced by Michael Feathers, author of the book “Working Effectively with Legacy Code” ).

    BTW, thank you for sharing the experience.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: