Hacker News new | past | comments | ask | show | jobs | submit login
The Little Manual of API Design (2008) [pdf] (tum.de)
142 points by daviducolo on June 18, 2015 | hide | past | favorite | 25 comments



I've been thinking about this at a meta level and I can't get to reach any conclusion.

Think of a simple instruction: draw a line from (a,b) to (c,d).

How many ways can it be "encoded as an API"? we already have a gazillion forms of drawing: SVG, OpenGL, Postscript, Asymptote, PGF/Tikz, Canvas, and so on. Why?

Forget about existing line-drawing APIs. Which of these would you choose?

- line(a,b,c,d)

- Line (a,b) to (c,d)

- draw-line (a,b) (c,d)

- drawline

- make-a-line

- line-from-to

- ...

- ...

Not to mention placement of parentheses (C vs s-expression), curly braces or angle bracket. The list goes on.

I started reading Bertrand Russell's 'On Denoting' but I'm not really sure it'll help me out (although I haven't finished reading it yet).

At another level: once you've converted your vector graphics primitive to "pixel maps", that itself is no less of a language. So at a more fundamental level, it's really information represenation, not language.

I'm not sure where the problem is, language vs computable-form vs information-representation.

Not to mention metalinguistics. Because API is not just one layer on top of your program. You build an API/language layer as a scaffolding, to use it to build a higher level API/language layer. And apparently its turtles all the way up and all the way down.

It's all very confusing


When languages are consistent, they are much easier to learn. Spanish is fabulously regular, which helps many people learn it.

When a second language is similar to your native tongue, it is much easier. Swedish speakers have very little trouble learning Danish, but Turkish is a bunch harder, and Korean is _very_ tough.

My point here is that your example is difficult because it lacks any larger context. If you want your API to be easy to learn for Lispers, then s-expressions are going to be better. If the rest of your API uses verbs like "make-a-box" and "paint-the-background", then "make-a-line" is probably the right fit.

Design always works this way: it is defined by its users and its context. When you hit trouble like this, step back.


When thinking about the API only, any one of your line implementations seems just as good as the other.

But if you also ask "which of these makes sense for the client application" that will likely narrow your options down.

Indeed, the parent PDF says that before even writing any code, write use cases. "The implementation should adapt to the user, not the other way around."


If we're going to design our own syntax to draw lines, I'll add a few things to the host language: First, a "point" data type, and a "line" data type. Most language can do this already.

Then I'd add some special syntax to denote points. Like one of those:

  (a, b) -- ordinary tuple.  Of the shelf in ML and Haskel.
  [a, b] // may work in C and C++
  (a; b) // Alternative syntax
We also need an operator to draw the line. Possibly a triple dash:

  (a, b) --- (c, d)
And of course this can be combined together (here in my custom version of C):

  Point p = (a; b);
  Line  l = p --- (c; d);
Now we need a way to actually draw the line. As a side effect. It could be a procedure, but when there's one line, there will be others. So, we often need to draw a list of lines. This syntax might work:

  draw {
    p      --- (c; d);
    (e; f) --- (g;h);
    (g; h) --- p;
  }
The semantics would be what you'd expect, with the possible benefits of some optimisation (some constructors can be avoided, the data can be packed before we draw all the lines at once…)

---

Now If I get to really try that in a real-world project, I'll probably find many ways to improve this lousy design.


Apropos of nothing much, back when I was coding primarily in Objective-C (incidentally, for cross-platform Linux and Windows, but not anything Apple) the form of the function call would give another much more expressive option. I'd write something like this:

  [drawline  from: A
               to: B];
Obviously, some people hate it.


Objective-C syntax aside, keyword arguments are great for readability and maintainability.


The right answer for a API to draw a line like you describe is to provide every possible way to draw a line since you never know which one the user wants to use. Granularity is one of the general five properties of every good API, of course it is not always good to provide all possible ways since it hurts compactness. The best I have ever heared about API design was a talk from Casey Muratori: http://mollyrocket.com/casey/stream_0028.html


It's not that you want to provide "every possible way to draw a line".. ideally your API provides the primitives necessary for a client to draw lines in all the ways that are useful.

The primitives that you provide relate to the overall goal of your API. Do you want people to use it for mathematical graphing? Will they start with an equation? Or is this for a website, where all you really want is <hr/>.


For your particular example QBasic was actually a nice way of writing it:

    LINE (a,b)-(c,d), colour
On the other hand, they went nuts with it and had ways of making rectangles with the same syntax, too:

    LINE (a,b)-(c,d), colour, B  ' Rectangle
    LINE (a,b)-(c,d), colour, BF ' Filled rectangle


> Because HTML forces us to repeat the name of the tag in the close tag, it encourages us to write things like:

   the <b>goto <u>label</b></u> statement
What sort of demonic possession bullshit going on here? Who is "encouraged" to do such thing?


You are, presumably, already a developer, so you already understand nesting. Perhaps a better example that a beginner could find quite reasonable after learning about start and end tags:

   <u>Underlined. <b>Bold and underlined.</u> Bold only.</b>
Why shouldn't that work?


This is a much better example of the point the author was trying to illustrate.

Though I'm not sure sure if the HTML / TeX comparison is the best to exemplify the concept. I feel that if a beginner were to make the conceptual mistake that HTML tags are not nested that they may also not grasp that {}'s are to be nested as well. Thus falling into the same trap as HTML.

I'll admit that {}'s look more obvious to form a nested structure but it may also be that my eyes are trained to see them exactly as such.


Fun thing is: HTML goes out of its way to ensure that this does work.


That's not allowed because parsing that kind of nesting requires a context sensitive parser, which is much more expensive computationally than context free parsers.


I understand that, you understand that, and your parent commenter probably understands that, but the point is that a user of HTML should not have to understand it.


IRC formatting codes (not standard, but popularized by mIRC and thus implemented by most clients) are also toggles instead of begin-end pairs, so they allow this. If I remember correctly, old text processors like WordStar also implemented formatting as toggles.


I guess the OP means something more like "HTML makes it easy to make mistakes like ..." which is true. I believe English is not his native language.


I think that is what the author means, but I also think it's a valid usage; it's ironic.


Related to section 3.7: you should try to create as much builtin functionality as possible (ideally, all of it...) using the mechanism(s) provided for 3rd party extensions. This can give everybody confidence that the extension mechanism is useful and complete; if library source code is provided, it also provides a good stock of example extensions.


some good advice, some doubtful advice.

One advice in this pdf is that on designing first before implementing. I think iterative cycles of design / implement / use / design /implement use yield better results.


Iterative cycles take advantage of the regularity of change. APIs shouldn't change once public, hence the emphasis on Big Upfront Design. However, change still needs to happen so versioning comes into play.

Personally, when it comes to APIs, you can tell those that have been designed upfront rather than iteratively; they are generally better IMHO.


The API that appears to be well-designed up front was probably preceded by many not as great APIs either done by the same designers, or that could at least be learnt from. That is still quite iterative, just in the long term sense. Real waterfalls don't exist.

If you have an API that does something well known, find and learn from existing APIs that do that. If not, then he prepared for lots of trial and error, scenarios you didn't think of, and so on. It might make sense to put out a "worse is better" API first so the learning and feedback loops can start.


What I would advice is to design the API (public part) without considering the internal code (private part).

We often change our point of view on how to solve a problem (private part), but rarely the problem itself changes (public part).

Iterate away your (internal) architecture as much as you want, but when dealing with the API (your external world interface) make sure to put yourself in your user shoes.


Seen some of these around... what I've been craving for is a little pdf of web api design.


Something that I've found extremely valuable with API design for public facing APIs is use readme driven development. I think it complements a lot of the points brought up in the PDF .




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: