laitimes

UUID design strategies to improve user experience

author:Flash Gene
本文翻译自 The UX of UUIDs,作者:Andreas Thomas, 略有删改。

Unique identifiers play a critical role in all applications, from user authentication to resource management. While using a standard UUID will meet all your security concerns, we can improve a lot for our users.

This post discusses the importance of unique identifiers (UUIDs) in applications and how there are some improvements that can be made to enhance the user experience.

UUID design strategies to improve user experience

Ensure uniqueness

Unique identifiers are essential to distinguish between entities in a system. They provide a reliable way to ensure that each project, user, or piece of data has a unique identity. By maintaining uniqueness, applications can effectively manage and organize information, making operations more efficient and promoting data integrity.

Any securely generated 128-bit UUID is sufficient for us, there are plenty of libraries to generate UUIDs, or you can use the standard libraries of your programming language of choice. In this blog, I'm going to use Typescript examples, but the basic idea works for any language.

const id = crypto.randomUUID()
// '5727a4a4-9bba-41ae-b7fe-e69cf60bb0ab'
           

We could stop there, but we're going to do it better and enhance the user experience with a few small improvements:

  • Make them easy to replicate
  • Add a prefix
  • More efficient coding
  • Change the length

Copying UUIDs is cumbersome

Try copying the following UUID by double-clicking on it:

c6b10dd3-1dcf-416c-8ed8-ae561807fcaf

If you're lucky, you'll be able to duplicate the entire UUID, but for most people, they'll only get one part, and one way to improve the usability of unique identifiers is to make them easy to copy.

This can be achieved by removing the hyphen from the UUID, allowing the user to simply double-click on the identifier to copy it. This small change can greatly improve the user experience when dealing with identifiers.

Removing hyphens from code is simple, and here's how to do it in js/ts:

const id = crypto.randomUUID().replace(/-/g, "")
// fe4723eab07f408384a2c0f051696083
           

Try reproducing it now and feel so much better!

Add a prefix

We can help users distinguish between resources in different environments or systems by adding a meaningful prefix. For example, Stripe uses a prefix like sk_live_ to represent a key for a production environment, or a cus_ to represent a customer identifier. By increasing such a prefix, we can ensure clarity and reduce the likelihood of confusion, especially in complex systems where multiple environments coexist.

const id = `hello_${crypto.randomUUID().replace(/-/g, "")}`
// hello_1559debea64142f3b2d29f8b0f126041
           

Naming prefixes is as much an art as naming variables. You want to be descriptive, but as short as possible. I'll share our naming strategy later.

Use base58 encoding

In addition to using hexadecimal representation identifiers, we can also consider more efficient encoding, such as base58. Base58 encoding uses a larger character set and avoids the use of obscure characters, such as uppercase I and lowercase l, resulting in shorter identifier strings without sacrificing readability.

For example, an 8-character base58 string can store about 30,000 times the state of an 8-character hexadecimal string. At 16 characters, a base58 string can store 889,054,070 combinations.

You'll most likely still choose to do this using your language's standard library, but you can also use a library like nanoid, which works with most languages.

import { customAlphabet } from "nanoid";

export const nanoid = customAlphabet("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");

const id = `prefix_${nanoid(22)}`
// prefix_KSPKGySWPqJWWWa37RqGaX

           

Here we generated a 22-character long ID, which can encode about 100 times the number of UUIDs while being 10 characters shorter than the UUID. The greater the total, the fewer possible duplicates.

-字符长度总数UUID16322^122 = 5.3e+36Base58582258^22 = 6.2e+38

Change the length

Not all identifiers need to have a high level of crash resistance. In some cases, a shorter identifier is sufficient, depending on the specific requirements of the application. By reducing the length of identifiers, we can generate shorter IDs while still maintaining an acceptable level of uniqueness.

Reducing the length of IDs may be good, but you need to be careful and make sure your system is resilient to ID conflicts. Luckily this can be easily done at the database level, in our MySQL database we mainly use IDs as primary keys and the database protects us from conflicts. If an ID already exists, we just generate a new one and try again. If our conflict rate rises significantly, we can simply increase the length of all future IDs.

长度示例总状态nanoid(8)re6ZkUUV1.3e+14nanoid(12)pfpPYdZGbZvw1.4e+21nanoid(16)sFDUZScHfZTfkLwk1.6e+28nanoid(24)u7vzXJL9cGqUeabGPAZ5XUJ2.1e+42nanoid(32)qkvPDeH6JyAsRhaZ3X4ZLDPSLFP7MnJz2.7e+56

Practical use

Finally, I'd like to share what we've implemented here and how we can use it in our codebase. We use a simple function that takes a typed prefix and then generates an ID for us. This way we can make sure that we always use the same prefix for IDs of the same type. This is especially useful when you have multiple types of IDs in your system.

import { customAlphabet } from "nanoid";

export const nanoid = customAlphabet("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");

const prefixes = {
  key: "key",
  api: "api",
  policy: "pol",
  request: "req",
  workspace: "ws",
  keyAuth: "key_auth", // <-- 这是内部的,不需要短或漂亮
  vercelBinding: "vb",
  test: "test", // <-- 仅用于测试
} as const;

export function newId(prefix: keyof typeof prefixes): string {
  return [prefixes[prefix], nanoid(16)].join("_");
}
           

When we use it in our codebase, we can make sure that we always use the correct prefix for the right type of ID.

import { newId } from "@unkey/id";

const id = newId("workspace")
// ws_dYuyGV3qMKvebjML

const id = newId("keyy")
// 无效,因为`keyy`不是有效的前缀名称
           

At last

This article discusses how the user experience can be improved when using a unique identifier (UUID) in an application.

  1. Simplified Copying: By removing hyphens from UUIDs, it is easier for users to copy the entire identifier by double-clicking.
  2. Add prefixes: Using meaningful prefixes can help users distinguish between different environments or resources, such as Stripe using specific prefixes to distinguish between production environment keys and customer identifiers.
  3. Efficient encoding: Consider using an encoding method such as base58, which uses a larger character set and avoids confusing characters, resulting in shorter and more readable identifier strings.
  4. Change the length: Depending on the specific needs of your application, you can generate shorter IDs by reducing the length of the identifier while remaining unique enough.
  5. Protection at the database layer: At the database level, primary key constraints can be used to prevent ID conflicts, which can be resolved by increasing the length of future IDs if the conflict rate increases.

By implementing these improvements, we can enhance the usability and efficiency of unique identifiers in our applications. This will provide a better experience for users and developers as they interact and manage with various entities in the system. Whether it's easily duplicating identifiers, differentiating between different environments, or implementing shorter, more readable identifier strings, these strategies can promote a more user-friendly and robust identification system.

After reading this article, if you find it useful, remember to like and support, and collect it Maybe you will use it one day~

Author: Nancheng

Source-WeChat public account: Nancheng University front end

Source: https://mp.weixin.qq.com/s/m0IMJY_F4CcFFJ2KNIO15A

Read on