Developers learn to cope with quality attributes like maintainability, security, and performance. But usability is usually left behind. It belongs to the domain of UI developers and interaction designers. Yet even if the code doesn't have any UI, it has users: the programmers that have to use or maintain the APIs. This talk introduces usability concepts and practices applicable to the design of APIs.
54. Jakob Nielsen
Standards
Visibility of System Status
Match expectations
Recognition over recall
Diagnose Problems
Error Prevention
Affordance
Feedback
Errors
55. Domain correspondence
No. of steps
Consistency
Recognition over recall
Progressive Feedback
Abstraction
Learning
Extension
Hello, everybody, my name is Diego Fernández.
I’m part of the user experience team at MuleSoft.
Today, you can ask to your phone to give you directions.
An application like Google Now or Siri will send the audio to a service to interpret your voice. It will connect to other services to give you directions, ratings from social networks, traffic information, and even make a car reservation.
If you tell me this story when I had 12 years old, I’ll think that is science fiction.
But is not.
Many people in this room are in charge of making that fiction a reality.
Directly or indirectly you create the services that enhance our lives.
As service designers, we care about the quality. The services need to be secure, scale, and evolve.
When it comes to usability, we tend to think only on the front end.
There is no need to think much on the service usability because services are designed for developers by developers. So, they know exactly what is needed.
The API creators run with an advantage, they don’t experience the process of learning the API. In other words: you are not your API user.
And why is this important?
Bad API usability can lead to bugs. 8% of Android had misused TLS and are vulnerable to man in the middle attacks.
The main cause: API usability, so many developers by-passed the default implementations because it was hard to try things on development.
Usability is about how easy to use are the interfaces
We can decompose it further into quality attributes.
Learnability, Efficiency, Memorability, Errors, and Satisfaction.
Are highly correlated.
To design an usable interface, it’s useful to think in the user interaction as it were a conversation.
The user has an idea of how the system works, which is based on his goals, past knowledge and expectations. That is called the user mental model.
While the system exposes its own model, which is the reflection of what the system designers wanted to do.
To have this conversation the user needs to understand what are the things that he can interact with.
The components on the screen communicates that information, sometimes with text, or sometimes with their form. The later is called affordance.
When the user interacts, the system has to give some feedback. And the user learns from their actions.
Those interactions doesn’t happen on isolation, their are part of a larger journey of the user with the system. Making that journey explicit is useful for improving the usability, because it helps to understand what is the past context of the user and where he wants to go.
While interacting with the application the user may make mistakes, like choosing the wrong path to do things.
… or it may have small slips.
In both cases an usable system should have tolerance to human error. Usually the phrase “Tolerance to human errors” it’s abbreviated to just Errors
So we have 3 basic concepts: affordance, feedback, and tolerance to errors.
I'll use the term affordance in a loosely way, perhaps contributing to the misuse of it.
Technically an affordance is the possibility of an action in an object or environment.
In this picture, a possible action for the door handle is to push it. The shape of the handle makes pushing easier, even when the sign says "Pull".
In cases like this there is a dissonance, and we tend to ignore the sign.
Besides the technical definition of the word affordance, in UX design usually is used to describe the information that the objects transmits to us.
And designers will use expressions like: “the handle affords pushing” (even if is not a 100% correct use of the term).
The concept of affordance was made mainstream by Donald Norman, in his book The Design Of Everyday things. And many people calls this example “Norman Doors”
On digital systems, we don’t have a physical shape.
However, the design on the screen also communicates information. Just by looking or moving the mouse pointer we’ll know which things are clickable or not.
That information is also cultural.
For example, today many phone UIs uses a flat design. That design removed many clues, things don’t look like a button anymore. And there are actions that are totally hidden.
From the usability point of view, that is not good. However, once that people get use to it, they will see the signs of where to go in the system.
Meaning that there is a relationship between the affordances and standards.
For example, some objects will communicate the right affordances in a mobile UI, but maybe not in a desktop UI.
In a conversation when we say something, we can tolerate certain response delay. Why a maximum that is around a second. The same happens in a user interface
Any delay greater than a second, should show a progress feedback to the user.
also feedback comes from shorter interactions, when the user clicks something interactive on the screen or pushes a button, there has to be some feedback. Otherwise the user will not kwon that things are working
the concept of feedback is tightly associated with the display of the system status.
The goal is not only to react to user interactions, but to give the user a good picture of what is the state of the system.
There are different strategies to handle human errors.
Like allowing the user to undo or cancel a mistake.
Using constraints, can prevent the user from making a mistake. A good example of constraint on physical devices are the power adapters for direct current, like the ones used on laptops. As user it doesn’t matter how you plug the power, the design doesn’t allow you put plug it on the wrong way.
Using proper defaults can prevent errors too.
And when a task has many steps, the chances to make mistakes increase.
Also when the UI follows common patterns, the chances to make mistakes are reduced.
Principles like affordance or feedback can be applied to an API too.
For example, using the term API in a broad sense we can see an Java code example…
we have a Java framework, that is going to be reused in our team.
And we use dependency injection with private fields, what is the usability problem here?
… when a framework user wants to use an object instance it may fail, because the object was not correctly created.
That breaks my expectation of the default constructor, basically the default constructor is an affordance that tells me what I can do with the class.
I can a long JavaDoc indicating how to instantiate the class, but…
is like with the door example, users probably will not read the sign first
With HTTP APIs happens something similar.
Having path to delete resources, was a common solution to some browser limitations in the past. However, it communicates mixed signals: a GET verb is not intended to mutate data.
the line on top, is the usual what to select by ID on a OData based API.
while the one on the bottom is one of the usual patterns follow by many HTTP APIs
Which one is better? It depends on the standards that our API follows. The important concept is to communicate the right signals to the developers that are discovering how to use the API. And keep a uniform pattern.
every developer knows that doing something like this is bad, because you might be doing troubleshooting more difficult.
From the usability point of view an APIs that mutes error that could affect the system state, is not giving a good feedback to the user.
Sometimes the feedback can be misleading.
This is a real example from the GitHub API. By the way, I like the GitHub API, is pretty nice and simple to use, but it has some usability annoyances too.
For example issues in GitHub cannot be deleted. That breaks many user expectations, about what they can do with issues.
When you try to delete an issue, the system will respond with 404. Which is unexpected, as a developer probably you’ll keep wondering if the issue path was incorrect. So the system is failing to provide me a good feedback about what is going on.
a better response is to indicate that the method is not allowed, and even better is to provide a link to the right place in the documentation
when it comes to error prevention, and usability issues the Date class in Java and JavaScript are great examples of what not to do.
For example, the receives a year, month and day. But the values are used in a totally un-expected way. The year 2000 is represented with one hundred, months start from zero, and days from 1.
JavaScript receives a String, but the behavior changes, sometimes it uses the current time, sometimes it doesn’t. Why?
The first version of JavaScript didn’t took into account ISO-8601 dates.
They added that support in newer versions. In order to make things easy, the keep the same interface, changing the behavior according to the received String.
What are the usability issues here? First there is no affordance about the behavior change, there is nothing in the constructor that tells me how the API behaves.
Is not uniform, and because of that it leads to bugs.
For the case of user interfaces we took into account affordances and feedback, and also the user journey but does make sense to think on the user journey for the case of APIs?
one difference is that our API can be used in many different ways…
so it’s very hard to pick a few relevant stories
why don’t we think on the interface in a generic way?
But to ideate a generic interface, we need to have some use cases in mind.
And when we start thinking in every possible use case, without thinking on the needs of the people that is going to use the API, we can end with many features that we don’t need.
A report from 2002 used in many Agile software presentations, found that most of the time only 20% of the features in software are used frequently.
To analyze what are the user needs, we need to take into account that users will approach the API in terms of their goals.
It might be some obstacles to reach the goal
The story of overcoming those obstacles varies a lot with the skills of the person
Once that we know the persona, its goals, and what are the obstacles.
We can ideate a story on how the persona overcomes the obstacles to reach the goal.
This approach to stories differs from Agile User Stories. Because agile user stories usually don’t tell anything about the persona or the obstacles.
It also differs from Use Cases, because Use Cases put the focus on roles and detailed specification of how the system behaves.
The advantage of this approach is that it can be used to prioritize features, by covering different details on each release.
But when you have many stories, like in the case of an API, trying to map every possible story could be a daunting task. Even in that case using stories to think on obstacles and goals, helps to define the personas that will use your system.
Stories can be used to find gaps.
It’s also useful to think on a “Origin Story”: the story of how the user starts using the API. That helps to reduce the ramp up in certain difficult areas like setting up authentication.
A tool like the API Notebook can be used to tell de usage story of the API.
It also helps to reduce the difficulty of setting up the authentication
Another approach is to use some high level stories to determine the features and personas. And then see what features fits for each type of user
Some features can be very hard to use for some users and become a barrier, but be very valuable to an advanced user.
Others may add some value.
And others may be neutral. In this way we can have an idea of what areas can be problematic, and where to put the focus
Another area where stories are useful is to evaluate how uniform is our system model across the user Journey
Here the date uses ISO format…
but later in the journey uses a time stamp
This kind of problem is easy to detect when we make the journey explicit by ideating stories.
Also we can create a concept map from the story
A concept map is very similar to a UML class diagram.
But instead of focusing in the system classes, it puts the focus on concepts and their relationships. This can be used to capture concepts perceived by the user during the journey.
and the good news is that based on the concept maps, we can derive types, and reuse them across our API specifications
We did all of this API analysis, now how might we know that our design decisions were good?
We need to evaluate our API design…
Usability tests consists on giving to participants tasks to do with the API.
How I pick the participants? The stories helps on this. Because once you think about goals and obstacles, the required skills comes to mind. That helps you to start an analysis of users that will evolve, and helps to find the right candidates.
Variation:
Make the participants write what they want to do in pseudo-code
This will help to understand the user mental model, and how the API differs
The mocking service in API manager, can help you to quickly prototype the API and test it.
Studio will also mock responses when you import a RAML with examples. Then you can add extra logic for your usability tests.