为了彻底解决需求含混性的问题,我们需要一个画面式的场景来全真模拟用户的行为:我们的产品要为哪些人服务?他们的背景如何?他们有哪些亟待满足的需求?他们需要软件产品的什么功能?他们怎么去玩?想达到一个什么样的目的,实现什么样的价值?这些都是我们要为用户想到的。用户故事就是这样一个东西,通过有效、及时的沟通,帮助用户澄清和优化需求。
小白 大鸟,前两章我们讲了测试的本质是验证软件需求,还讲了如何去审核软件需求,保障软件需求的完整性和正确性。到目前为止,我们的需求含混性解决了吗?
大鸟 我只能告诉你:这样还不够!还不足以“设身处地”地替用户去考虑。我们需要一个 画面式的场景 来全真模拟用户的行为:我们的产品要为哪些人服务?他们的背景如何?他们有哪些亟待满足的需求?他们需要软件产品的什么功能?他们怎么去玩?想达到一个什么样的目的?想实现什么样的价值?这些都是我们要为用户想到的。
小白 那我们具体该如何“设身处地”地替用户去考虑呢?
大鸟 通过用户故事。
小白 用户故事是什么?
大鸟 你可以理解为:用户故事是一个备忘录似的交互模型,是从用户角度来描述用户渴望得到的功能。它强调的是通过有效、及时的沟通,帮助用户澄清和优化需求,用户故事有一个通用的模板,如下:
As a role(作为一个角色),I want to do something or a piece of functionality(通过某项功能,执行一些操作),so that achieve some business value or statement of intent.(以便能够实现特定的目标/价值)
在这个模板中,有三个不同的关键点,分别为:
● 用户角色(Who)。
● 某项功能(功能即用户能亲自执行的操作)。
● 实现了某个目标,获得了某种价值(Goal/Value)。
下面是一个例子:
例 作为一个皇马的球迷,通过点击皇马官网的最新新闻栏,便能够实时了解最新的皇马动态。
● “皇马球迷”( 用户角色 )。
● “点击皇马官网的最新新闻栏”( 功能 / 用户操作 )。
● “了解皇马的动态”( 客户目标 / 价值 )。
小白 用户故事主要是为了通过 某个功能 来体现 用户价值 。
大鸟 对产品而言,永远应该把那些最能体现用户价值观的功能置于最高优先级。
我们先看下面两个反例。
例1 如果把“保存”按钮统一放在页面上端而非下面,那么对屏幕上侧的控件做些修改时,就无需滚屏即可保存了。
例2 所有自定义字段,统一改为1000长度。
第一个故事勉强可以写为:
作为一个用户,可以方便地点击上端的“保存”按钮,以便在某些控件修改的时候无需滚屏即可保存。
但是这个故事仅属于易用性优化级别而不是功能级别,颗粒度显得过小。而作为一个用户,这个需求显然和“增删改查”等功能需求,在价值上相差甚远。
第二个故事,找不到“用户”的位置,因为它是我们自己要做的改进,客户完全可以不感知。
所以,上面这两个用户故事都不能很好地体现用户价值。
小白 用户故事由谁来写?是开发人员吗?
大鸟 不对,开发人员容易站在自己的角度去思考和划分故事,这样就背离了用户故事的初衷。一般用户故事是由用户来写的,或者由用户口述,我们的需求人员(有可能就是PM)来整理的。下面,让我们看看“卖香烟”这个例子。
用户故事:卖香烟
1.用户投入一些钱。
2.售货机显示用户已经投了多少钱。
3.如果投入的钱足够买某种香烟,这种香烟对应的按钮的灯就会亮。
4.用户按了某个亮了的按钮。
5.售货机卖出一包香烟给他。
6.售货机找零钱给他。
注意到,一个用户故事里面的事件可以这样描述:
1.用户做AA。
2.系统做BB。
3.用户做CC。
4.系统做DD。
5.……
用户故事只是描述系统的外在行为,以客户能够明白的方式,描述了一个系统的外在行为,它完全忽略了系统的内部动作。如果是下面这样的用户故事:
1.用户投入一些钱。
2.售货机将塞进来的钱存在钱箱里,然后发送一条命令给屏幕,屏幕显示目前已经投入的金额。
3.售货机查询数据库里面所有香烟的价格,判定钱足够买哪些香烟,对于钱足够买的那些香烟,对应的按钮的灯就会亮起来。
4.用户按下一个亮起来的按钮。
5.售货机卖出一包香烟给用户,然后将数据库里面该香烟的存货数量减1。
6.售货机找零钱给用户。
不管是口头描述,还是书面形式,这样的内容是描述用户故事时一个很常见的错误。特别是千万不要提及任何有关数据库、记录、字段之类的、对客户一点意义都没有的东西。
小白 可测试性是指什么?
大鸟 通常,不可测试的故事发生在一些非功能性的需求上。所以,可测试性意味着用户故事尽量采用功能性来做描述。
小白 用户故事是对用户、对需求的描写,可能非常庞杂,甚至含混。
大鸟 的确如此,用户故事是对需求的细化和切分。既然是细化,就得有一个度,需求的颗粒度需要多少才能称之为用户故事?这就牵扯出和用户故事一起出现的另外一个关键的单词叫 Epic(史诗级故事),通俗来说就是大型的故事。Epic 有一些自身的特点:它是由许许多多的、较大的、不确定的需求组成,另外Epic本身不能直接通过其完成迭代(逐层分解)和开发,而是首先需要划分成较小的真正的用户故事。除了这两点,Epic因为包含了太多的模糊性需求,所以常常混杂了很多不同的特性,而一个特性就是一组可以归为一类的需求。Epic分为两类:
(1)复合故事(compound story):由多个小的故事组成。
(2)复杂故事(complex story):本身就很大且不容易分解的故事。
对于太小的故事,不值得去写故事和评估,则可以将其合并到需要半天或几天完成的故事中,比如缺陷报表和用户界面变更。
小白 那该如何细化呢?
大鸟 细化可以分成如下几种。
(1)按用户角色细化。
(2)根据数据边界来细化。
(3)根据用户的操作来细化。
小白 你是说按用户角色来分,而没有说按用户来分。那用户和角色的区别是什么?
大鸟 这里有三个概念,即用户、角色和权限。
在应用系统中,权限的表现是什么?
(1)对功能模块的操作,对上传文件的删改,对菜单的访问,甚至对页面上某个按钮、某个图片的可见性控制,都属于权限的范畴。
(2)此外,有些权限设计,会把功能操作作为一类,而把文件、页面元素、机器列表等作为另一类,这样构成“资源”的模型。
角色是什么?可以理解为一定数量的权限的集合、权限的载体。例如一个论坛系统,“超级管理员”、“版主”、“普通用户”都是角色。版主可管理版内的帖子,可管理版内的用户,可以下载某些资源等,这些都是权限。要给某个用户授予这些权限,不需要直接将权限授予用户,可将“版主”这个角色赋予该用户。
用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般是多对多的关系。而在做数据表建模时,可把功能操作和资源统一管理,也就是将它们都直接与权限表进行关联,这样可能更具便捷性和易扩展性(如下图所示)。
张三、李四、王五都是用户,但是很有可能他们的权限都一样。他们都是一种角色,所以按照用户来划分,会造成用户故事没有区分度。
小白 明白了,张三、李四、王五属于一种角色。
大鸟 他们属于一个“组”,当用户的数量非常大时,要给系统每个用户逐一授权(授角色),是件非常烦琐的事情。这时,就需要给用户分组,每个用户组内有多个用户。除了可给用户授权外,还可以给用户组授权。这样一来,用户拥有的所有权限,就是用户个人拥有的权限与该用户所在的用户组拥有的权限之和。
当故事只为 单一用户角色 编写时,故事的可读性是最强的。比如这句话:“作为一个用户,我可以访问资产负债表数据。”可以做如下分解:
例 作为一个用户,我可以访问资产负债表数据。
——作为 系统管理员(实际上是系统管理员组) ,我可以访问资产负债表数据;
——作为 普通用户(实际上是普通用户组) ,我可以访问资产负债表数据;
——作为 根( root )用户 ,我可以访问资产负债表数据。
小白 什么叫根据用户的操作来细化?
大鸟 一般我们用CRUD(Create/Read/Update/Delete,即增删读改)来细化。可以做如下分解:
案例 作为一个用户,我可以访问资产负债表数据。
——作为一个用户,我可以 增加 资产负债表数据;
——作为一个用户,我可以 删除 资产负债表数据;
——作为一个用户,我可以 修改 资产负债表数据;
——作为一个用户,我可以 阅读 资产负债表数据。
小白 但是真实情况可能不那么简单。除了增、删、读、改等操作外应该还有激活、冻结等。如果要是安装测试的话,应该还有安装、卸载之类的。
大鸟 你说得没错,具体的内容我会在测试的分类里详细介绍。
小白 什么叫做按用户角色合并?
大鸟 对于太小的故事,不值得去写故事和评估,则可以将其合并到需要半天或几天完成的故事中,比如缺陷报表和用户界面变更。