Hacker News new | past | comments | ask | show | jobs | submit login
User experience design for APIs (keras.io)
274 points by _ntka on Nov 21, 2017 | hide | past | favorite | 42 comments



When I worked on the .Net framework at Microsoft we would run usability studies on many of the APIs well before we shipped them. It was always enlightening seeing how professional programmers use your API. We would assume that people would approach the API with a specific mental model for example, only to find that they thought about the API quite differently. I wrote an article in 2004 about how we approached API usability at the time: http://www.drdobbs.com/windows/measuring-api-usability/18440...

The great thing about doing usability studies on APIs is that it is easy to mock up a prototype of the API that people can start to code against. The API doesn't have to work but you get to see how people react to the names of classes, methods, parameters etc. I used to blog about API usability and what we were learning here: https://blogs.msdn.microsoft.com/stevencl/tag/api-usability/

There is a group of researchers and practitioners currently working on API usability. Some good links here: http://www.cs.cmu.edu/~NatProg/apiusability.html


Before I left Square earlier this year, I lead our design efforts on the developer API.

https://docs.connect.squareup.com/

It was really interesting work and the team was quite committed once we found the right team.

People always asked what does a designer do on an API. It turns out that if the team cares, quite a lot.

Documentation is the obvious one but lots of other things like structuring the actual information, setting up apps, working on API explorers, look at terminology even how the endpoints are thought of and of course, how do you easiest get up and running with the API.

It was surprisingly interesting work from a design point of view.


+1 Perhaps I have said this before, but UX folks have been my go-to colleagues whenever I need their inspsirations for anything ranging from graphs (like monitoring metrics) to debugging since the UX team is heavily involved from the inception of a project and sometimes have more intimate knowledge of the overall architecute of the project than the core developers do.

They are amazing (of course I am talking about the right kinds).


And I have it the same way with developers. They were always my go-to colleagues more than other designers for insights and

I would generally suggest to hang out with radically different perspectives than your own.

Luckily, in my new company both my partner feel the same way.


Right!

Worth sharing I am a DevOps so I do production support. One night I was at the dinner table fixing some horrible issue. My sister and brother-in-law asked why I was frowning. Initially I refused to explain the situation but they convinced me to brief them the failure. They raised some questions as outsiders (one is a doctor, another is an accountant). Immediately lightbulb lighted up! Within minutes I was able to find the root cause, pushed a fix, documented the issue, and closed my laptop.


Exactly


Square has excellent developer documentation! Hopefully it's in good hands after you've left. It would suck if the quality degraded.


Glad you like it. It's in good hands indeed.


Great documentation - I am looking to document our own SaaS app API in the coming months, and am inspired to follow Square's lead in terms of style and structure.

Did you use a third party documentation CMS for that, or roll your own internally for all the formatting etc.?


A combination. The actual API Reference is using a documentation CMS the other stuff is home-brewed.


It's been years since I've consumed a square API, but I found it amazing when I did. Thank you for your work, even if it came after I used it.

Do you think that the Square API hit the level of design just because of the people involved? Or are there organizational factors that played into it? I.e. was good API design seen at the top as a good reason to take longer with a release? I really want to find suggestions to take into my company.


A combination.

From the day I started back in 2012 it was clear to me that in order for us to grow functionality to enough verticals in the merchant space we would have to build an API as that was the only way to actually allow for the platform to grow beyond what we could build internally.

It was a hard push for a while though as the focus was in some of the other areas that made us actual money.

The first inception had a pretty strong team but less backup in the organization. We did a lot of great work that never saw the light of day.

Then the last couple of years it all changed and there was suddenly a push to do proper API I was "called into duty" again. This time the foundation was product led rather than tech led and that changed things a lot.

My personal experience was that people just saw API as some technical curiosity rather than as an actual foundation for the business.

Luckily plenty of people in the organization was aware of its importance.

This has changed a lot the last couple of years I think not the least because of Stripes documentation which is almost legendary today.

For some reason, I was always aware of its importance. I even wrote an essay about it back in 2009 and wrote:

"The next big battle is going to be a battle between digital ecosystems; not gadgets, not products and not services.

The most important weapon is going to be the WMCs: Weapons of Mass Connection, a.k.a. the APIs.

These APIs will make it possible for different organizations to have data flow freely between them. Allow for anyone with the right idea to leverage on others’ success without taking anything away from them. On the contrary, the more trusted interpreters you can give access to the data flow, the more robust the digital ecosystem will be."

http://000fff.org/the-power-of-digital-ecoystems/


You cannot build a large API effectively without using it. Programming is tons of details, and you're going to miss some if you aren't programming with your API yourself. It's like building a graphical user interface without ever firing it up.

For instance, if you build a simple REST interface with a list at /object/ and details at GET /object/1 and changes at POST /object/1, then you're good, right? This is a well-understood way of structuring things?

Well, what if your objects are really simple and someone has to synchronize 100k of them. It's not possible to do that efficiently through such an interface.

The API has to see some use, and it has to be able to evolve as you learn. And you need to be ready to make some sacrifices on your side of the fence, to make the life of the API user easier.


This is essentially the argument behind BDD, except applied at a level where the 'customer' is another developer.

Some of the worst APIs I've seen have been ones designed by a backend developer based upon some vague specifications handed down by a non-technical PO. They were often designed with half of the stuff that was necessary missing, lots of stuff that wasn't necessary and some stuff which made no sense before being thrown over a wall.

The better APIs were 'designed' by the developer who would write the code that would consume them. Even if that just meant an email or a scrap of paper with a few example URLs and snippets of JSON.


This. I work in Developer Relations and we used to say our motto was to be the "0th customer". Just by building on top of new APIs we planned to release we'd discover piles of issues and improvements that even the best developers can't spot in the design phase.


Programmers are so bad with this, this needs to be a more respected aspect of writing software in general. "Well, I comment everything" isn't enough. If you spent hundreds or thousands of hours on your API, but skimp on the part where you actually look at it from the users' point of view, that's such a colossal waste. You have to multiply the number of future users with the hours wasted on tedious setup hoops and learning confusing naming conventions. I look at the damage bad UX design can do to society, culturally, and I weep. A single bad decision, there, can cause millions of wasted hours.


Two decades into my career and I absolutely shudder every time I get a request to "integrate with <xxx>'s API, it'll be easy!"

It almost never is.

Everything about the experience sucks. The documentation is usually a mess and the code flow is usually strange as hell. But I can live with that.

It's the completely opaque error states that kill me. The article dedicated an entire section to it and I hope people take it to heart. When I pass bad data or something you're not expecting give me some clue as to what it might be!

I just spent 60+ hours working on an integration. 95% of that was spent changing parameters and encodings hoping that something would magically fix the 400 I kept receiving back from the server.

It turns out a shared secret had a typo (on my end).

The thing is this bad design is costing that company real $$. Not only was it a frustrating experience for me, I took a couple of hours of their engineers time trying to hunt it down. The lack of error handling made it difficult for them to track the issue down on their side as well.

I'll never forget the first time I touched Twilio's API. Everything was so clear. I had screwed something up, and got a clear message about what was wrong. It was magic.. and the whole thing was up and running in less than an hour.

Give me more of that please!


Nit: Really verbose error messages like the last example are at risk of being brittle. If the API changes, there may be a failure to update the error message. This is because the messages may concern things at a distance, and may have arbitrary prose that no longer makes sense.

For example, imagine if all your error messages were basically documentation style prose. That would be a nightmare, and would set you up to a lot of error message refactoring. A better strategy is somewhere in the middle.


Wow, the example in the article is an extremely verbose error message! But still, detailed and helpful error messages really do make the developer's life easier.

When building API end points, I take a different approach by including both messages and message codes, as well as a general "result" code (to make it easy to determine if it's a basic success/error result (also including the right HTTP code)).

An example that I'm working on right at the moment:

    {
        "result": {
            "code": "error",
            "message_code": "too_many_user_agents",
            "message": "You have sent %s user agents; this is more than the maximum allowed per batch (%s user agents). Please send fewer in each batch."
        }
    }
The message describes the problem; what they did wrong, what the limit is and how they can fix it so it doesn't happen again.

As well as this, the developer can easily check that the response code was an error, and there's the message_code - this will NEVER EVER change for this problem, so a developer could write code to specifically deal with that scenario.

However there's also a human readable message, which may potentially change (perhaps a grammar or punctuation fix, or if it included a URL it might change one day...)

I've found this approach is the best sort of middle ground.


I thought it was a good idea when an error message says

    bad request type, see http://company.com/API/ce32h 
except that it always seems the company forgets and removes the page.

maybe that could be fixed to some degree in a build step


Links to broader descriptions in your docs are one useful tool here.

As is having a hook in github which notices that a PR updates your API schema and adds a comment with a checklist of things to be sure you've considered.


I'm recommending this post to everybody I'm working with.

Many APIs are targeted to internal teams creating SPAs nowadays. Maybe the same developer writes both the backend API and the fronted app. Those APIs tend to be a wild west of all the mistakes the post is about. Documentation is often sub optimal, not to talk about vulnerabilities introduced by quick and dirty hacks because the team decides that the backend can trust the frontend (missing validations and missing authorization checks are common in the experience of a collegue working on penetration tests.)

Unfortunately such badly designed APIs are going to hinder the development of new functionality for the time being. We're moving from spaghetti code to spaghetti APIs.


Folks interested in this would probably also be interested in:

* this talk by Jesse Noeller from PyTexas a few years ago: https://www.youtube.com/watch?v=-vZ_E1OO_PY

* the WriteTheDocs community, which is sortof a mashup of traditional technical writers and software engineers. http://www.writethedocs.org/meetups/

* the mailing list GET PUT POST (shameless plug): https://getputpost.co/overhauling-api-docs-with-gocardless-9...


Related, but shameless plug, my PyCon 2017 talk "How to make a good library API" is also about the "API as UI" concept: https://www.youtube.com/watch?v=4mkFfce46zE

There's also a Django-specific version called "Your Django app is a User Interface": https://www.youtube.com/watch?v=Mnzvjn1v1CY


ooh thanks!


API documentation and usability is so severely lacking, even in products you would expect to deliver something excellent. I work for an ISP, and we've recently acquired industry standard software for things like DDI/IPAM and so on. The software, annual licensing and so on for some of these products is 5 to 6 figures, yet the API(s) are a mixture of ambiguous REST, undocumented SOAP and a day-to-day nightmare.

The only breath of fresh air I've had lately is interacting with the NetBox API which uses Swagger to sort of self-document and allow for testing.


I've found that first writing the docs first using API Blueprint has been the single most valuable thing I've done in my API development. It really makes you think about data shape, input params, edge cases etc. and leads to much nicer APIs in my experience. I think it's because, in my case anyway, it's a separate project and language to the implementation, so your thinking is not bound by whatever you're implementing with.


A few more guidelines that seem obvious to me, but which I see broken all the time:

1) If an API value can be changed any time, it should probably be a plain object property

2) If an API value can be changed but there are side effects, it should probably be a "setFoo" method

3) If an API value can be specified, but not changed after init/instantiation, it should probably be an argument to the constructor or init function


I really like the error messages that Joi[1] provides. You can easily use the error.message property to give a human friendly message to the end-user and if the default options don't serve your needs you can overwrite them with custom messages.

Someone made a Joi playground a few months ago, Joi Tester[2], that makes it really easy to test your Joi schemas. If you're curious, feel free to give it a try (I'm not affiliated with the tool in any regards but I do think it's awesome).

[1] https://github.com/hapijs/joi

[2] http://framp.me/joi-tester/


Everyone who has ever worked with a "proper" API (e.g. Mailchimp) with awesome and intuitive status messages will hopefully never again fail on this. Very bad that this is still not state of the art.


I find it interesting that you hold the MailChimp API in such a high regard.

I use it frequently as an example of how not to build an API. I find it hard to integrate efficiently with it - it got worse from version 2 to 3, although some of the blunders have later been fixed.

You're probably right that the error messages are relatively thorough. Many of the constraints aren't documented in the reference documentation, though, so it requires trial-and-error.


Great, except for this…

> (in general, always use ValueError and avoid assert).

ValueError is for when,

> an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception

(the docs explicitly note only for builtins, but I'm frankly okay w/ people using it in their code.)

You should not be raising this when you should be raising AssertionError, however, the two conditions are very different; the latter is for conditions that should be true but for some reason aren't. I find these usually crop up when running through a bunch of ifs:

  if a:
  elif b:
  elif c:
  else:
    # *One* of the above should always match, in this case.
    # This branch should never be taken, and it wasn't any fault of the user we're here.
    raise AssertionError('good description of the situation')
Attempts to restructure the above are usually fairly bad: you can omit the `else`, but then execution will never take any branch, and if the branches do something like initialize a variable that the code following the branches will make use of, you're doomed anyways, and it's better to bail in an informative manner. You can meld the last elif and else together (i.e., the else just handles case C above), but then it also inadvertently handles unexpected states D, E, etc. too.

IMO, AssertionErrors should indicate bugs in the called API. ValueErrors indicate bugs in the caller's use of the API.

(You may choose a less "destructive" method of asserting, such as logging, but in my experience, these get lost, and if you're in an undefined state then you still need to find some way to repair that state, and in my experience most attempts to do so are more trouble than they're worth. It's better to fail earlier and harder and louder, s.t. bugs are discovered and swiftly fixed.)


> IMO, AssertionErrors should indicate bugs in the called API. ValueErrors indicate bugs in the caller's use of the API.

Yes, I agree with this stance. `ValueError` should be used for user-provided input validation (as well as `TypeError` in some cases). But as it happens, many Python developers use `assert` statements to do input validation, and generally don't provide any error messages in their `assert` statements. I'm suggesting going with `ValueError` (and a nice message) instead.


APIs and programming languages are UI for programmers, so yeah, they deserve some UX thinking.

However, where is the current trend of functional programming in this piece? (I am not disparaging FP, on the contrary, I think it's a good development.)

Shouldn't API calls be, for example, easy to test? In functional programming, we often avoid doing actions directly, and instead give descriptions of actions (in form of functions) that are to be made. Does your API support that?

What about minimization of the state that the API requires to keep, and its transparency?

I am sorry if I come off a little incoherent. Best would be if I could give some tool a program that calls an API, say a sequence of API calls. And I would be told, this sequence is valid for the API. So I could prove for my program that it is accessing the API correctly.


Reminds me of Bryan Helmig's (Zapier) talk at APIDays SF back in 2013 about an API consumer shift.

http://bryanhelmig.com/your-api-consumers-arent-who-you-thin...


> Deliberately design the user onboarding process. How are complete newcomers going to find out the best way to solve their use case with your tool? Have an answer ready. Make sure your onboarding material closely maps to what your users care about: don't teach newcomers how your API is implemented, teach them how they can use it to solve their own problems.

Really good tip! Going to spend a little more time reworking my onboarding workflow with this in mind.


Perhaps "Don't change your API to something incompatible but with the same names" would be a good piece of guidance too?

https://github.com/fchollet/keras/issues/3921#issuecomment-3...


Not an "API", but git has a terrible UI... yet the error messages (and guidance included in response to correct commands) are the best I've ever seen. They guide the user through a typical workflow.

A similar guidance is pop-ups in games (e.g. when next to car, "F to enter").


After three attempts at designing an ML rest-lile API, I ended up writing the deepdetect's API. Never touched its fundamentals since mid 2015. Very very far from perfect but has served great til now!


pytorch with a keras like functional/layers API would be amazing. I'm guessing we might see that in tensorflow when keras adds support for the new eager mode.


Can you elaborate? I feel like torch.nn gets you pretty close.


It's telling that this is on the Keras blog, because the Tensorflow APIs are quite a mess




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

Search: