大量预先的需求收集和文档会以很多方式导致项目失败。原因如下:
- 最常见的是需求文档变成了软件的开发目的。
- 记录语言的不准确性,事实上很难用语言把复杂的东西描述清楚。
用户故事的起源
用户故事的起源是来自与XP极限编程的计划游戏环节,据现在能够追查的记录,最早是这样提到“用户故事”的,在1998年,客户通过用户故事(像用例)来定义项目范围。 XP没有把用户故事作为一个单独的实践来说明,而是作为计划游戏中的一个游戏环节。
什么是用户故事
用户故事描述了对用户、系统或者软件购买者有价值的功能。用户故事由以下三方面组成。
- 一份书面的故事描述,用来做计划和作为提示。
- 有关故事的对话,用来具体化故事的细节。
- 验收测试,用于表达和编档故事细节且可以用于验收故事是否完成。
一个好的用户故事包括三个要素:
- 角色:谁要使用这个功能。
- 活动:需要完成什么样的功能。
- 商业价值:为什么需要这个功能,这个功能带来什么样的价值。
格式如下:
作为一个<角色>, 我想要<活动>, 以便于<商业价值>
例如:
作为一个“网站管理员”,我想要“统计每天有多少人访问了我的网站”,以便于“我的赞助商了解我的网站会给他们带来什么收益。”
用户故事的六个特性 - INVEST
INVEST = Independent, Negotiable, Valuable, Estimable, Small, Testable
一个好的用户故事应该遵循INVEST原则。
- 独立性(Independent) — 要尽可能的让一个用户故事独立于其他的用户故事。用户故事之间的依赖使得制定计划,确定优先级,工作量估算都变得很困难。通常我们可以通过组合用户故事和分解用户故事来减少依赖性。
- 可协商性(Negotiable) — 一个用户故事的内容要是可以协商的,用户故事不是合同。一个用户故事卡片上只是对用户故事的一个简短的描述,不包括太多的细节。具体的细节在沟通阶段产出。一个用户故事卡带有了太多的细节,实际上限制了和用户的沟通。
- 有价值(Valuable) — 每个故事必须对客户具有价值(无论是用户还是购买方)。一个让用户故事有价值的好方法是让客户来写下它们。一旦一个客户意识到这是一个用户故事并不是一个契约而且可以进行协商的时候,他们将非常乐意写下故事。
- 可以估算性(Estimable) — 开发团队需要去估计一个用户故事以便确定优先级,工作量,安排计划。但是让开发者难以估计故事的问题来自:对于领域知识的缺乏(这种情况下需要更多的沟通),或者故事太大了(这时需要把故事切分成小些的)。
- 短小(Small) — 一个好的故事在工作量上要尽量短小,最好不要超过10个理想人/天的工作量,至少要确保的是在一个迭代或Sprint中能够完成。用户故事越大,在安排计划,工作量估算等方面的风险就会越大。
- 可测试性(Testable) —一个用户故事要是可以测试的,以便于确认它是可以完成的。如果一个用户故事不能够测试,那么你就无法知道它什么时候可以完成。一个不可测试的用户故事例子:软件应该是易于使用的。
用户角色建模
在很多项目中,需求分析人员只从一个角度写用户故事,这样往往容易忽略一些故事,因为有些故事针对的并不是系统的一般用户。
虽然使用软件的用户有着不同的背景、持有不同的目标,但我们仍可以把这些单独的客户进行分组,把一类作为一种“用户角色”。用户角色是一组属性的集合,这些属性刻画了一群人的特征以及这群人与系统可能的交互。
角色建模的步骤
- 通过头脑风暴,列出初始的用户角色集合
- 整理最初的角色集合
- 整合角色
- 提炼角色
尽量坚持一个原则:用户角色定义的是人,而不是其它外部系统,如果觉得有帮助,可以偶尔确认一个非人物的系统角色。确认用户角色的核心目的是为了让用户对新系统感动满意。
搜集用户故事
四个字,够用就行。可以也要在项目开始前尽可能多的写出用户故事,但并不是要在项目开始前要花费几个月的时间去写用户故事,相反,它要求大家展望未来一个 发布时间,故事发布的时间越往后,我们就不在需要详细的写这个故事,可以用一个占位符来表示,比如:客户说想要一个报表功能。不需要详细的去描述这个功能 (如:用什么样的方式来实现)。
不同大小的网用来捕获不同的大小的需求,第一遍,我们可以用大网眼的网捞一遍需求池,来得到所有大的需求,通过这些大需求对软件形成整体的感觉,接下来使 用网眼稍微小一些的网再来捞一遍,可以得到中等大小的需求,在开始还没有必要顾及那些小的需求。(可能会漏掉一些需求,但不要再去花费的时间捕捞了)
也许在捕捞的时候会漏掉一些需求,因为这个需求对软件来说不是很重要,故事像鱼一样,会长大,也会死亡,根据每轮的迭代的反馈,会向事先不可预知的方向发展,有些需求可以会变的不在重要,甚至已经没有用了;以前漏掉(认为不重要)的需求可能会变的越来越重要。
捕捉用户事故的方法
- 用户访谈, 这可能是每个团队都想要的,与客户面对面的交谈。
- 问卷调查, 如果需要等到大量用户关于某些具体问题的回答时,是非常有用的。
- 观察, 在观察别人使用自己做的软件时,自己会获得很多提高用户体验或生产力的想法。
- 故事编写工作坊, 是开发人员、用户、产品客户和其它对编写故事有帮助的人共同参加的会议。在工作期间,参与人员尽可能多的 去写故事(不分优劣好坏),不排优先级,最后让客户去排优先级。
- 演示, 与观察相同,在为别人演示自己所做的软件时,可能会感受对其中一些用的不爽的地方,观看者也可以在第一时间提出对这个功能更好的建议。第一时间获得用户的反馈。
用户故事验收测试
验收测试提供了确认用户故事是否被完整实现的基本标准,有了这样的标准,我们就知道什么时候某件事算是做完了。
验收测试还是对用户故事细节的补充,因为故事是不包含细节的,为程序员提供了大量有用的信息。所以应该在代码编写前编写验收测试,主要由客户定义测试。
在一个用户故事卡片或者wiki上,以列举要点的形式,把对系统行为的期望结果和实际结果记录下来。这种技术适用于较小的或者简单的用户故事。
优秀用户故事准则
- 从目标故事开始,为了确定故事,从每个角色使用系统的目标开始考虑。
- 切蛋糕,分割故事时,试着将它分割成贯穿应用程序所有层面的故事,即每个小的故事功能都是完整的。
- 编写封闭的故事,一个封闭的故事时指那种随着一个有意义的目标的实现而结束的故事,能让用户使用后觉得他完成了某个任务。
- 卡片约束,对于任何必须要遵守而不需要直接实现的故事可以把它们标为约束,例如:使用JAVA语言开发,使用MySQL数据库,响应时间为1s等。
- 根据实现时间来确定故事规模,近期的故事应该足够小可以放到迭代中完成,而远期的故事则可能比较大,即要把精力放在即将发生的事情上。
- 不要过早涉及用户界面,一直以来困扰着软件需求方法的问题之一是将需求和解决方案混在一起,用户界面包含了太多的细节和解决方案。
- 有些需求并不是用户故事,用户界面,重要系统之间接口的定义等并不是用户故事,用其它合适的方式实现即可,不强求使用用户故事。
- 在用户故事里包含用户角色,开发人员会联想实际的、真切的用户,开发出满足用户需求的软件。
- 只为一个用户编写,当故事只为单一用户编写时,故事的可读性通常是最强的,从单个用户的角度考虑故事时,这类问题会变得清晰。
- 以主动语态编写,用户故事用主动语态编写时,更容易阅读和理解。
- 由客户编写,客户是软件的实际使用者,他们负责定义故事的优先级,所以由客户编写用户故事是最理想的。
- 不要忘记意图,用户故事是提醒开发人员和客户进行讨论的,只是占位符,所以要简洁,不要加入太多的细节以此取代对话。
估算用户故事
故事点数是需要实现一个故事所付出时间的相对度量,借鉴于XP(故事这个概念也是如此)。它们应该被用来估算困难程度,而不是承诺一个特定的时间阶段,这样不同的团队规模或是任务上花去的时间就不会影响故事点数”。
- 用故事点估算故事,故事点事故事复杂度、工作量或工期的相对估算。
- 应该由团队估算故事,估算属于团队不属于个人。
- 通过和其它估算进行比较来进行三角测量,例如团队一致同意一个故事的估算是另外一个故事估算的2倍,同时同意是一个更大故事估算的一般,通过故事间的比较可以大致判断估算是否合理。
- 团队是否用结对编程对故事的估算没有影响,结对编程影响的是团队的开发速率,不是他们的估算,因为故事估算不是时间的估算,结对编程只会影响开发的时间。
发布计划
为了计划一个发布,客户必须排列故事的优先级,可以采用莫斯科(MoSCoW)法则进行排序:
- 必须有(Must have),是指系统的基本功能。
- 应该有(Should have),是指很重要但短期内有替代解决方案的功能,如果没有时间限制,通常认为是强制的。
- 可以有(Could have),是指如果没时间就可以在发布中不予考虑的功能。
- 这次不会有(Won't have this time),是客户期望拥有但同时承认需要在后续发布中实现的功能。
如果客户已经定义好所有故事的优先级,团队为每个故事进行了估算,那么基于团队的开发速率,是很容易算出一次发布的大致完成时间的。
利用发布计划,我们顺利地将粗粒度的故事分配到发布中的多轮迭代。这种层次的计划--不包含很多细节,可以避免给出精确需求的感觉,却足以根据它开始行动。
迭代计划
整个团队通过举行迭代计划会议来为下一轮迭代做计划,客户以及团队中的所有开发人员包括测试人员都要参加,迭代会议的主要内容如下:
- 讨论故事,客户从最高优先级的故事读给开发人员听,直到他们充分理解故事,能从故事中分解出任务。没有必要理解故事的所有细节,不是会议中的每个人都需要理解所有细节,在正式开发时开发人员可以继续和客户一起理清故事的关键细节。
- 从故事中分解出任务,有利于多人共同完成一个任务,因为开发人员有各自擅长的技能,比如分成前端和后端部分。只有对故事有了最小的设计方案时,才可能进行分解任务,所以分解任务就是对任务的一次及时设计。
- 开发人员承担每个任务的职责,每个分解出来的任务必须要有人负责,即使采用结对编程也要挂在其中一个人的名下,这是他的职责,他自己负责找人结对。但是任务分配不是一成不变的,可以团队成员的开发进度动态调整。
- 开发人员估算他们承担的任务,以确保他们不会做出过于乐观的承诺,因为任务足够小,更容易做出可靠的估算,从而能够计算出整个团队本次迭代能够完成几个故事。
用户故事和其它收集用户需求方式的比较
除了用户故事,常见的需求方法有:用例(use case),IEEE 830软件需求规格和交互场景设计。
IEEE 830软件需求规格
IEEE 830是电气与电子工程师协会定义的如何编写软件需求规格的指南,IEEE的建议覆盖了诸如如何整理需求规格文档、角色原型和良好的需求特征等等,其中最让人印象深刻的就是使用句法“系统应该……”。有如下缺点:
- 按照这种方式记录需求乏味且容易出错,而且非常费时,对于中等规模的系统大概有300页左右的文档,很难有人把它全部读完,而且常常使读者无法理解全局。
- 用户看到正在开发的软件时,会有有效和重要的反馈循环。用户看到软件时,他们会想出新的点子,并且改变他们之前的想法。因此在开发之前写出所有的软件需求是不可能的,都是凭着分析师的想象写出来的,项目越大,偏差越大。
- 他们侧重于关注需求的检查清单(checklist),而不是用户的目标。需求清单不会像故事那样给读者一个对产品的整体理解。而用户故事则描述用户目标而不是系统功能列表,能够更好的满足用户的需求。
- 软件需求规格中每个需求的成本是不可见的,一般系统分析师花费几个月编写出冗长的需求文档,然后把文档交付给程序员,随后程序员告诉分析师需要24个月完成,但是时间只有6个月,所以许多需求可能无法完成,对应的需求文档可能就白写了。
- 采用这种方法来描述系统需求,非常容易混淆需求和设计的界限,这样的表述实际上已经包含了部分的设计在内。由此常常导致这样的迷惑:系统需求应该详细到何种程度?一个极端就是需求可以详细到概要设计,因为这样的需求表述既包含了外部需求也包含了内部设计。
其实需求列表最大的问题在于,列表上的项目描述了软件的行为,而不是用户的行为或者目标,需求列表很少回答“但是,如何使用以及为什么有人需要这个功能呢?”
用例
用例(Use Case)是一种描述系统需求的方法,使用用例的方法来描述系统需求的过程就是用例建模。用例方法最早是由Iva Jackboson博士提出的,后来被综合到UML规范之中,成为一种标准化的需求表述体系。
用例是对系统之间以及一个或多个用户之间交互的一般性描述,使用者要么是用户,要么是另外的系统。用例可以编写为非结构化的文本,或者符合结构化的模板。
用例和用户故事的差异主要有以下几个方面:
- 范围不同。二者都用来体现商业价值,但故事规模可以设定比较小(例如,10天完成),以便以此为单位安排工作。用例包含的范围可能比故事大得多。
- 完成程度不同。James Grenning曾指出:故事卡中的文字“加上验收测试用例就基本等同于用例”,这意味着故事对应于用例的基本流,而故事的测试要求对应于用例的备选流。
- 寿命不同。用例通常是持久的工作产品,在产品开发和维护时,用例一直存在。然而,故事通常只存在于实现该故事的迭代中。虽然故事卡可以存档,但是许多团队都将故事卡销毁。
- 编写目的不同。用例的目的是记录客户和开发团队的一致意见。故事是为了便于制定发布计划和迭代计划,并作为有关用户需求细节方面的交谈备忘录。
用户画像与用户场景
通常在产品设计过程中会遇到一个问题,你的产品适用于什么样的用户,什么样的场景。简而言之就是什么样的用户在什么场景下使用你的产品。这也是产品经理设计产品最基础的部分,有了这个基础才能去给产品一个明确的定位,从而进行产品功能的规划,页面设计以及用户体验等东西。只有充分挖掘了用户画像和用户场景,产品才能为用户提供价值。
用户故事和场景的主要区别是范围和细节,场景包含更多的细节,它们的范围通常涵盖多个故事。场景的优点和缺点都是它包含了非常多的细节,优点在于有足够多的细节便于理解与开发,缺点在于这样不利于定义优先级和进行进行迭代。
用户故事的优势
- 用户故事强调口头沟通,用户故事作为提示语句提醒开发人员在将来需要和客户进行沟通和讨论,重视口头交流这一转变提供了迅速的反馈周期,往往能促成对需求的充分理解。
- 人人都可以理解用户故事,IEEE830软件需求规格往往充斥着太多的技术或者商业术语,开发人员和客户无法同时理解它们。
- 用户故事的大小适合做计划,用户故事的大小合适,可以方便的设定优先级,然后基于优先级做计划。但是用例和场景都相对较大,很难设定优先级,而IEEE830的功能列表非常细,基于它排优先级会把人逼疯了。
- 用户故事适合于迭代开发,我们可以根据需要将大的故事拆分成比较小故事,小的故事比较容易在迭代中完成设计、开发和测试,而用例和场景则相对较大,一个迭代很难完成。
- 用户故事鼓励延迟细节,我们可以先写出一个初始目标层面及占位意义的故事,在后来这个故事对于开发进程比较重要时,才需要用更多细节来代替这个简单的描述。
- 用户故事支持随机应变的开发,随着不断的发现机会,团队视线能够迅速的在高层和低层细节思考间来回切换。
- 用户故事鼓励参与性设计,相比用例及场景易读、易懂,因而能够激发用户的积极性,成为软件设计的参与者,同时,随着用户逐渐掌握如何使用对于开发人员直接有用的故事来描绘他们的需求时,开发人员与用户间的关系会变得更加密切和主动。这个良性的循环使所有开发中涉及的人或者软件使用者都获益良多。
- 用户故事传播隐性知识,缘于对面对面沟通的重视,故事能够促进团队内隐性知识的积累。开发人员与客户之间以及他们内部的沟通越密切,越多的隐性知识能得到传播与加强。
用户故事的缺点
- 当用户故事比较多时,故事间的关系变得错综复杂,尤其是其中有大的故事和分解后细小的故事,这时很难理清楚它们之间的关系,管理比较麻烦。
- 当多个团队协作开发时,因为用户故事强调口头沟通,很难使不同的团队间共享讨论的细节,这时还是需要把交流情况记录下来进行共享。
用户故事的本质
用户故事本质上就是鼓励沟通,甚至强迫沟通,因为它没有细节,通过持续的沟通,进而基于用户持续的反馈不停的对软件开发进行调整,从而确保最终交付的软件就是用户想要的。