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:
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: