The most important aspect of any module is not how it implements the facilities it provides, but the way in which it provides those facilities in the first place.
-- Damian Conway in Ten Essential Development Practices
Public APIs are forever -- (you have) one chance to get it right.
-- Joshua Bloch in How to Design a Good API and Why it Matters
Interfaces matter. The more public they are, the more they matter. Indeed, once a public API -- such as Conway's CPAN modules or Bloch's Java SPIs -- attracts widespread usage, changing it becomes practically impossible. By contrast, just about anything else can be easily fixed in a later release.
And yet -- as indicated by Brooks' famous aphorism, plan to throw one away; you will, anyhow -- you're most unlikely to concoct the perfect API at your first attempt.
Making the task more daunting still, the dark art of interface and API design is certainly not an easy one to master, there being many disciplines in play: computer science, human factors (ergonomics), cognitive science, psychology, sociology, linguistics, usability, and so on.
I've spent the past few weeks researching this difficult topic and found very few references dedicated to this subject. Instead, many books devote a section or two to the art of interface design, or perhaps mention it in passing while analyzing a knotty design or coding matter.
This meditation reports the interface and API design references I've found useful and further presents some general interface design ideas and checklists in the hope that they may prove useful -- and that they might be improved upon by your insightful feedback.
Bloch's Seven Characteristics of a Good API
In his How to Design a Good API and Why it Matters keynote, Joshua Bloch proposed seven API design principles:
Bloch also cautions that you need at least three different implementations of an API before you can be confident of its soundness.
Conway's Sufficiently Advanced Technologies (S.A.T)
In module design, interface is everything. Going one step beyond this dictum, Damian demonstrates and explains several practical applications of Clarke's Law ("Any sufficiently advanced technology is indistinguishable from magic") by presenting a series of useful modules whose interface is...nothing
-- Advertising of Damian Conway's S.A.T seminar
Like Bloch, Conway proposes seven API design tips, namely:
Some example S.A.T.-esque modules that achieve a lot with very little interface are: strict, Smart::Comments, Perl6::Slurp, Getopt::Clade, Getopt::Euclid, IO::All.
If anyone has attended TheDamian's S.A.T. talk, I would love to hear more about it, since I've been unable to find much detail on this topic on the Web.
Perl 6 Design Principles
The linguistic and cognitive principles behind the Perl 6 design are nicely laid out in Perl 6 and Parrot Essentials as follows:
API Design Checklist
After all that, here's my attempt at an API design checklist:
Some Examples of Interface Mistakes
For some light relief from all those checklists, from the thousands of interface and API goofs that have been made over the years, I list here a few random ones I remember.
Perl 5's "string eval" and "block eval" is an example of violation of the "principle of distinction", aka "different things should look different" (this has been fixed in Perl 6, where block eval is now spelled try). This example illustrates the importance of choosing good names. Certainly, I've been shocked many times over the years at meeting experienced Perl programmers who were completely unaware that Perl supported exception handling and I feel that would not have happened had Perl sported a try keyword.
Lexical file handles are, for me, the most important feature introduced in Perl 5.6. Those evil old global file handles spawned a host of unfortunate idioms, such as:
select((select($fh), $|=1)[0]);In terms of a clear and simple interface to perform a simple task (set autoflush on a file handle), it doesn't get much worse than that, a compelling illustration of why keeping state in global variables is just plain evil. I won't dissect this horror further, other than to exhort you to please replace it with:
use IO::Handle; # ... $fh->autoflush();
To round out this section, notice that the ANSI C strtok function has a shocker of an interface: it unintuitively writes NULLs into the string being tokenized; the first call has different semantics to subsequent calls (distinguished by special-case logic on the value of its first parameter); and it stores state between calls so that only one sequence of calls can be active at a time (bad enough in a single-threaded environment, but so intolerable in multi-threaded and signal handler (reentrant) environments that the POSIX threads committee invented a replacement strtok_r function).
Human Aspects
The three greatest experts in the human side of interface design that I'm aware of are:
From The Design of Everyday Things, Norman's seven principles of design are:
Some other random principles derived from Norman and Nielsens's works are:
GUI Design Checklist
References
Some Related Perl Monk Nodes
++ for an amazingly comprehensive reference list.
However, in trying to absorb the 39 various bullet points of proposed guidelines on API design, I'm reminded of the Justice Stewart quote on pornography:
"I shall not today attempt further to define the kinds of material I understand to be embraced . . . but I know it when I see it . . . "
Of the various guidelines, I like Bloch's best because of the short and clear concepts they present. The others need to be parsed and understood and use several metaphors that impede clarity unless you already know what the authors are talking about.
Part of the challenge in giving API guidelines is that API style is context dependent as well. Different language styles lead to different API styles and what works best for one language might not work best for another.
For the reference section, I'd suggest adding things like Tufte's VDQI, as the principles he lays out for eliminating non-data ink have some nice parallels to API design -- particularly of the Conway style. On the other hand, sometimes, as with named parameters, clarity and extendibility means more ink (er, pixels), not less.
Separately, one reason that I like test-driven development is that by writing unit tests first before writing code, I wind up "using" my API before I implement it. At that point, the cost of change for the API is minimal. Even as code is implemented and additional features are added, the cost of change at that point is still pretty low. I'll frequently do several drafts of the API just while writing the test file.
-xdg
Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.
Great review! I've read some, but by no means all, of these references before, but I've never seen them pulled together in one place. They're not specific to Perl, and this article deserves a wider audience.
Although many of Jakob Nielsen's observations are sound, I'm not a fan of his recent writing -- I stopped reading AlertBox a few years ago when too many of his postings seem to be of the 'here's some cursory information -- buy the whitepaper if you want more'.
If you want a quick, simple book on usability concepts for web design, take a look at Steve Krug's Don't Make Me Think. It's the first book I typically give people on usability, as it's a very usable book itself.
This meditation reports the interface and API design references I've found useful and further presents some general interface design ideas and checklists in the hope that they may prove useful -- and that they might be improved upon by your insightful feedback.
For me the two greatest tools for interface/API design I've come across are Test Driven Development and Refactoring. Growing effective interfaces/APIs over time, rather than designing them all up front, is a stupidly useful technique.
API Design Checklist
Alan Shalloway and Ron Jeffries' list of features for a simple design is one that resonates for me:
The three greatest experts in the human side of interface design that I'm aware of are: Donald Norman, Jakob Nielsen, Larry Wall
I know lots of people who would argue with Nielsen's place on that list - especially with the absence of Alan Cooper!
While Larry is a hugely talented programming language designer (in my opinion anyway :-) I'm not entirely convinced that this necessarily maps onto "human" interface design in general.
Great overview, ++
In the next couple of days the Pragmatic Programmers are going to publish a book relevant to this (and seemingly language agnostic):
Kevin Pugh "Interface Oriented Design"
florg
perlmonks.org content © perlmonks.org and adrianh, drbean, eyepopslikeamosquito, florg, ForgotPasswordAgain, jhourcle, Polonius, xdg
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03