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 characteristics of a good API:

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

-- from advertising of Damian Conway's S.A.T seminar

Like Bloch, Conway proposed seven API design tips, namely:

Some example S.A.T.-esque modules that achieve a lot with very little interface are: strict, diagnostics, Smart::Comments, Perl6::Say, Perl6::Slurp, IO::Prompt, Getopt::Clade, Getopt::Euclid, Tie::File, Win32::TieRegistry, IO::All.

Further tips gleaned from listening to TheDamian's YAPC::Asia 2006 S.A.T talk are:

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. (Update: Try Catch Exception Handling finally made it into core perl 5.34 as an experimental feature - see also New built-in perl5.38 try/catch syntax and SO question about Perl exception handling).

The Unix make utility decrees that the actions of a rule must start with a tab. If you accidentally insert a space before the leading tab, look out! Ditto if your editor or other tool is configured to automatically convert tabs to spaces. This unfortunate design choice is a violation of the principle of least astonishment because most programs treat spaces and tabs the same way. Moreover, when you hit a (typically cryptic) error message for using a space instead of a tab, it may take a long time to figure out what the problem is because tabs and spaces look the same in most editors.

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 replace it with:
use IO::Handle; # update: not needed for Perl 5.14+ # ... $fh->autoflush();

Another file handle annoyance is:

print $file $name, $rank, $serial_num, "\n";
Do you want $file to be treated as a filehandle ... or did you just forget a comma? Two ways to clarify are:
print {$file} $name, $rank, $serial_num, "\n";
and:
use IO::Handle; $file->print( $name, $rank, $serial_num, "\n" );

To round out this section, notice that the ANSI C strtok function has a shocker of an interface: it surprises by writing NULLs into the input 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 principles derived from Norman and Nielsen's works are:

GUI Design Checklist

Here's a brief GUI design checklist. For more details, see the most excellent About Face 2.0 by Alan Cooper.

References

References Added Later

Related Perl Monk Nodes

Many references were added long after the original post was made. Updated 10-jun: Minor wording improvements, expansion of "Conway's S.A.T" (thanks drbean), "Human Aspects", "GUI Design Checklist", and "References" sections. Updated 30-jan-2011: Added modernperl Ugly Perl reference. Updated 20-Jan-2021: Added makefile example where tabs are different to spaces.


In reply to On Interfaces and APIs by eyepopslikeamosquito

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.