Build Design Systems With Penpot Components
Penpot's new component system for building scalable design systems, emphasizing designer-developer collaboration.

medium bookmark / Raindrop.io |
Images:
We have the same usability expectations from everything we’re interacting with, UIs or APIs. Therefore, the guidelines that we use for UI can also be translated to API. We’ve gone over the first 5 guidelines in a previous article. Now, it’s time for the rest.
UI: Recognizing something as familiar involves a minimum amount of cognitive energy and is triggered by the context. Recall implies retrieving details from memory and takes much more time. It’s easier to choose from a set of options, than to write those options from memory. A simple UI, using generally known icons is based on recognition. A command-line interface is based on recall. Information and functions should be made visible, intuitive and easily accessible.
The pencil icon is a symbol for editing, easy to recognize, independent of the app.
A variable name should say what it represents, not how it’s used: isLoading
, animationDurationMs
.
A class name should be a noun and should say what it represents: RoomDatabase
, Field
.
A method name should be a verb and should say what the method does: query()
, runInTransaction()
.
UI: Your application might be used by both inexperienced and experienced users. Create a UI that it caters to both of these types of users and allows them to adapt frequent actions. It is said that 20% of the features are used by 80% of the users. You need to create a balance between simplicity and power. Find out what those 20% are for your app, and make those parts of the app as easy and as simple to use as possible. Apply the principle of progressive disclosure and allow the rest of your users to access advanced features in a secondary screen.
The Wi-Fi settings defaults to basic options but also contains advanced options. It fits the needs of the user.
Users should be able to accomplish their tasks with the API efficiently and the API needs to be flexible. For example, when querying a database, Room provides different return values allowing them to do synchronous queries, use LiveData or, if they prefer, use APIs from RxJava 2.
@Query(“SELECT * FROM Users”)
// synchronous
List<User> getUsers();
// asynchronously
Single<List<User>> getUsers();
Maybe<List<User>> getUsers();
// asynchronously via observable queries
Flowable<List<User>> getUsers();
LiveData<List<User>> getUsers();
Methods placed in a class that has no direct relation to the code that the developer has already written are hard to find. Even more, “Util” or “Helper” classes that tend to group a lot of useful methods can be hard to find. When using Kotlin, the solution for this is to use extension functions.
UI: The UI should be kept simple, containing only the information relevant for the user at that time. Irrelevant or rarely needed information should be removed or moved to other screens since their presence distracts the user and decreases the importance of the information that is indeed relevant.
Pocket Casts app uses a minimalist design
In the episode lists screen, this podcast app shows minimum, contextual and relevant amount of information: if the user hasn’t downloaded an episode, the download size and the download button are visible; if the user has downloaded it — the duration and a play button. At the same time, all of these and more are present in the details screen for the curious user.
API: API users have one goal: to solve their problem faster with the help of your API. So make their path as short and direct as possible.
API: Unnecessarily exposing internal API logic can confuse the user and lead to bad usability. Don’t expose methods and classes that are not needed
API: Starting with 22.1.0, the Android Support Library provides the RecyclerView
suite of objects to enable creation of UI elements based on large data sets or data that changes frequently. Whenever the list changes, the RecyclerView.Adapter
needs to be notified with the data that was updated. That lead to developers creating their own solutions for computing the differences between lists. In the 25.1.0 version of the Support Library, this boilerplate was drastically reduced by the DiffUtil
class. Moreover, DiffUtil
uses an optimized algorithm, reducing the amount of code you need to write and increasing performance.
UI: Provide your app’s users with error messages that help them recognize, diagnose and recover from errors. Good error messages contain a clear indication that something has gone wrong, with a precise description of the problem in polite and human readable language, containing constructive advice on how to fix the problem. Avoid showing a status code or an Exception class name. The user won’t know what to do with that information.
Error messages when creating an event. Source
Show an error on an input field as soon as it’s defocused, don’t wait until the user presses a button to submit the entire form, or, even worse, wait for the errors to come from the backend. Use the TextView’s capabilities to display an error message. If you’re creating an event form for example, prevent your users from creating events in the past by setting constraints directly to the UI widgets.
API: The sooner a bug is reported, the less damage it will do. Therefore, the best time to fail is at compile time. For example, Room will report any problems with incorrect queries or wrongly annotated classes at compile time.
If you can’t fail at compile time, then try to fail at run time as soon as possible.
API: Users shouldn’t be using exceptions for control flow. Exceptions should only be used for exceptional conditions or incorrect API usages. Use return values to indicate this, where possible. Catching and handling exceptions is almost always slower than than testing a return value.
For example, trying to insert a null
value in a column that has a NON NULL
constraint is an exceptional condition and leads to an SQLiteConstraintException
being thrown.
API: Developers already know what IllegalStateException
or IllegalArgumentException
mean, even if they don’t know the reason this happened in your API. Help your API users by throwing existing exceptions, preferring more specific exceptions to general ones, with a good error message.
When creating a new Bitmap
via createBitmap
method, you need to provide elements like the width and the height of the new bitmap. If you’re providing values <= 0 as arguments, then the method will throw an IllegalArgumentException
.
API: The same guidelines for writing error messages for the UI apply to the API also. Provide detailed messages that will help your users fix their code.
For example, in Room, if a query is run on the main thread, the user will get a java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time
. This indicates that the state in which the query is being executed (main thread) is illegal for this action.
UI: Your users should be able to use your application without any documentation. For complex or very domain-specific apps, this might not be possible so, if documentation is needed, make sure it’s easy to find, easy to search, and that it answers common questions.
Elements like “Help” and “Send feedback” are usually placed at the bottom of the navigation drawer
API: Good naming of methods, classes and members makes an API self documenting. But no matter how good an API is, it won’t be used without a good documentation. This is why every public element — method, class, field, parameter — should be documented. Whatever is easy and obvious for you, as an API developer, might not be as easy and obvious for your API users.
API: The code examples have several roles: they help the users understand the purpose of the API, the usage, and also the usage context. Code snippets are intended to demonstrate how to access the basic API functionality. Tutorials teach developers a specific aspect of the API. Code samples are more complex examples, usually an entire application. Of these three, the biggest problems appear when you don’t have code samples because developers are missing the bigger picture — how all of your classes and methods work together and how they should work together with the system.
If your API becomes popular, chances are you will have thousands of developers using those examples and those samples will become the model of how your API should be used. Therefore, every mistake you make will come back to bite you.
We’ve learned a lot along the years about the usability of user interfaces; we know what our users need and how they think. They want UIs that are intuitive, efficient, correct, that help them do a specific task, in an appropriate way. All of these concepts go beyond UIs and are applied to APIs also, because developers are users too. So let’s help them (and us) and build usable APIs.
APIs should be easy to use and hard to misuse — it should be easy to do simple things, possible to do complex things and impossible, or at least difficult, to do wrong things. Joshua Bloch — source
AI-driven updates, curated by humans and hand-edited for the Prototypr community