界面呈现的状态应与底层状态机严格对应,不能凭视觉猜测当前状态
别名: 界面与状态机 · 视觉猜测 · view is not state · 投影
概念解释
屏幕上能看见的每一块「现在怎样」——按钮文案、转圈、错误红字、禁用——必须是底层那一个节点的投影,而不是一套自己过活的视觉状态。人(和测试、和辅助技术)不能靠「看起来像在加载」来猜机器在哪一格。看起来像,机器却在另一格,下一拍事件会按另一格的边走,画面与因果同时骗人。
对应是双向的:每个合法节点在界面上有可区分的呈现;每一块呈现也能指回唯一节点。多对一(几个节点长得一样)会让人无法评价;一对多(同一节点有时转圈有时不)会让人以为发生了转移。
机制
视觉是快的、本地的、容易被动画和样式分支改写。状态机是慢一拍的、要过事件的。两者若各养一份,视觉会先变:设计师加了一种「加载完成前的微光」,工程师没给它节点,微光就成了无边可走的假态。或者反过来:机器已经到了失败,视觉还停在上一次成功的绿色,因为那次绿色是样式残留。人按绿色决策,事件却按失败的边走。
严格对应的办法是单一来源:界面从节点函数画出来,不从「上一次留下的 class」画出来。测试问的是节点,快照问的是投影是否一对一。辅助技术读到的名称也应是节点名,而不是「按钮1」。视觉猜测之所以诱人,是因为它在验收时用眼睛代替了读状态——眼睛过了,机器没过。
边界
装饰性动画(按钮的按压缩放)不是节点,不必进状态机;它必须叠在节点投影之上,不能单独成为「现在怎样」的证据。多窗口、多对象各有一台机器,对应是每台对它的那一块界面,不是全屏只有一个节点。乐观层是显式的额外节点(「本地已提交、未确认」),不是同一节点的另一种画法;把它画成与「已确认」无法区分,就是对应失败。皮肤、主题、密度改变像素,不应改变可区分性:失败在深色主题里仍必须是失败,而不能看起来像禁用。
怎么落地
- 每个节点写一条呈现规格:可见控件、文案、是否禁用、辅助名称。规格之外的画面视为 bug。
- 界面代码只从当前节点取值,不读「上一次的样式」或平行的
isXxx。 - 验收用读当前节点代替看颜色:自动化里 assert 的是枚举,不是截图像不像转圈。
- 验证:把机器停在失败,问没看过代码的人「现在是什么状态」。若他们说「还在加载」或「好像成功了」,投影没对应。再把节点在五个合法值之间切,每一刀画面应跳到规格里的那一种,且辅助技术报出的名称跟着变。故意留下一次成功的绿色再切到失败:若绿色还在,就是凭视觉残留在猜。