Writing a decent API
Posted in Adobe Flash, Problems & Solutions on June 8th, 2010 by Øyvind – 1 CommentOver the last 6 months I’ve had to employ many Flash libraries that I have not worked with before. What strikes me is how poorly documented they are and how badly written some of them are. I won’t mention names, but I suspect some of you have an idea of where to find code like this. In order to make the world a better place — as always — here are two reminders that would help.
Use coding standards and best practices
Proper method names, argument names, argument types and return values are crucial to the mere mortals trying to use your API. Keep an eye on your naming schemes! Use the common denominator of data types when you can and create specialized value objects when necessary. This method signature might make perfect sense to you at a time of writing:
1 | getCoords( arg1:*, arg2:*, ar3:*):Object |
…but please clean that up when you release it to the general public! Answer me this: What kind of coordinates are we requesting? What kind of input is expected and what are their types? And what the hell does that generic return type contain exactly?? Might I suggest something like:
1 | getCityCoordinates( region:String, country:String, city:String):Coordinates |
You might think this kind of thing is trivial and basic. And it is, hence my bafflement when I read stuff like the first example in library released as the official API for one of the more common social media RIAs. You couldn’t imagine how many APIs out there break away from such common sense.
Clean up after yourself!
There are libraries out there without a single line terminated by a semi colon. As we know, the semis are optional, but they can cause the dreaded “internal build error/classes may not be nested” situation in Eclipse-based IDEs which usually eats up at least half a day of valuable time. I’ve had it happen to me, and needless to say I don’t consider semi colons to be optional. I use FDT to write my code and I have it set up to present me with an error whenever it comes across an unterminated line.
Other known culprits of internal build error are empty constructs like if-, for-, while and switch statements in addition to empty classes and interfaces. If there are incomplete sections in the API, pull them out and make sure the rest of the code doesn’t reference them.
Write proper ASDocs
How many libraries out there merely repeat the method signatures in the ASDocs? Then what’s the point? Most sane people use advances IDEs that will present ASDocs even inline with the code hinting, so make the most of it when the function and argument names cannot convey the full purpose of a property, event or method. To demonstrate, I will give an example from the ASDocs of my own logger utility, the Olog. I will not be humble in this case, because Olog’s ASDocs are in fact immaculate.
The main logic is spread across 10 classes, but there’s only two access points to the log console; the specialized event type and the Olog class itself. The Olog class serves a single purpose: It is the interface, the Application Programming Interface. It serves as the entry and exit point and the position of all the documentation. The core of the module is not as pretty, but that’s my problem. The Olog class consists of well named functions and getters and setters, all with comprehensive and highly cohesive ASDocs. In a sense you could say that this class’ primary purpose is to act as the black surface coating in the black box principle; it’s there to stop the reader from digging deeper, or should I say to make it totally unnecessary to dig deeper. Most of the methods have a single line in them, a call to another core method. This allows this class to focus on the task of providing decent documentation. The ASDocs are generated from this file.
This is a method from within the core of Olog:
1 2 3 4 5 6 7 | internal static function newTimeMarker(name:String = null, origin:Object = null):int { var n:String = (name) ? name : "Operation"; var o:String = Otils.parseOrigin( origin ); var t:int = getTimer( ); return _runTimeMarkers.push( [n, t, o] ) - 1; } |
But from the outside of the box it appears like this:
1 2 3 4 5 6 7 8 9 10 11 | /** * Creates a timing marker that you can later complete by calling completeTimeMarker() to * output the time in between. * @param name String reference to use when the marker completes an results are displayed. * @return An integer ID to use as argument when calling completeTimeMarker(). * @see completeTimeMarker() */ public static function newTimeMarker(name:String = null, origin:Object = null):int { return Ocore.newTimeMarker( name , origin ); } |
Thats a ratio of 5:2 of respectively documentation and actual code! By using the Olog class as a dedicated API layer, I’m able to use that class as both a source of proper ASDocs and a structural reference for myself.
Now, pretty please…?

