Summary

 

Motley:  Don't be anal about Application Programming Interface (API) design.

 

Maven: Good APIs are discoverable, consistent, simple, usable, hard to misuse, cohesive, lack side-effects, strongly typed, documented, has tests and samples, extensible when necessary, and are developed with anal minds.

______________________________

 

[Context: Motley has just been involved a design review for a companion team and has some concerns he is sharing with Maven]

 

Motley: I am not sure about this. I just attended a design review with Murdoch's team. The issue at hand was a new API they were designing for clients to talk to their logic layer. Their piece is in native code, which I am not that fond of, but design is design no matter what language. This is the fourth API in a row that I have been reviewing that simply extends the IOleCommandTarget interface in COM.

 

Maven: What's the issue with that API? Forgive me, I do most of my development in managed code.

 

Motley: Here is the API for IOleCommandTarget::Exec() directly from MSDN:

 

HRESULT Exec(

  const GUID *pguidCmdGroup,  // Pointer to command group

  DWORD nCmdID,               // Identifier of command to execute

  DWORD nCmdExecOpt,          // Options for executing the command

  VARIANTARG *pvaIn,          // Pointer to input arguments

  VARIANTARG *pvaOut          // Pointer to command output

);

 

You typically use this API to enable some kind of object and the container that it sits in to dispatch commands to each other. It's mostly used with toolbars and menu items.

 

Maven: Ah, yes, the old "command" API. I worked with a developer in the past who threw one of those into every API set so that he could extend it without publishing a new interface. It became a big grab bag for every little extension and got out of control real fast. At least the Exec() method above is somewhat typed - his command API took in a string that indicated what the method should do. You may as well have that one API as your object model and that's it!

 

Motley: I don't want to be anal about the design review. This one isn't so bad, but it can be overused, in my opinion. The APIs Murdoch's team are adding to the product are not meant to be used by third parties - they are internal APIs. Why rely on a command-based API set if the APIs are internal?!?

 

Maven: That's a good question. What was his answer?

 

Motley: Consistency. They already have a bunch of extensions using Exec() so they are just adding more to be consistent.

 

Maven: Sounds like some refactoring is in order for the internal APIs. Even for public APIs, unless there is some post-ship customer extensibility, I would not likely follow this model.

 

Motley: I am having a tough time convincing him that this API approach is suboptimal. I am about to give up. I hate asking this, but any advice? Should I continue to pursue this issue or concede defeat and fight another battle?

 

Maven: Well, we have talked a lot about design already, and most of those principles hold here. API design, however, is an art that has principles in itself.

 

Motley: I know of some good examples. There are many examples of good APIs inside the .NET framework. You can get by with just Intellisense for the most part when developing against many of the classes. Well, that is if you forget about ADO.NET for a little bit. I have to relearn the ADO.NET APIs and reread the documentation every time I develop something in that framework, but I digress. And don't get me started on the SharePoint APIs - "site" vs. "web" anyone?

 

Maven: You are right - .NET holds many good examples. Now based on those examples, what makes the APIs you mention "good"?

 

Motley: Let's see. Discoverability is high. I can pretty much guess the namespace, object name, and method name much of the time. Microsoft has named the APIs very intuitively so I don't need to rely on documentation other than the Intellisense comments.

 

Maven: That's a good one! APIs that are easy to find, even without docs, make development a pleasure. What else?

 

Motley: Along the same lines, APIs should be consistent with the rest of the system. I should just "know" the namespace it's in and the names should make it easy to understand the responsibility of the object or method.

 

Maven: Good stuff! Keep going.

 

Motley: Simplicity is also key. I want to avoid jumping through hoops just to use an API. Back to our design principles - coupling can get in the way of simplicity here if I have to create one object before another before I can use the API I really want. I should be able to easily explain what one API does, it should meet the needs of the audience, and there should be few parameters.

 

Maven: You can tie many of these things up into ensuring APIs have a high degree of usability. Usability does not just apply to user interfaces, but also developer APIs. To complement that, the API should be hard to misuse. Make it difficult for a developer to make a mistake. The IOleCommandTarget interface above is easy to misuse based on the generic in and out pointers. It also contains many parameters, which is contrary to your last statement. Anything else to add to designing great APIs? What else don't you like about IOleCommandTarget?

 

Motley: It should do one and only one thing (i.e. be cohesive) and have no side-effects. You could argue that the IOleCommandTarget really does only one thing - dispatch commands - but it folds up much functionality within it. I also want my interfaces to be strongly typed so that any mistakes I make are caught at compile-time vs. run-time.

 

Maven: Wow, Mot, those are some fantastic tips! Any more?

 

Motley: That about covers it for now. I guess I didn't need your advice after all. BUT, as I have come to know Mr. Always-Has-The-Last-Word Maven, I am willing to bet my paycheck that you have a few more things to add.

 

Maven: That's a bet I am NOT willing to take! You know me too well, Mot. Here are a few more. Good APIs:

  • Are documented. In the world of managed code, always supply XML comments with your APIs. As you noted earlier, Visual Studio's Intellisense parses the comments and shows them to developers while they are editing. This is a great help.
  • Has tests and samples. Why not provide your unit tests with your APIs, at least to internal teams? They provide an indication of how the API is used and what kind of boundary conditions there are. Sample code is also extremely important, both internally and externally. Most developers start with a sample and build from it. As a result, samples need to be of extremely high quality as they form the basis for much (eventual) product code.
  • Are extensible, but only if you need it. There should be a good reason for extensibility, otherwise you expand your test matrix and open yourself up to all sorts of creative development from the outside world.
  • Are developed with anal minds.  Yes, that sounds a little weird. Yes, you should be anal when you are reviewing Murdoch's APIs. Once an API is published, you must support it for many years to come. Try your best to get it right the first time. Point out every little issue in an API, no matter how small it seems. Aim for perfection. Be anal when asked to create or review an API!

 

Motley: This was actually a good discussion. I didn't really consciously realize there was that much to creating a solid API.

 

Maven: The job of a software engineer is forever complicated.

______________________________

 

Maven's Pointer:  Usability testing applies just as well to APIs as it does to user interfaces. Why not ask for developer volunteers, give them coding scenarios, and ask them to program a small solution to a problem using your new API set? Ask them to think out loud, and ensure you document their every move. It may provide some valuable information on whether your APIs are usable.

 

Maven's Resources: