Ten More Good Rules for More Bad APIs

Chet Haase
Pointer IO
Published in
9 min readNov 19, 2015

--

This article is exclusive to Pointer — a reading club for developers.

Signup at Pointer.io for our weekly newsletter.

I hope you’ve had the chance to read the prequel to this sequel: Ten Good Rules for Bad APIs. If not, you might want to read it now, otherwise, the numbering scheme in this article won’t make any sense at all. Go ahead, I’ll be here when you get back.

Okay, ready?

Now that you’ve read the previous article, you should be familiar with Rule #6: Always Ship an Incomplete API. In keeping with Rule #6, I published that article before I was actually done. But that’s okay, because as any programmer knows, the typical release cycle for any product is Ship-Test-Iterate. With that critical Test phase in the middle, after we ship the product, we discover the problems we probably should have fixed the first time around, so we do more work and ship again. Then we test again and realize what we’re missing the next time around. And on it goes. There’s a reason that software version numbers have no upper bound.

In any case, after I posted the last set of rules I discovered more important API design rules that I find totally important. So here they totally are.

Rule #7: Don’t Leave Your Developers Guessing

The traditional thinking on good APIs is that methods should be documented so that developers can easily discover the important details: how to call the methods, what the return values are, what valid parameter values are, and any other salient information that they need to know.

But face it, how many developers actually take the time to read anything except the answer to the question they posted on StackOverflow? And even there, they’d rather copy and paste the solution rather than read the lengthy two-sentence explanation or the myriad of correcting follow-up comments. Developers have other, more important things to do, like getting a coffee and catching up on the latest gamer news.

As bad API developers, we need to write libraries for real developers, accepting the fact that they don’t care how much time and effort we put into the documentation. If they can’t glean the facts they need from the names of your classes, methods, and fields alone, then we have failed.

Fortunately, this is not a hard problem to solve; we simply have to be better about naming our objects appropriately and completely. There’s a reason that we use a programming language and not just zeroes and ones to write our code. Use the language, people!

Here’s an example of a nicely-documented API for a class that calculates the Fibonacci sequence to 100 digits and return it as a String:

/**
* A utility class used to calculate Fibonnaci sequences.
*/
public class FibonacciUtil {
/**
* Returns a String with the first {@code numValues} values
* in the Fibonacci sequence.
*
* numValues the number of values in the sequence. Must be
* a positive number.
* return String The Fibonacci sequence up to {@code numValues}
*/
public String getSequence(int numValues) {...}
}

And here’s what the developer sees:

public class BlahBlahBlah {
public String getBlah(int blah) {...}
}

At this point, they will, quite reasonably, go to StackOverflow and post a question with a copy of the original code+documentation and ask what it does and how to use it.

Now let’s take another run at it, this time with self-documenting class and method names:

public class UtilityClassWhichReturnsStringsContainingFibonacciSequences {
public String calculateFirstNValuesOfFibonacciSequenceWhereNMustBeAPositiveNumberAndReturnAsString(int n);
}

Note the complete lack of documentation… and the complete lack of need for it. It should be completely obvious to anyone calling this method what it’s going to do. Of course, most developers would still post a question on StackOverflow just to make sure, but this is just part of their standard workflow. At least the answers they get there will have a greater chance of being correct.

Rule #8: Developer Overview

Although Rule #7 should alleviate the need for most documentation, there may still be a desire for some broader explanation, summarizing the API or providing warnings about how not to set the hardware on fire.

Traditionally, API developers might provide this in some kind of ‘overview’ document, available on the download site and bundled with the library. But these documents go completely unread by everyone except the poor tech writer that slaved over those details. Technical documentation is like the art of the great impressionists, meticulously crafted but going unappreciated in the artists’ lifetimes, except that at least impressionism was noticed eventually.

A more realistic approach is to recognize where developers get their information and to post your API docs straight onto StackOverflow in the form of questions that you then answer. Nobody will actually search for those questions, but at least they’re there for some disgruntled answerer to link to when redundant questions are posted.

Rule #9: Self-Documenting Code

Other developers have talked about self-documenting code. Including me, when I talked about it in Rule #7 above. But it is usually discussed in a way that I find pretty tedious (with the exception of Rule #7). People talk about naming conventions that make it easier to tell what APIs do in the system. That’s fine as far as it goes (though it runs directly up against Rule #1 in the previous article, Write Similar Functionality in Multiple Ways), but, to me, misses the point entirely. If I’m going to document my code, I’m going to make sure that everyone knows why it’s there and what it does, because that’s what documentation is.

That’s why I take the revolutionary approach of letting the developer and user know exactly what’s going on with the code at all times.

I’ll give you an example of what I’m talking about. In this simple function, I issue logs to document the code flow in realtime:

public float hereIsAMethodThatDoesStuff(float a, int x) {
log("now in hereIsAMethodThatDoesStuff. This method makes some");
log("calculations and does other things that I thought would");
log("be pretty important.")
float y = x + a;
log("Just added x and a to get y");
float z = y;
log("Just set z equal to y, can't recall why this was necessary");
log("Now going to return z, which is the return value");
return z;
}

Note, here, that this is not about simply naming a method in some reasonable way, but about documenting everything that happens in the code to make it completely clear and obvious to the developer what’s happening and why (to the extent that I could figure out my own reasons when I wrote the code).

Of course, this technique only serves the needs of the developer if if were simply logged into some obscure output stream, which is why I’ve implemented my own custom log() function to do something far more useful. Here is an abbreviated version of that function:

public void log(String s) {
System.out.println(s);
Dialog.show(s);
}

This log() function not only prints to the standard output stream (useful to developers, but not so much to real people), but also to a modal dialog on the screen. That’s right — my code is self-documenting to the user as well as the developer, keeping everyone apprised of what’s happening at all times.

Note, also, that I incorporate this important technique so completely into my tool chest that I even self-document the log() function itself, so that the developer and user even know what’s going on in that API. Here’s the complete version of the log() function shown above:

public void log(String s) {
log("About to print stuff to standard output stream");
System.out.println(s);
log("Now showing stuff to user");
Dialog.show(s);
log("log function finished, returning");
}

You can see that even the log() function has log() calls. The only problem with this approach is that the instrumented log() function causes a stack overflow due to infinite recursion. I’m working on a fix for that before the next drop of my API. (Apologies for the developers that I broke with my last drop; I probably should have tested this before I pushed the latest version, or at least not deleted the previous version so that there was a backup plan in case of breakage. But hey, I’m all about iterating quickly, not correctly).

Rule #10: Consistency is Dull

Face it: our jobs as developers are boring. We type code into computers all day. We compile it. We run it. We debug it. We type some more. How exciting can it be?

Programmers are like authors, except without the fabulous book tours, the society parties, and the huge royalties that I’m sure they all make. But authors get to type their own words in patterns and phrases that they made up. They’re not constrained to typing in words and phrases that someone else created for them to use in some standard programming language.

So why don’t we make our libraries more fun to write? And what’s more fun than variety? (Okay, a lot of things are more fun that variety. But I don’t have a lot to work with here. We’re talking about computers and code).

I’ve heard some developers advocate for consistency and patterns that make it easier for consumers of those APIs to understand more about the overall structure and relationship of the methods and classes to each other. But given Rule #1, and the overall tedium of typing the same kind of thing over and over again, wouldn’t it be more interesting if we just made stuff up?

Imagine a world where you could use any syntax you wanted to describe your methods and fields. So instead of this:

public boolean isWorking() {...}

You could write this instead:

publicEnemy#1! maybeso...maybenot is This Thing on?{} /.../

How fun would that be for you to write and for your developers to read? Now it’s more like fiction than code, where you create your own journey and your developers have to figure out the destination, and the path, and the mode of transportation. It’s like a grand mystery, written in a foreign tongue on the banana leaves of your imagination.

Sure, your code wouldn’t compile. But you could just see this as a temporary failure of the compiler. So fix that compiler to make your code will compile. Now you’ve just added new features to the language and zest to your API. Of course, developers won’t be able to use your library without also using your enhanced compiler, but that’s just an implementation detail that they will surely put up with for the extra excitement you’ve added to their dull, tedious lives.

There they are, all ten rules. But I’d be remiss if I didn’t provide you more than what you asked for. In fact, I have just the rule for such an occasion:

Rule #11: Give Them More Than They Need

It’s an undisputed truth that humans are never satisfied and that programmers (being human-ish) are even less so. Developers find bugs for a living; this makes us uniquely qualified to find fault with absolutely everything we encounter. Your beautiful, finely-constructed APIs are just another beckoning target in the firing range of their discontent.

So why give them extra opportunity by providing them with exactly what they think they want? Why not bewilder and amaze them, and delay the inevitable complaint phase, by giving them more than they require? If nothing else, it will confuse them and keep them busy.

So don’t just provide a Utils class, but also a Utils2. And maybe a Utils4 (leaving room for some future Utils3 that might exist in a future release). And don’t just write the methods that do the calculations they want, but also provide more functions that do calculations they haven’t thought of and don’t yet know how to use. Sure, these things aren’t driven by particular use cases and are probably hard to test and validate. But that’s what bug databases and future versions are for.

That’s why this is the eleventh rule out of ten — it’s more than you needed, but exactly as much as I felt like providing.

--

--

Chet Haase
Pointer IO

Past: Android development Present: Student, comedy writer Future: ???