或许是从“网站/网页”时代一路走来,我们仍然喜欢叫一个界面是“页面”。那时候的信息传递基本上是单项的,一个网站就好想是一本书,所以”网页“这个词也是一种文档或书籍的隐喻。我们设计导航就像是在设计书籍的目录,设计内容就好像是在排版。

然而时至今日,我们的设计对象大多已经不能和书籍联系起来。我们在设计应用。而无论网站也好,APP 也好,很多同学却仍然在使用页面的思路。大体是全局导航是什么,是个 tab 还是个 drawer, 还是网页上的一个横向菜单栏?然后每一个选项对应哪个页面,这个页面上的触发器(按钮、链接等等)又会产生什么页面。一路形成一个页面树。最后把它们之间的跳转关系用连线表达出来。

这样的做法,首先兜了一个圈子。因为需求方在告诉我们要实现什么功能。而我们要先把这些功能转换成页面树。

另一个问题是,常常忽略一些页面的状态。譬如一个页面上有个“请登录”按钮,我们以页面的思路,那么这个按钮,点了就会去登录页。登录页上自然有表单,填写用户名和密码,还有个“登录”按钮,点了之后,就提交表单,然后大抵是转到主页,或者来源页面。等等,登录页面没有填写用户名怎么办?没有填写密码怎么办?用户名错了怎么办?密码错了怎么办?如果用这套思路,只能靠经验来处理。或者说面对表单,一般而言有表单检查,面对网页按钮,一般有 lvha 四种状态,用这样的模式来固定我们的设计流程。

更重要的问题来了:这样的思路,完全和“应用”不匹配。

当我们面对一本书,我们寻找要看什么,而面对一个应用的时候,我们思考该怎么完成要做的事情。

所以,我们不妨试试用例的思路。软件工程里的用例定义晦涩而复杂。我们先来给我们的“用例”下个简单的定义:我们的应用可以让用户做的一件事情。 当然,这件事用户可以选择做,比如一个 IM 的删除好友,用户需要删除就删除,不需要就不删除。也有一些事用户一定要做,比如我们一定要用户登录了才能使用我们的应用,那登录这件事,用户就一定要做。

每件事都是确定的,那么就一定可以画出流程图。对于一个流程,就有触发器,有反馈,还有规则。如果这件事的流程图过于复杂,且内容相对可以独立分开,我们就可以拆成一些小事,每件事是一个子用例。每个子用例也都有触发器、反馈和规则。

那么当需求方给我们功能时,我们就可以根据功能,较为直观的想到,我们的应用应该可以让用户做哪些事,即有哪些用例。还有用户的典型行为,比如他们通常先做什么,后做什么,以及一些奇葩用户,他们先做什么,后做什么。

根据用户的行为,我们就可以把各种显式的触发器组织成我们导航系统。从而拥有一个应用的骨架。

然后我们设计每个用例的流程。还拿登录来说。假设一个不登录也可以使用部分功能,而登录了才能使用全部功能的应用:

登录可能有三个触发器:一个是“进入应用”这一事件,我们尽量引导用户还是登录了再用吧;二是“点击登录按钮”事件,视登录的重要性不同,按钮可能在一个叫做“个人中心”的界面里,也可能在首页上方等等位置,总之有一个或多个位于不同区域的登录按钮,点击它们都会触发这一事件;三是“用户尝试开始需要登录的用例”这一事件。一和三都是隐式的,没有明显的界面元素。二是显式的,我们需要视情况把他们安置在某些界面中。嗯,这时候我们需要考虑的__第一个界面__,把他们放在哪里呢?

这些事件的其中一个被触发了,就该登录了。我们需要用户名和密码。所以我们需要一个表单来完成这件事。它可能是一个全屏的界面,也可能是一个弹出层,用户可以关闭这个界面。表单有一个用户名输入框,有一个密码输入框,还有一个提交表单的按钮。这是我们需要考虑的__第二个界面__。

任何需要用户做的事,实际上用户都有可能不做。

任何你期望用户按顺序做的事,用户都有可能不按这个顺序做。

基于上面这两个客观事实。我们来看看“我们需要用户名和密码”这件事。实际上,我们期望用户:第一步、不限顺序的输入用户名或者密码;第二步、点击提交表单的按钮。所以:

  1. 用户可能什么都不做。嗯,虽然这种一直盯着登录表单就这么盯下去的可能性在现实生活中不太大。显然,这种情况下,我们的登录流程也不能做什么。或许可以引导注册或者其他帮助什么的,我们暂且不考虑这么多。
  2. 用户可能退出了应用。我们的登录打消了他继续使用的想法。我们的登录流程这时候也不能继续做什么。我们的交互设计师可能需要反思登录的方法,我们的产品经理需要重新思考到底什么功能才需要登录。但这不属于本次的登录设计。
  3. 用户可能关闭了这个界面。我们需要针对触发器做出不同的行为:转到首页 / 返回登录按钮所在的界面 / 转到需要登录才能进行的用例的入口处。一个未登录的首页是我们需要考虑的__第三个界面__。需要登录才能进行的用例入口可能有界面,可能没有。视情况而定。由于我们在设计登录流程的时候,通常还没有设计那个用例,尚且无法确定是不是有个入口界面,所以我们建议在设计那个用例的时候,如果有入口界面,考虑是否区分登录和未登录状态。在这里,就不考虑了。
  4. 用户可能不填用户名,点击了提交表单。嗯,我们需要提示他,必须要填用户名和密码才能继续下去。这是__第二个界面的状态1,也是第一种反馈__。
  5. 用户不点提交表单按钮。嗯,我们的登录流程这时候也没办法继续做什么了。如果真的有很多用户这么干,我们需要考虑是不是提交表单的按钮做的有问题,但是这也不属于本次登录设计了。
  6. 用户先点表单提交按钮。这种情况 = 没填用户名和密码,即情况4。
  7. 一切如我们所愿。用户输入了用户名和密码,然后点击了提交表单。

如果像情况7那样进行了。我们的应用就该提交表单了。

任何网络数据请求,都有可能不成功。

所以提交表单有两种结果:

  1. 失败。我们根本没有把数据提交到服务器,或者服务器没有响应。这时候,我们需要提示用户网络出了问题,以及是否有建议的解决方案等,就不细说了。不过这是我们__第二个界面的状态2,也是第二种反馈__。
  2. 成功。我们成功提交了数据,并且得到了响应。

成功之后,就该考虑服务器响应的结果了,服务器的结果根据登录api的设计,可能不完全相同。我们讨论一个典型的。

任何程序都有可能出错。

  1. 服务器出错了。服务器因为种种原因没法验证用户名和密码。不过他还能响应,所以给了我们一个错误码以及错误消息。这时候根据具体情况,我们需要提示用户些什么东西,等等,具体情况具体分析。这是我们__第二个界面的状态3,也是第三种反馈__。
  2. 服务器检查用户名,发现用户名不存在。我们可能需要提示用户他是不是输入了错误的用户名。如果连续多次都不存在,我们可能还要分析是不是有程序在暴力破解我们,可能需要出动验证码了。这是我们__第二个界面的状态4,也是第四种反馈__。
  3. 服务器检查用户名,存在,但是密码不匹配。我们需要提示用户是不是输入了错误的密码。如果多次错误,同上,需要考虑是不是暴力破解。这是我们__第二个界面的状态5,第五种反馈__。
  4. 成功验证通过。

最后根据不同的触发器,做出不同的响应,转到首页、返回登录按钮所在页,或者开始进行那个需要登录才能进行的用例。这是我们的__第六种__反馈。这里一个__登录后的首页__是我们的__第四个界面__。登录按钮所在页可能会发生变化,假设那个登录按钮在手机app的“个人中心”里,那登录后的个人中心大概就没有登录按钮了,会显示些个人信息什么的。这是视情况可能有的__第五个界面__。

在这个例子里,我们在设计用例流程的过程中设计了界面,以及考虑到了各种界面的状态。相对于从页面层次的角度来做设计,是不是要完善和严密的多呢。