一个人对错误的反应——无论是自己犯的还是他人犯的——是一个复杂且常常令人痛苦的心理过程。在本文中,我将解释为什么几乎所有的错误提示信息的设计都公然无视用户体验理论。我将使用交互式原型来展示如何解决这个问题。我还将转向交互理论,回顾模式的概念,并解释可逆性、恰当性和及时性的原则。
每个设计师的清单里都会包含“设计错误界面”。但即使完成了,程序员仍然会回来说:“还有另一种情况——我们也需要一个错误界面。”在这种情况下,程序员是设计的客户,这很有道理:程序员比任何人都更了解错误。设计师和经理们都认同这种方法——但它存在严重缺陷。
“我们不是我们的用户。”设计师们不断重复这句话。他们想表达的是:不要仅仅依赖自己的专业知识(这不可避免地会过时,而且容易产生职业偏见),而要关注用户在自然环境中的行为。
所以,问题在于——程序员不是我们的用户。程序员的行为、思维方式,以及与计算机的联系与其他人截然不同。我知道我在说什么。我的大多数朋友都是程序员和工程师。我在工作中也经常和程序员交流。我自己也是一名程序员,使用多种语言(从 Swift 和 GLSL 到 Forth 和 Assembly)。但幸运的是,我也是一名非常关注心理学的设计师。那么,让我来告诉你程序员的一天通常是怎样度过的:
程序员甚至还没来得及好好写点东西——他们停顿了一下,砰,一个错误出现了:“空白符缺失”。不知何故,下一行也出现了错误(尽管那一行完全没问题)。左侧面板也满是错误。这还不算编译错误。除了红色圆圈,可能还有黄色圆圈——程序员的大脑已经习惯了忽略这些警告。
如果错误来自硬件故障、第三方库的 bug 或文档不清晰,程序员不会把这些错误当回事。他们会把这些错误视为一种有用的工具,帮助找出别人的错误。而有些烦人的拼写错误,你会在自己的代码中苦苦追寻,希望编译器能自动捕获它们。那么,关于拼写错误的错误消息就是程序员最好的朋友。
简而言之,程序员对错误消息产生了一种容忍度——所有那些带有感叹号的圆圈和冗长、说教的红色文字。
从人体工程学的角度来看,程序员的环境与普通用户的环境有着根本的不同。因此,设计师绝对不应该采用程序员对待错误的态度。如果我们负责设计一个 IDE(集成开发环境),那么我们当然会咨询程序员——他们是我们的用户。但在开发其他产品时,最好不要依赖他们的观点。相反,我们应该咨询心理学家。
红色感叹号会让用户想起老师在课堂笔记中批改的内容,并被理解为一种惩罚(当然,除非有人已经培养了对惩罚的耐受力,比如程序员)。那么,心理学是如何看待对错误的惩罚的呢?
重要的是不要用消极情绪来强化错误,因为大脑对此非常敏感,并会将这种行为标记为不值得投入精力的事情。
我知道有些人看到错误信息就会慌乱不已。他们开始点击所有按钮,只为让它尽快消失。这些人很难适应界面,因此他们倾向于完全避免与界面交互。这并不是因为他们愚蠢,而是因为他们是普通人——而不是程序员。
看看这个!几乎每个字段都用红墨水划了线,界面提示你输入姓名,并要求你填写,而且是必填项!
但程序员对此完全没意见。程序员坚信,把笨蛋塞进错误里是有用的,这样他们就不会再试图用 null 或 undefined 来破坏程序了。程序员和工程师称之为“傻瓜式防错”,展现了他们独特的同理心。
当用户从一个输入字段切换到另一个输入字段时,第一个字段会触发一个名字很不靠谱的事件:“onblur”。开发者经常用它来进行验证——以防用户漏填字段、输错生日或忘记邮件中的“@”。问题是:当用户切换到另一个应用时,“onblur”也会触发。过去,表单跨越三页时,空字段是个问题。如今,所有内容都能放在一个屏幕上——很难忽略一个空字段。至于其他的检查——它们对用户没有任何帮助。它们只是另一种“傻瓜式”的玩意儿。但用户不是傻瓜。当他们想要什么东西时——他们会发挥创造力。我知道有人会修改页面代码,以获取他们严格意义上不应该获得的政府服务。而如今,他们甚至不需要知道如何编写代码:只需单击一下即可打开 DevTools,再单击几下——所有验证都消失了。输入任何你想要的内容。
通过像傻瓜一样对待用户,开发人员产生了两个问题:第一 - 他们浪费时间构建“保护”,第二 - 他们陷入了一种虚假的安全感(没有比“通过模糊性实现安全”更糟糕的保护)。
在焦点切换时进行验证毫无意义,而且问题重重,我甚至不想在这里讨论它。让我们继续讨论主按钮上的验证:“继续”、“提交”等等。
我们与雅虎界面的交互分为三个阶段:
让我们来分析一下。
激活按钮——这很好,雅虎点赞了。我有一篇名为“禁用按钮”的文章,解释了这背后的理论和实践。如果你仍然认为禁用按钮对用户有帮助,那你绝对应该读一读。
接下来是可逆性原则。这意味着你可以将界面恢复到初始状态。雅虎又赢了——你可以重置界面。但只能通过逐个点击每个字段来实现。这有什么意义呢?为什么仅仅因为你移开焦点,错误信息就会消失?这纯粹是算法故障!在我关于设计流程的文章中,我指出即使是顶级公司有时也会设计出糟糕的界面,所以不要盲目追随权威。要遵循科学。
下一个原则是恰当性。用户点击了“继续”按钮——交互的对象是按钮,而不是输入字段。如果按钮发出某种震动或吱吱声来表达不满,这可以理解。但是输入字段呢?根本没人碰过它们!它们怎么可能感知到按钮的情绪呢?只有程序员知道,在代码中,这些对象是相互关联的——但外部观察者一无所知,因为它们之间没有视觉联系。
现在来谈谈时效性原则。设计师用红色高亮显示几个字段,期望用户做出什么反应?如果所有字段的重要性都一样,用户应该先解决哪个字段?这需要对注意力中心进行复杂的讨论(这里的注意力中心不是指某个具体的输入字段,而是“出了点问题”的整体感觉),但我建议保持简单:界面基本上就是按照“坐下-停留-过来”的顺序排列,打破了“一次一个动作”的原则。
这里,一切都非常不对劲!
界面有“模式”的概念。在我的大学里,程序员选修了一门名为“界面设计”的课程,课程内容包括解释为什么弹出窗口被称为“模态窗口”。现在,我惊讶地发现,程序员和设计师似乎对如何处理模式一无所知。
老式计算机有一种特殊的“HALT”模式,用于调试错误,也称为“控制台模式”。如果处理器尝试执行无效操作,程序将被中断,处理器将停止运行,并切换到控制台模式。您也可以通过按下物理“HALT”按钮手动触发 HALT 中断。使用开关或调试程序(在单独的控制台上运行),您可以修复错误并返回程序执行模式。
“处理器”一词并非偶然——它源于“进程”。错误中断只能在进程运行期间发生,而不会在处理器停止并处于调试模式时发生。这一事实在我们稍后讨论进程和状态之间的区别时会很有用。
向用户清晰解释他们最终进入不同模式的原因和方式至关重要。例如,调试器会显示导致无效操作的指令地址。同样重要的是解释如何返回(记住可逆性原则)。经典的 Norton Commander 完美地诠释了各种模式:
我见过有人批评这类解决方案:“窗口叠在其他窗口上看起来很丑”。即便接受了这种说法,我仍然无法认同设计师通常提出的替代方案:“我们把这个窗口移除,把错误显示到别的地方,这样更美观。” 就好像设计师忘记了自己是工程师,只是拿起画笔,像个泥水匠一样把瑕疵掩盖起来。
如果你真的想摆脱窗口,正确的方法是记住什么是模式、它们来自哪里以及它们是如何工作的——然后弄清楚如何避免切换到其他模式(如果你想深入了解模式,请阅读 Jef Raskin 的《人性化界面》)。例如:软盘空间不足?不允许复制文件。软盘未插入?不要将其显示在目标列表中。现代操作系统就是这样做的——它们消除了执行可能导致错误中断的操作的可能性。
现在我们可以猜一下雅虎上的“继续”按钮的作用了:它启动了一个错误调试模式。在该模式下,用户被赋予了程序员的角色,并被迫修复所有导致程序崩溃的空值和未定义值。不幸的是,开发人员并没有意识到这对普通用户来说有多么糟糕。我希望他们至少明白,他们剥夺了用户返回上一个模式的能力——这违反了良好用户体验的最基本规则。
乍一看,似乎所有网站的错误显示都和雅虎一模一样。所以这肯定是“最佳实践”,是行业标准……但事实并非如此!每个人的做法都不一样。我们来看看亚马逊:
让我们来分析一下。
一个活动按钮——很好。亚马逊正在跟上雅虎的步伐。
自动聚焦到第一个字段——太棒了(雅虎没有这个功能):用户可以立即开始输入。填完第一个字段后,按“继续”键会直接将光标移动到第二个字段,也就是错误所在的地方。真是聪明的举动!
有人会反对:自动对焦在桌面端运行良好,但在移动设备上键盘会遮挡半个屏幕,所以最好隐藏它,直到用户点击输入。这样一来,你解决了一个问题,又制造了另一个问题。然后你选择你的毒药……问题是,你会认为一种弊端较小,而有些用户会认为另一种弊端更严重。无论哪种情况,你都在选择一种弊端。不要这样做(我稍后会解释如何做)。
界面可逆性。你输入一些内容,错误消失;然后你删除它并切换到另一个字段——哇,一个没有错误的空字段。所有字段都一样。将界面恢复到初始状态比雅虎要难,但由于算法不稳定,仍然是可能的。
与雅虎的同事一样,亚马逊的程序员在“继续”按钮和输入字段之间建立了心灵感应:按钮不想继续,但输入字段都大声喊出来(突然变成输出字段)。
特别要提一下密码确认框——为什么它不变成红色?不填就无法继续。想说要等到前一个框填完后才进行校验?当然,你得给用户解释一下错误校验算法,再给他们看源代码——这真的会很有帮助(讽刺)。
现在,我们来快速看一下IBM的解决方案:
激活按钮——不错。没有自动对焦,但至少界面会自动滚动到第一个字段并显示错误。
界面不可逆——无法将字段恢复到第一个屏幕上的样子。换句话说,你无法退出调试模式。那么,为什么还要有第一个屏幕(调试模式)呢?如果你认为空字段是错误,那就直接显示第二个屏幕吧。哦,你不想立刻吓到用户?还记得感知心理学吗?你决定稍后再吓唬他们,作为对他们错误的惩罚?让我再重复一遍心理学家的话:
重要的是不要用消极情绪来强化错误,因为大脑对此非常敏感,并会将这种行为记录为不值得花费精力的事情。
例子不胜枚举。以网站 capital.xyz 为例:
日期字段为空,点击“下一步”按钮,字段自动对焦。手机字段为空,点击“下一步”——完全没有自动对焦。为什么?这背后的想法是什么?剧透:根本没这回事。只是算法出了问题。
谷歌甚至更进一步——你输入的每一个字符它都会责骂你……
即使你不同意我的批评,你也必须承认,知名公司的顶级设计师和程序员在实现同一项任务时,都采用了截然不同的方式。这意味着完美的解决方案尚未找到。很可能,根本没人真正去寻找它。程序员只是在缺乏对用户交互原则清晰理解的情况下编写代码,然后跑来找设计师说:“嘿,这里又有一个错误需要显示出来。”
当我为自己的项目设计错误显示时,我没有依赖别人的解决方案——我依靠科学。我在撰写本文时收集了来自雅虎、亚马逊和 IBM 的示例。在对所设计机制背后的原理没有深入理解之前,研究参考文献是有害的。你只会捡起别人的错误,然后引用权威文献来为自己辩护。几乎每个人都这样做。没有人愿意重新发明轮子——工业程序员没有时间或动力去做这件事。所以每个人都坚持使用老式的命令行、字母数字显示方法。还记得当时错误是如何显示的吗?如果没有,来看看控制台:
如今,界面开发人员仍在做着同样的事情:直接把错误日志直接倒在屏幕上。21世纪唯一的升级?把文本涂成红色,然后把信息分散到屏幕的不同位置。
这可不行。我们赶紧解决吧!
我们用“错误”这个词来描述两种截然不同的事物:事件和状态。快速回顾一下:当处理器尝试执行无效操作时,它会触发中断并进入调试模式。这是一次性事件。我们说“发生了错误”。然后,我们去寻找导致崩溃的内存中的特定值。该值——或者更准确地说,存储单元的状态——也称为“错误”。换句话说,我们模糊了因果之间的界限——仅仅是因为我们没有想出单独的词。为了避免混淆,我将使用两个术语:进程错误(事件,某个时间点)和数据错误(内存中的错误值,一种状态)。
我们来看一个邮箱输入框。缺少“@”符号?这是数据错误。被邮件服务器退回邮件?这是流程错误。或者以邮政编码为例。位数太少?这是数据错误。数据库中找不到邮政编码?这是流程错误。
输入字段只是一个数据容器。数据可能会缺失。如果你没有输入生日,并不意味着你出生在零日。这个输入字段根本没有数字,只有占位符“日”。数据缺失了。
因此,空白字段并非数据错误。不存在的东西本身就不是什么错误。空白字段是创建数据的机会,是一个良好的起点,也是一个互动的邀请。你可能已经注意到,空白表单看起来比已填充的表单更优雅。那么,为什么要用有毒的红色来破坏它呢?谁会喜欢与标记为危险的字段互动呢?
不要这么做。我准备了一个交互式原型来向你展示应该怎么做。
让我们看看电水壶中按钮和水的状态是如何变化的。打开电水壶。水沸腾后,按钮会弹开。但触发按钮的不是水,而是温度传感器。如果传感器损坏或丢失,按钮就不会弹开。
现在手动按下按钮——水不会突然变冷。了解导致状态变化的具体原因很重要。
规则如下:如果对对象 A 执行了某个操作,那么只有 A 的状态可以改变,而对象 B 的状态则不能改变。要更改 B 的状态,需要一个直接作用于 B 的独立进程。
例如,数据库搜索可能会触发索引重建——这会更改数据库本身,但不会改变您搜索的值。
让我们来看一个常见的 UI 设计错误。用户想通过邮政编码查找城市。他们输入邮政编码,点击“搜索”,然后……输入框变红,或者值消失了。发生了什么?这是一个流程错误——数据库中没有结果。但 UI 却将其显示为数据错误,就好像用户输入了错误的邮政编码一样。但也许邮政编码是有效的——只是城市还没有添加到数据库中。也许五分钟后就会添加。用户并没有输入错误数据。输入框不应该受到指责。我们无权触碰它。流程错误需要以不同的方式显示(稍后会详细介绍)。
根据希克-海曼定律,提供的选项越少,用户选择所需内容的速度就越快。将这一原理推向极致,便可得出“一屏一操作”原则。有人可能会说,复杂的程序不可能简化到这种程度,但让我们回想一下 Hanx Writer 文本编辑器——苹果设计奖得主——它几乎精简了所有内容。或者想想在 Photoshop 中按下一个按钮就可以隐藏整个界面,只留下一个工具可见。在某些情况下,“一屏一操作”原则非常有效。至少,在放弃它之前,先尝试一下。
在优化了开立经纪账户的网页工作流程后,我决定在移动应用中测试这种方法。看看我的交互式原型吧——它通过了 17 位用户的快速测试,与旧版本(每个屏幕有多个输入字段)相比,速度提升了 13%。
有人可能会说,时间的提升并不大——少了52秒,而不是整整一分钟。但首先,试着数到8——这实际上是一段相当长的时间内,任何事情都可能发生。其次,测试表明时间减少了,而不是像一些人担心的那样增加了。他们假设额外的屏幕转换会减慢用户的速度,但结果却恰恰相反:信息越少,用户处理速度就越快。当只有一个操作可选时,用户会毫不犹豫地执行。
原型就是这样。屏幕上只有一个输入字段。用户输入数据,按下“继续”,屏幕就会滚动到下一步。如果你手动尝试在空白字段处向前滚动,屏幕会迅速弹回:“不行,不行”。输入字段保持焦点,提示用户输入数据。无需任何额外的高亮——毕竟,它是屏幕上唯一的字段。完美。
如果你点击“继续”,但输入框为空或邮箱地址缺少“@”符号,键盘会弹回来,仿佛在说:“想继续吗?那就继续填写吧。” 没有任何错误信息!
我再强调一遍:我们不会隐藏错误信息。相反,我们设计的系统绝对不会出错。没有数据就意味着没有数据错误。没有流程就意味着没有中断或调试模式。这里唯一的期望是数据以正确的格式输入。顺便说一句,这里有一个很棒的方法——接受任何合理格式的数据。例如,Sberbank.ru 允许您输入带有国家代码 (+7)、本地前缀 (8) 或完全不带区号的电话号码。
从本文俄语版的评论来看,并非所有人都理解原型的用途。有些人期望看到一个完美无瑕、随时可用的产品(一个他们可以直接复制的产品),结果却大失所望,对诸如缺少重新发送短信验证码的选项之类的问题吹毛求疵。让我再次澄清:本文中的原型并非成品的精确复制品。它们的唯一目的是展示如何消除错误信息。
现在,让我们将此解决方案扩展到界面无法简化为“一屏一操作”模式的情况。 “Ingos Investments”的原型反映了数据量巨大,以至于每个屏幕上必须显示多个字段的情况。
让我们设想一个场景:用户尚未填写所有字段,点击了“继续”按钮。界面立即聚焦于第一个空白字段,调出屏幕键盘,并滚动到该字段正上方,方便用户查看正在输入的内容。即使屏幕上有多个字段,我们仍然坚持“一次一个操作”的原则,巧妙地将其他字段隐藏在键盘下方。在活动字段下方,会出现一条提示:“所有字段必须填写”。这不是错误消息,而是一个有用的提示,没有任何令人担忧的危险信号。
当用户点击屏幕键盘上的“下一步”时,他们只会跳转到下一个字段——这和填写表单的常规流程一样,而不是笨重的错误调试模式。提示已经给出,所以用户不太可能再次尝试填写空白字段。但如果他们真的这么做了,那么他们会再次看到这个温馨提示。
怀疑论者可能会说:“但如果空白字段位于屏幕最顶部,无法滚动到键盘上方怎么办?或者,如果网站是在桌面上打开的,根本没有屏幕键盘怎么办?” 答案是:没什么大不了的。所有这些极端情况都在原型中得到了完美的体现。我也听到过这样的担忧:“如果我们不把每个字段都涂成红色,用户就不会意识到需要填写”。测试表明,这些担忧是毫无根据的。这些担忧背后真正的恐惧,是害怕打破常规,尝试一些真正新颖的东西——一些对用户更有利,而不仅仅是对我们自己更有利的东西。
为了创建“Ingos Investments”的原型,我编写了一个状态管理调度器。交互元素将其内容报告给管理器,然后管理器决定如何处理它们。
程序员常说输入字段是独立的元素。邮箱字段不知道电话字段里的内容。当你切换输入字段时,它会触发对其内容的验证。当你点击“继续”按钮时,所有输入字段都会收到一个命令——检查你的数据。这就是为什么它们会突然一起亮起红灯。这就是它的构造方式。程序员说你无法改变它。设计师也相信这一点。不过亚马逊的例子表明,密码确认字段确实知道前一个字段的内容。所以他们可以随时修改。
这意味着你可以而且应该创建一个状态管理器。当用户尝试跳转到下一个屏幕时,状态管理器会检查所有字段,找到第一个包含不完整或无效数据的字段,将用户带回该输入框并显示提示。本质上,这是一次时光之旅——回到用户出错的点。因此,将后续字段标记为错误是没有意义的——它们发生在将来,而用户尚未到达它们。
使用状态管理器,您还可以在鼠标悬停在“继续”按钮上时检查字段内容。如果数据缺失,按钮的标签会更改为特定的字段名称,例如“输入街道”——这遵循了时效性原则(用户尝试继续,但需要填写字段,我们会通知他们)。这个新标签在按钮和字段之间建立了视觉联系,使程序员有理由将这两个元素的行为联系在一起。
程序员可能会问:“为什么要把事情复杂化?” 没错——对程序员来说越复杂,对用户来说就越容易。这是规则。说实话,这只需要一两天的时间。需要更多精力的是通知系统。数据错误和流程错误应该显示在各自的层级结构中:数据错误应该显示在数据容器中,而流程错误应该显示在应用程序范围的通知中。这是一个完全独立的主题,我希望有时间写一篇关于通知设计的文章。
因此,我们发现了以下事实: