Site Archive (Complete)
Architecture Blog: A&D 2007: UI Principles in API Design
Architecture & Design
PATTERN LANGUAGE

Modeling, Managing, Making it Right.

by Jonathan Erickson
IF YOU BUILD IT

... Will they Come?

by Arnon Rotem-Gal-Oz
August 06, 2007

A&D 2007: UI Principles in API Design

One of the interesting presentations I attended at Dr. Dobb's Architecture & Design World was "User Interface Principles in API design" by Elliotte Rusty Harold.

Elliotte started off by mentioning that developers are people too (I guess...) and that designing an API we need to think about the people (developers) who are going to use it. I totally agree, in fact, when it comes to API design is one place I insist developers use TDD even if they don't do it on their day-to-day development. Dogfooding their own API is probably the only way to really ensure you get a usable API.
Elliotte thinks you should go further than TDD and write some sample programs first.

The challenges of API or library design come from the fact that you cannot be sure about Elliotte mentioned some of the fundamental principles of UI design that apply to API design.

  • The importance of consistency
  • Simple is better (and for god sake please keep complexity internal) which translated to YAGNI and "when in doubt, leave it out")
  • Smaller surface (API) is easier to use.

To demonstrate the point of proper API design Elliotte compared the complexity of JMidi vs. the elegance of JFugue. While in JFugue you just use a couple of lines to play a few notes:

Player player = new Player();
player.play("C D E F G A B")

JMidi required more than 20 lines of setting all sorts of things related to its internal structure.

Elliotte also had a lot of practical advice on varios aspects like maintenance, specific advice for Java, specific advice for .NET, etc. Instead of my reiterating it, I suggest you just take a look at the presentation which is available on his site.

One point Elliotte made which I don't completely agree with was that you should prefer classes over interfaces. we discussed this issue after the presentation and I said that it is true for libraries but I am not
sure that it is always true for frameworks (see Frameworks vs. Libraries for more details on the difference). In IoC scenarios, interfaces allows extending the framework for use with user defined types. One real-life example I offered was a plug-in framework we developed internally a few years ago. This framework incorporated a fixed set of components based on certain third-party components (grid, tree, etc.). This worked very nicely, until in one project we wanted to use other third-party components (let's say a ribbon or another grid) which left us with either waiting for the infrastructure guy to find the time to make the changes, fork the infrastructure code, or build something new (we went with building something new since working with end-users we found we actually didn't need most of the capabilities the framework offers like security/roles, role tayloring capabilities etc.)

On the other hand, one argument for using classes over interfaces that Elliotte is right about is that when you use interfaces and then make a change in that interface. The change breaks all clients. If, however, all the clients used a subclass they would automatically inherit the new functionality.

I thought I could work around this limitation in .NET 3.5 (or whatever microsoft will end-up calling it) by using extension methods so I did something like the following (tests, etc. are excluded for brevity)

  class Program
{
static void Main(string[] args)
{
testInterface tc = new testClass();
tc.DoSomthing();
tc.DoSomethingElse();

}
}

interface testInterface
{
void DoSomthing();
void DoSomthingElse(string test); // compilation error....
}

static class testInterfaceDefaultBehaviour
{
public static void DoSomethingElse(this testInterface ti)
{
System.Console.WriteLine("Doing something else");
}

}

class testClass : testInterface
{
public void DoSomthing()
{
System.Console.WriteLine("Doing something here...");
}
}
I was wrong....

Main does recognize the DoSomethingElse pretty well. However adding it to the Interface definition caused a compilation error.

This is a shame since the MSDN documentation says that:

In effect, extension methods make it possible to extend existing types and constructed types with additional methods.

If it had worked that would have let us have something like method_missing in ruby in C#. Well, .NET 3.5 is still in beta so maybe it would change (not counting on that).

Posted by Arnon Rotem-Gal-Oz at 10:12 AM  Permalink




 
INFO-LINK


Related Sites: DotNetJunkies, SD Expo, SqlJunkies