My first job at Microsoft was providing developer support for the early Windows SDKs. To do my job well, I spent hours studying the Windows SDK documentation, the Windows source code, and writing sample applications. I then spent hours poring over customers’ (such as Lotus, WordPerfect, and Computer Associates) code helping them figure out what was not working.
This gave me a deep appreciation for API design early in my career. I saw clear examples of elegant APIs as well as horrific monstrosities. I once created a sample for selecting a font in GDI that I called “ReallyCreateFont” because both of the built-in Windows APIs (
CreateFontEx()) were basically broken.
CreateFont case taught me first hand the pain resulting from exposing an API publicly, having customers use it in ways not expected, and then having to do unnatural acts to avoid breaking backwards compatibility.
I was supporting WordPerfect’s development of WordPerfect for Windows. This was sometime in early 1991 if I remember correctly. I had the WordPerfect engineer on the phone. He had given me access to the WordPerfect source code, but I couldn’t give him access to the Windows code. So we were each stepping through WordPerfect in the debugger, him in Utah and me in Bellevue. I could see what his code was doing and what Windows was doing, but he could only see disassembly for Windows.
The problem he was seeing had to do with font rendering. In the debugger we stepped into
CreateFontEx(), which calls into
CreateFont(), which calls into some internal GDI function, which calls into the device driver’s
Escape() function (I can’t believe I actually remember all this crap like it was yesterday). Somewhere in this call stack I came across a block of code in Windows with comments that read something like
// This is a hack to deal with Adobe’s Type Manager. // ATM *injects code* into GDI replacing our code with their own. // In order to retain backwards compatability we detect // ATM’s attempt to do this, let it do it, and then trick it // into thinking it actually hacked us this way.
I am not making this up (although that comment is paraphrased from my memory).
It turns out that the way WordPerfect was using
CreateFontEx() was reasonable, but pushing the envelope of what anyone had done before, effectively exposing a bug caused not by the original API design or implementation, but something the API provider had to do to ensure app compatibility because of something another 3rd party had done!
Holy-shit! Let me get this straight:
- A 3rd party app (Adobe Type Manager) used
CreateFontEx()in a way the API designer failed to anticipate.
- The API designer needed to retain backwards compatibility so it had to resort to putting 3rd party app specific code in the API implementation.
- Another 3rd party comes along and the complexity of the ‘fix’ caused another bug to surface.
This is a pretty extreme example, given that what Adobe had done in injecting code into Windows was pretty over the top. But I think it really helps reinforce several principles I have on API design:
- Principle 1: All successful APIs will be abused in ways you cannot anticipate.
- Principle 2: You will support a successful API forever.
The only way to ensure an API does not get abused is to ensure it is not successful. But if it is successful you will have to support it forever.
Of course if you don’t really want your API to be successful then you can ignore these principles.
My only gripe is that he does not put enough emphasis on the point he makes in bullet #3 on slide 2:
- Public APIs are forever - one chance to get it right
I believe early stage ventures should avoid creating APIs at all (unless they are purely a dev tool or framework). They certainly should not try to “be a platform”. You can read my deep and insightful (ha!) thoughts on this here:
But if you are going to ignore my advice and start exposing APIs, take this to heart:
You will do them wrong. Callers will use them in ways you don’t expect. And you will waste huge amounts of energy supporting them in the future.
When exposing APIs be absolutely certain the value you get from doing so is worth it. If you do design APIs, Joshua’s guidelines are good.
Update 4/19/12 - I added "unless they are purely a dev tool or framework" above.