API Design Thinking
In this article
"When the point of contact between the product and the people becomes a point of friction, then the [designer] has failed. On the other hand, if people are made safer, more comfortable, more eager to purchase, more efficient — or just plain happier — by contact with the product, then the designer has succeeded." — Henry Dreyfuss
Can we apply design thinking to improve our APIs from being a failure, according to Dreyfuss' definition?
Design thinking follows 5 essential steps:
- Empathize with the user.
- Now that you understand the people involved, define the problem.
- Ideate on possible steps to solve the problem.
- Prototype possible solutions.
- Solicit feedback, test your approach and iterate on a final answer.
On previous projects, our UX designers spent significant amounts of time with actual users to understand their frustrations with existing systems, their needs and motivations. They spent time riding with repair technicians or making pizzas in a store.
An API is not about collecting data in the fastest and most expedient way possible for us as developers — it's a deliverable that enables our users to get their job done. Our users are developers just like us. The goal of the first design step is to set aside our own assumptions and preconceived ideas to see the problem our API solves from a different perspective, to appreciate what it will be like to consume the API.
First and foremost, we have to remember that people use our API.
Once we understand our users and their needs, we should take a step back and frame the problem we're solving from our user's perspective. Ask how they will use it. This could be the difference between:
"As a technical leader, I need to communicate an idea by publishing an article on the WWT Platform."
"I need a rich-text edit field to accommodate at least 1500 words of content and ability to press a submit button while ensuring I have a Wi-Fi connection."
"I need to make a REST call to an HTTPS endpoint that accepts a POST of JSON content and stores it into a database."
Defining the problem requires balancing both art and science; art pushes engineering/science out of its narrow methodical box, while science provides analytical guard rails to keep art on track. We need both. UX designers normally take what they learned from meeting with real users and analyze it while also allowing themselves space to be creative about describing the problem that needs to be solved. As engineers, we often get stuck in the "how" of collecting arguments, data formats and network protocols, when we actually need to take time to step back and ask "why?".
By step three of the process, asking "why" should have shaken us loose from the obvious "how" to get us to a point where innovation can happen. It's easy to add another method to the REST interface, but should we? Are there other approaches? Other ways to structure the data that makes the interface clearer?
Asking "why" should challenge the status quo, even if we return to the place we started at, as there are benefits to considering alternatives. Are there new ways to approach the API, new languages, libraries or architectures? At this stage, no idea is off-limits. There are many methods for ideation. Pick one and see how it works for you. At the end of the day, the most important thing is to break out of habitual patterns and allow change to happen.
If Ideation is the process of brainstorming the possibilities of how our API might solve the user's problem, then prototyping and testing give a sense of which of the many ideas have merit. This is the step where UI designers create low-cost wireframe mockups so they can rapidly test a handful of different options and get user feedback. Although it's not going to production, you can apply the agile principle of release early and often. At the prototyping stage, our UX designers will have several options sketched out, and the end result might only validate that elements of each have merit, or one might emerge a clear winner.
Perhaps our users like the use of a builder pattern, but really dislike some of the method namings? Perhaps multiple method arguments should be replaced with an object, or a partially used object decomposed into something smaller and more focused on the need at hand? Is there an argument for stronger type-safety, or moving to a loosely typed language?
Can we learn from our UX practice, where we create lightweight prototypes to get quick feedback from our users?
I've found that unit and integration tests provide one approach to having a lightweight prototype where the exposed API contract is executable, and I can see how my changes affect end-users. I quickly learn empathy, as the tests force me to experience the pain my users would feel as I set up and tear down tests around a given section of the API.
Automated tests can never replace genuine feedback from our users though. The essence of the "test" stage of design thinking is that we need to hear feedback. If we invested too heavily into a fully formed implementation, we might be reticent to truly listen and make the requested changes, so keep the prototypes lightweight and the feedback cycle quick. Think of it as the "red – green – refactor" cycle of test-driven development but applied at the design stage of our API.
We must ask ourselves (honestly), is this an API we would want to use? In six-months time, when you no longer have context, would it still make sense to us?
There's a balance point between doing too much in a single step and an API feeling like a bowl of popcorn where none of the pieces seem to fit together. Finding this balance point is an art, but it elevates the API from merely functional to feeling great, from something our users dread using to something they talk about and even enjoy.
As an example, our team needed to set up realistic data for our automated testing. A lack of empathy and an over-familiarity with one particular programming language meant that it was delivered to us as a single stored procedure call with many dozens of parameters that would only succeed if you understood the implied relationships between groups of parameters (due to integrity constraints on the many database tables hidden behind the scenes). We were stunned and found ourselves saying, "there's got to be a better way!" while referencing "data setup" as a pain point in numerous retrospectives for the lifetime of the project.
Design thinking that builds in empathy for our users and genuine feedback should help ensure that our API user experience is a delight and not a point of friction for years to come.