Don’t try to be too smart. Be boring, predictable and consistent.
When designing an API, it’s tempting to do a bit of extra work and surprise the developers using it. It might be returning some additional information that would require an additional call otherwise, or try to predict the intentions and handle some specific cases differently. The intentions are perfectly fine — provide a pleasant, simple interface.
The problem is that it requires making assumptions which, sometimes, are inevitably wrong. The worst case is when the API makes an assumption of what the developer expect to get back, gets it wrong, and returns something unexpected. More work with docs, more bug fixing.
Recently, I had to do some work with PHP/WordPress at my day job and encountered a couple of examples of an API doing the unexpected which give something to learn from.
The idea is simple. You pass an array, specify a number of random values to return (optionally, defaults to 1) and you get them back. Since it might return multiple values, it sounds reasonable to expect to get an array back, especially when passing the optional parameter, right?
Well, not really. It returns an integer with a key if the number of random values requested was 1. It does make sense if the method always returned one key, obviously, but that’s not the case. So the developer now has to check if the code requested a single value and handle this case separately.
Actually, this method does a bit more. When thinking about returning random things from an array, the most predictable option seems to be to return random values. However, this method does return keys to random values and not the values themselves. According to the docs, the motivation is “[t]his is done so that random keys can be picked from the array as well as random values.”. Again, all in good intentions and makes sense at first. But it would simplify things if it just returned a list of random values from the array and if you need random keys, you can pass an array that consists of all keys available.
This WordPress method updates a meta value (key-value store associated with a post), given a post id, key and new value. Sounds simple and it does what it says on the box.
The problem here comes with a return value: “Returns meta_id if the meta doesn’t exist, otherwise returns true on success and false on failure. NOTE: If the meta_value passed to this function is the same as the value that is already in the database, this function returns false.”.
So, it returns the same value in a case of 1) database error 2) update which updated nothing.
Sometimes, it's definitely useful to know if any actual updates where performed and you might want to inform the user that no values were changed. But that’s application specific and there are many application where it simply doesn’t matter and the API consumer/developer is in a good position to decide if it’s required.
What’s much more important is ability to properly handle errors. In case of a database failure, you might want to inform the user, halt the execution, log it somewhere. However, this implementation makes a straightforward check much more difficult.
How could it be solved? Simple true on success (success as in the database operation was successful) and false on error might do the job. To achieve similar functionality, you can return a number of rows updated (0 if none, instead of false) and boolean false if no rows were updated. In PHP, 0 !== false so that would solve the issues.
These two examples show how well intended extra smarts in an API call can just make it more difficult to use it. Just something to have in mind when implementing the next function that will be widely used in the wild, often in unexpected use cases.
Thanks for reading this post! If you have ideas and want to share them with me, feel free to contact me at gediminas [dot] rap [at] google’s little mail service.