API Design: The Good, Bad and the Ugly

I was doubting if I should write this post, because the topic of good API design is a very controversial topic. What is a good API is something that can be debated about.

I do however want to talk about this a bit, because recently I have gotten my Nao Robot from Aldebaran and I naturally as a Java/Scala developer wanted to try out their Java SDK.

Once I got the Nao the Java SDK was at version 2.1.2 and I was rather shocked when I saw how I had to use the SDK to control the robot. And although I am not very keen on criticising someone’s hard work, in this i can’t help but but to remark about the usability of this API.

So let’s start with a small example, for example in order to let the Robot speak in the 2.1.2 SDK I had to use the following code:

Application app = new Application(args);
Session session = new Session();
com.aldebaran.qimessaging.Object tts = session.service("ALTextToSpeech");
tts.call("say", "I am NAO and will concur the world", "English");

What is wrong?

So what is wrong about above API design, well there are some very obvious issues about this. The first one is that the API design has chosen to create a class named ‘Object’ which is incredibly unhandy as everything in Java inherits form the java.lang.Object type, so this means you automatically everywhere need to fully qualify the usage of the API classes.

One of the most frustrating parts about this API is that there is no strongly typed API. Whenever I want to do any operation on the robot, from speaking to motion I need to provide the name of the method in the Nao API as if I am doing reflection which is very cumbersome.

Nao 2.1.4

So when I started writing this article the SDK was still 2.1.2, but in the meantime whilst writing and investigating this, it seems the API has been updated and they are now providing Java proxy objects which allow easier interaction. The same snippet above now looks more clear and as following:


Application application = new Application(args, PEP_URL);
Session session = application.session();
ALTextToSpeech tts = new ALTextToSpeech(session);
tts.say("I am NAO and will concur the world");

The majority of my concerns are now addressed one would say

Complex Event Callbacks

However there is still a bit of nitpicking in the newer more streamlined API, and this is the Event driven callback based API. If you want to get any events from the Robot, like his head was touched the following code is required:


Application application = new Application(args, PEP_URL);
Session session = application.session();
ALMemory memory = new ALMemory(session);
memory.subscribeToEvent("FrontTactilTouched", new EventCallback<Float>() {
@Override
public void onEvent(Float o) throws InterruptedException, CallError {
LOG.debug("Received head touched: {}", o);
}
});

So basically nothing to special, but what gets annoying on a Robot is that you might need/want to monitor a huge amount of sensors. So you very quickly get a huge amount of anonymous inner classes which makes the code ugly and hard to build any kind of higher level logic.

The solution?

So again now we get into the debate what is a good API, well in my opinion a good API prevents me doing extra work. It provides me out of the box what I need to accomplish my end result. So in case of a Robot I expect a minimal effort needed to monitor sensor events for example.

So I don’t want to rant without providing a solution to this problem. So how did I solve this myself, well I have written in the past a small in-process Event Bus mechanism that simply can use reflection and annotations to send Events to the right listener methods. So in the end I ended using this with a small bit of extra code like that makes listening to any event a lot easier. So how does listening to a Nao Event look in such a case:

@EventSubscribe
@EventSource({"FrontTactilTouched", "MiddleTactilTouched", "RearTactilTouched"})
public void receive(TriggerEvent triggerEvent) {
    if(triggerEvent.isOn()) {
        LOG.info("Head was touched: {}", triggerEvent.getSource());
    }
}

This above code is a simple method in a class that is annotated with a an ‘EventSubscribe’ telling the Local EventBus it is interested in messages. The EventBus determines the type of message it can receive by checking the type of the first parameter using Reflection .

Next to this I introduced an annotation EventSource to indicate which sensors of the Robot to listen to. I written a simple bit of logic that uses reflection to read all annotated methods with EventSource and automatically created the Nao SDK Event callbacks for it which then get forwarded to the Event listener using the in-process EventBus.

Conclusion

So what is my point now really, although you don’t have to agree with my API design in the solution, or perhaps don’t understand exactly how it works, but there is one very important point.

This point is that the API I introduced makes it a lot simpler to listen to any sensor on the Nao Robot. I no longer have to bother wiring up with the lower level callback logic and not even need to understand it, I simply as a developer can implement the logic I wanted to run with my Robot. This is in the end my take-away with API development, build the API that allows your users to solve their core problem.

In case of a Robot the core problem you want to solve is automate sensor reading and movement control with the Robot and perhaps even higher level logic like AI, complex behaviours etc. On that level you really do not want to be bothered by the Callback based complexity.

I strive to make more abstractions for the NAO Robot, and hopefully open source them at some point. Hopefully the developers at Aldebaran take a peek at this and can use it to improve the Java SDK 🙂

 

 

Advertisements

2 thoughts on “API Design: The Good, Bad and the Ugly

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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