开发者也是用户 — 第一部分:构建更具可用性的 UI 与 API 的 5 个方针

在前一篇文章中,咱们探讨了 UI 可用性与 API 可用性的重要性,并说明了 UI 可用性原则能够应用于 API。下面是前文连接:html

开发者也是用户 - 简介 可用性 - 学于 UI,用于 API前端

在本文中,咱们将具体讨论前 5 条可用性方针:android

  1. 系统状态的可见性
  2. 让系统符合真实世界
  3. 为用户提供自由的操做方式
  4. 一致性与标准
  5. 预防错误的发生

1. 系统状态的可见性

系统应当在合理的时间,经过合适的反馈,让用户了解它正在作什么。ios

**UI:**当用户进行一项须要耗费较长时间的操做时,应告知用户操做的进度。例如,在加载图片时显示一个进度条,在上传下载文件时显示百分比。应当让用户知道正在让他们等待的是什么,须要花多长时间。git

上图:告知用户当前状态。图片来源github

**API:**API 应当提供某种能够查询当前状态的方式。例如,AnimatedVectorDrawable 类提供了一个方法来检查动画是否正在运行:数据库

boolean isAnimationRunning = avd.isRunning();
复制代码

API 能够采用回调机制来给出反馈,让 API 用户知道对象在什么时候改变了状态 —— 相似于动画开始与结束时的通知。例如,AnimatedVectorDrawable 对象能够 registering 一个 AnimationCallback 来完成上述操做。后端

2. 让系统符合真实世界

应用程序应当“说”用户的语言,使用用户熟悉的短语和概念,而不该该使用面向系统的术语。bash

上图:使用用户熟悉的概念。图片来源app

类与方法的命名应符合用户的预期

**API:**当在一个新的 API 中查找类时,用户可能无从下手,于是依赖以前使用相似 API 的经验,或者依赖在 API 领域通用的观念。例如,当使用 Glide 或者 Picasso 下载并展现图片时,用户极可能会去查找名为“load”或“download”的方法。

3. 为用户提供自由的操做方式

为用户提供撤销操做的机会。

**UI:**某些用户发起的操做可能含有歧义,例如“删除”或“存档”邮件。此时应显示一条消息让用户确认,并容许用户撤销此操做。

上图:容许用户撤销当前操做。图片来源

API 应容许中断或重置操做,并能简单地将 API 恢复到正常状态

**API:**例如,Retrofit 提供了一个 Call#cancel 的方法,此方法会尝试取消飞行模式下的 call 调用,以及取消还未被 execute 执行的 call 调用,让其以后也再也不会执行。此外,若是你在使用 NotificationManager,你会发现既能够建立通知也能够取消(cancel)通知。

4. 一致性与标准

你的应用程序的用户不该该去思考不一样的文本、情景或者操做是否有着一样的意义。

**UI:**与你的 app 进行交互的用户在此以前已经经过与其它 app 交互获得了训练,他们会但愿各个应用的可交互元素的样式与行为都相同。若是偏离了这些惯例,那么用户就会更容易出错。

所以,UI 须要与平台保持一致,并使用用户熟悉的 UI 控件,以方便用户快速识别并使用它们。此外,一致性应当贯穿你的整个应用。在 app 的不一样界面中,使用相同的文字与图表来表示相同的东西。例如,在你的 app 中用户能够修改多个元素,那么请使用相同的修改图标。

上图:对话框应该与平台保持一致。图片来源

**API:**全部的 API 设计都应遵循一致性原则。

各个方法应保持命名的一致性

请参考下面的例子。假设咱们有一个 interface 暴露了两个设置不一样类型 observer 的方法:

public interface MyInterface {
    
    void registerContentObserver(ContentObserver observer);
    void addDataSetObserver(DataSetObserver observer);
}
复制代码

使用它的用户可能会思考:register…Observeradd…Observer 究竟有什么区别呢?是否一个方法一次接受一个 observer,另外一个方法一次能够接受多个 observer 呢?开发者要么去认真阅读文档,要么去查找 interface 的实现,来研究两个方法的行为是否相同。

private List<ContentObserver> contentObservers;
private List<DataSetObserver> dataSetObservers;
public void registerContentObserver(ContentObserver observer) {
    contentObservers.add(observer);
}
public void addDataSetObserver(DataSetObserver observer){
    dataSetObservers.add(observer);
}
复制代码

所以,请为作一样事情的方法进行 相同的命名

能够在命名时考虑使用反义词,例如:get - set,add - remove,subscribe - unsubscribe,show - dismiss。

各个方法应保持参数顺序的一致性

在重载方法时,须要确保在新旧方法中都存在的参数的顺序保持一致。不然,你的 API 用户将要花更多的时间来理解重载与被重载方法的区别。

void setNotificationUri( ContentResolver cr,
                         Uri notifyUri);
void setNotificationUri( Uri notifyUri,
                         ContentResolver cr,
                         int userHandle);
复制代码

避免在函数中使用连续的、同类型的参数

虽然在 Android Studio 中,使用连续的多个相同类型的参数是件简单的事情,可是这样作很容易致使参数顺序出错,而且很难找到这种错误。参数的顺序应当尽量与参数的逻辑顺序一致。

当这些参数的类型都相同时,用户很容易犯错。例如上图中 county 和 country 就弄反了。

为了解决这种问题,你可使用建造者模式,或者应用 Kotlin 的 命名参数(named parameters)

方法的参数应不大于 4 个

参数越多,意味着方法越复杂。用户须要理解每一个参数在方法中起到的做用以及与其它参数的关系,也就是说每增长一个参数都会致使方法的复杂度呈指数形式增长。当一个方法的参数超过 4 个时,就能够考虑将其中一些参数封装在其它类中或使用构造器了。

返回值会影响方法的复杂度

当一个方法返回某个值时,开发者须要知道这个值表明着什么,如何存储它等。若是不须要用到这个值,那么它也不该当对方法的复杂度形成影响。

例如,当向数据库插入一个元素时,Room 既能够返回 Long 也能够返回 void。如用户须要使用返回值时,首先须要了解此返回值的意义,以及如何存储它。而在不须要返回值时,用户可使用 void 类型方法。

@Insert
Long insertData(Data data);
@Insert
void insertData(Data data);
复制代码

所以,你应当容许 API 用户本身决定是否须要返回值。若是你正在开发一个基于代码生成器的库,应该容许其生成返回多种可选类型的方法。

5. 预防错误的发生

建立防范于未然的设计。

**UI:**用户常常会一心多用,所以你应当防止用户在无心识下形成的错误,减小用户“翻车”的机会。比方说你能够在毁灭性操做前弹框要求确认,或者提供正确的缺省值。

好比,Google Photos 应用会弹出一个确认框来确保你删除相册不是误操做;而 Inbox 的“邮件稍后提醒”功能仅需一键操做。

上图:Google Photo 在毁灭性操做前弹出确认框;Inbox 在暂停收件操做时提供方便选择的缺省值。

API 应该引导用户正确地使用 API。尽量使用缺省值。

API 应当易于使用,且能防止误用。经过提供缺省值能够帮助用户正确使用 API。例如,当建立 Room 数据库时,有一个缺省值能够确保在升级数据库版本时数据不丢失。因为数据库版本对用户来讲是透明的,又由于升级时数据会保持,因此使用 Room 的应用程序对用户来讲易用性更好。

与此同时,Room 也提供了一个方法 fallbackToDestructiveMigration 用于改变这种行为,若是没有提供迁移方法,那么在数据库版本改变时会销毁并从新建立数据库。


深刻了解另外 5 条原则请访问: 让用户认知,而不是回忆 弹性、高效的使用方式 优雅、极简的设计 帮助用户认识、判断、改正错误 提供帮助与文档


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索