Appearance
第6章 需求之系统用例规约
6.1 用例规约的内容
用例图表达了用例的目标,但是对于完整的需求来说,这是远远不够 的。用例的背后封装了不同级别的相关需求,我们需要通过书写用例规 约把这些需求表达出来。用例规约就是以用例为核心来组织需求内容的 需求规约。有了用例规约,可以不需要另外写其他格式的需求规约。用 例规约的各项内容用类图展示如图6-1所示。
text
图6-1 用例规约的内容
@startuml
!theme plain
hide empty members
class 涉众
class 涉众利益
class 执行者
class 用例
class 条件
class 扩展
class 包含
class 关系
class 路径
class 步骤
class 字段列表
class 业务规则
class 补充约束
class 质量需求
class 设计约束
涉众 "1" -- "1..*" 涉众利益
涉众利益 "*"-- 用例
执行者 "1..*" -- "1" 用例 : -主执行者
执行者 "*" -- "*" 用例 : -辅执行者
用例 "1..*" -- "0..*" 条件 : -前置
用例 "1..*" -- "0..*" 条件 : -后置
扩展 --|> 关系
包含 --|> 关系
关系 "1" -- "1..*" 用例
关系 "*" -- "1..*" 用例
路径 "1" -- "1..*" 步骤
用例 "1" -- "1..*" 路径 : -基本路径
用例 "1" -- "1..*" 路径 : -拓展路径
步骤 -- 关系 : -发生点
补充约束 "*" -- "1..*" 用例
补充约束 "*" -- "*" 步骤
字段列表 --|> 补充约束
业务规则 --|> 补充约束
质量需求 --|> 补充约束
设计约束 --|> 补充约束
@enduml
图6-1的各项内容中,执行者和用例在用例图中已经存在,照搬到用例规 约中就可以。剩下的内容用例图上没有,需要另行添加。目前UML并未 包含用例规约的表示法。过去常见的做法是用Word等文字处理器来书写 用例规约,不过扁平文本形式难以高效建立和维护用例各项内容之间的 关系。现在已经有专门用于编写用例规约的工具,例如Case Complete、 Visual Use Case等,而且越来越多的UML建模工具也开始提供编写用例规 约的功能,使得需求人员能够以“立体”的方式来书写和保存用例规约, 并以文本、图形、表格等各种视图查看或输出.
接下来,我们逐个看看除了用例名称和执行者之外的其他各项内容的要 点。
6.1.1 前置条件和后置条件
用例通过前置条件(precondition)、后置条件(postcondition)以契约的 形式表达需求。用例相当于系统的一个承诺:在满足前置条件时开始, 按照里面的路径步骤走,系统就能到达后置条件。
前置条件:用例开始前,系统需要满足的约束。
后置条件:用例成功结束后,系统需要满足的约束。
在本书中,后置条件不再像有的方法一样分为最小后置条件和成功后置 条件,只写出最想要的那个状态,这样就避免掉入“从实现角度看这样可 以那样也可以”的陷阱。
前置条件、后置条件必须是系统能检测的。
“录入保单”用例的前置条件是错误的。业务代表是否已经把保单 交给内勤,系统无法检测,不能作为前置条件;同样,“收银”用例的后 置条件也是不对的。顾客是否已经带着货物离开商店系统也无法检 测,不能作为后置条件。
前置条件必须是用例开始前系统能检测到的。
比如,储户开始取现金的交互前,系统不知道储户是谁,要取多 少钱,所以无法检测“储户账户里有足够的金额”这个条件。
类似于“存在大于最低限额的现金”这样的背景条件作为前置条件是可以 的。就算很长时间没人来ATM取现金,这个条件是否成立就摆在那里。
前置后置条件是状态,不是动作。
例如,“经理→批假”的前置条件不能写“员工提交请假单”,因为是一个动 作不是状态,应改为“存在待审批的请假单”。特别要注意的是,写成“员 工已经提交请假单”很可能也是不对的,因为状态和导致达到某个状态的 行为不是一一对应的,请假单未必是员工自己提交,也可以组长负责帮 本组人员请假,也可能是从另外的系统批量导入。
如果分不清楚状态和行为的区别,建模就会遇到很大的麻烦。后面的建 模工作中,还会不断讨论状态和行为的问题。
前置后置条件要用核心域词汇描述。
“系统正常运行”“网络连接正常”等放之四海而皆准的约束,和所研究系统 没有特定关系,不需要在前置条件中写出来,否则会得到一堆没有任何 增值作用的废话。
后置条件也不能简单地把用例的名字加上“成功”二字变成“××成功”。例 如,用例“顾客→下单”的后置条件写“顾客已经成功下单”,这不是废话 吗?更合适的后置条件是“订单信息已保存”。
“已登录”不应作为前置条件。
一些用例规约会有这样的前置条件:××已经登录。下面花一些篇幅来讨 论这样做是否合适。 以购物网站为研究对象,登录不是用例。这一点在第5章已经阐述过了。 如何处理登录?在过去的不少书和文章里可以看到做法。
画法一:把其他用例作为“登录”的扩展图6-5
text
图6-5
@startuml
actor "会员" as 会员
rectangle "购物网站" {
(登录) as 登录
(下单) as 下单
(查看以往订单) as 查看以往订单
}
会员 --> 登录 : 使用
下单 ..> 登录 : «extend»
查看以往订单 ..> 登录 : «extend»
note right of 购物网站
这样做登录成了主用例,显然用户不是为了登录来的,而是为了下单和查看订单来的。
end note
@enduml
会员登录以后可以下单,也可以查看以往订单,还可以退货……所以图6- 5把下单、查看以往订单画成登录的扩展。这是错的。并不是先做A然后 可能做B或C,B和C就成了A的扩展。例如,张三先吃饭,然后可能看电 视,也可能上厕所,也可能散步。如果把看电视、上厕所、散步画成吃 饭的扩展,意思就成了“张三可能会以上厕所的方式吃饭”或“上厕所是张 三达到吃饭目标的一条路径”。
第二种做法,把“登录”变成被其他用例包含(Include)的被 包含用例(Included Use Case)。这样做是正确的。登录用例本来不存 在,后来在写用例规约的时候,发现“下单”“查看以往订单”等用例里都有 以下步骤:
1.会员提交身份信息 2.系统验证身份信息 3.系统保存会员登录信息 4.系统反馈会员定制界面
为了节省书写用例规约的工作量,考虑把这些形成一个小目标的步骤集 合(不是单个步骤)分离出来,作为一个被包含用例单独编写规约。这 个用例只被其他用例包含,不由主执行者指向。被包含用例的这个特点 和类的私有操作很相似。
text
图6-6
@startuml
actor "会员" as 会员
rectangle "购物网站" {
(下单) as 下单
(登录) as 登录
(查看以往订单) as 查看以往订单
}
会员 --> 下单 : 使用
会员 --> 查看以往订单 : 使用
下单 ..> 登录 : «include»
查看以往订单 ..> 登录 : «include»
note right of 购物网站
下单和查看以往订单都包含登录,这样是合理的
end note
@enduml
按照图6-6的做法,“下单”用例规约的步骤里,应该有表示包含“登录”用 例的步骤集合:会员【登录】。“登录”二字加了粗括号表示这是一个被 包含用例,它的步骤和约束在另外的地方描述。不喜欢粗括号可以用加 下划线等其他方法以示区分。
有些人觉得这样做的话,好些用例里会出现会员【登录】,看起来有些 碍眼,就想能不能把它提到前置条件里,那就得到了第三种:把“登 录”作为一个用例,“会员已经登录”作为其他用例的前置条件。 这样用例的步骤看起来更清爽,但是严格来说这也是不对的,“登 录”不是购物网站的用例。
可能有的人会觉得第三种画法更好,理由是从最终实现上看,会员登录 以后可以下单,可以查看以往订单,不用再重新登录,看起来是不是第 三种更合理?其实还是第二种合理。第5章说过,如果在做需求时考虑复 用,可能已经陷入了设计的思维。能够在多个用例中复用登录的状态, 这是设计人员的本事,他甚至还可以做到10个用例的界面都从一个模板 生成,但不能因此就把这10个用例合并成一个。
认为第三种更好的另一个理由也和“复用”有关:当几个执行者在使用某 些用例时都会有登录的步骤集合,把登录单独分离出来,可以抽象出一 个用户执行者,指向登录。
这个看起来正确,实际上也是不对的。不同的涉众利益会带来不同的需 求。这样做,潜意识里就有着一种追求“需求复用”的思想,会诱导需求 人员对不同用例之间的微妙差别视而不见,这对于做需求来说是危险 的。会员登录需要验证码,货管员登录时不需要。系统反馈给会员的是 未完成的订单,反馈给货管员的则是最近货品的动态。会员登录时可能 要求反馈速度很快,而且允许百万会员同时在线,货管员登录则没有那 么严格。 更合理的做法是,分成几个不同的被包含用例。 被包含用例(以及扩展用例)严格来说不能算用例,应该有更好的名 字,例如“交互片段”,否则名称中带的“用例”二字容易误导开发人员从实 现的角度定义用例,而不是从对外提供价值的角度。
6.1.2 涉众利益
前置条件是起点,后置条件是终点,中间的路该怎么走?这就要由涉众 利益决定了。如果只考虑目标而没有考虑涉众利益,正确的需求是出不 来的。
假设我需要1000元现金。为了达到这个目的,首先我会拉开家里的抽 屉,如果里面有超过1000元的现金,我就从中拿1000元;如果抽屉里没 有现金或者现金不够,我就拿上银行卡,到楼下ATM去取。问题来了: 同样的目标,为什么家里的抽屉拉开就可以达到,而楼下的ATM却要插 卡输密码?
背后的原因是涉众利益不同。涉众利益即针对某件事情,某类人担心什 么和希望什么。家里的抽屉只涉及我和家人的利益,如果我和家人和睦 相处,拉开抽屉就可以拿;反之,如果我和家人的利益冲突得非常厉 害,那么可能需要买一种长得很像ATM的抽屉才能满足我家的需要。
对于银行ATM来说,就不是这样了。储户在ATM取现金时,涉及的涉众 利益如下: 储户—希望方便; 担心权益受损。 银行负责人—希望安全; 希望节约运营成本。 正是在这些涉众利益的交锋之下,目前我们日常生活中所看到的ATM的 用例片断如下:
基本路径
1.储户提交账户号码
2.系统验证账户号码合法
3.系统提示输入密码
4.储户输入密码
5.系统验证密码合法、正确
6.系统提示输入取现金额
7.储户输入取现金额
8.系统验证取现金额合法
9.系统记录取现信息,更新账户余额
……
业务规则
5.密码为6位数字
8.取现金额应为100元的倍数;取现金额应少于账户余额;单次取
现金额不超过3000元;当日取现金额不超过20 000元
设计约束
1.通过磁条卡或芯片卡提交账户号码
我们来看看涉众利益的交锋如何影响了需求。步骤1有设计约束,“通过 磁条卡或芯片卡提交账户号码”,这是为了照顾储户“方便”的利益。
既然为了储户方便,还验密码干什么?银行不是口口声声说储户是上帝 吗?为什么不在储户提交账户号码后,把钱箱弹出来让储户随便取?这 是为了照顾银行“安全”的利益。
既然设密码是为了安全,密码长度怎么只要6位呢?何不设10位或更长的 密码?这又是“安全”和“方便”交锋后的妥协。可以想像,如果有一 天,“ATM黑客”魔高一丈,6位密码很容易攻破,这条规则可能就会变成 密码为8位数字。
步骤“系统验证取现金额合法”以及“业务规则取现金额应为100元的倍 数”……如果能有1元2元的ATM,储户会非常高兴(没有零钱坐公交车? 到ATM那里取去),但银行不高兴——成本太高了。业务规则“单次取现 金额不超过3000元;当日取现金额不超过20 000元”,这同样是考虑银行 节约运营成本的利益。当然,银行方的解释会是为了保护储户的利益, 防止被冒领,等等。
系统记录取现信息,更新账户余额。这是储户看不见摸不着的,为什么 要写出来?因为要是系统不做这件事,银行方就吃亏了。
认识到需求由涉众利益的冲突和平衡来决定,我们的需求过程就会充 满“人”的味道,变得乐趣横生。扩展开来看,我们为什么在现在的公司 工作,为什么选择现在的配偶,甚至午餐吃什么,都是权衡了各种涉众 利益的结果。
为了寻找用例的涉众,可以用“醉酒法”思考。假设台上的演员“喝 醉”(“喝醉”加了引号,是因为在台上的未必是人)了在台上表演,谁看 到这个场面会担心自己的直接利益受到侵害?担心的人就是这个用例的 涉众。其主要有以下来源。
- 涉众来源一:人类执行者
用例的执行者如果是人类,当然是用例的涉众。执行者如果不是人类, 就不是涉众,因为它没有利益主张。针对图6-11中保险系统的“内勤→录 入保单”用例,内勤是人类,是涉众,而OA系统不是人类,不是涉众。
text
图6-11
@startuml
actor "内勤" as 内勤
actor "OA系统" as OA系统
rectangle "保险系统" {
(录入保单) as 录入保单
}
内勤 --> 录入保单 : 执行
录入保单 --> OA系统 : 同步数据
note right of 录入保单
涉众:内勤
end note
@enduml
- 涉众来源二:上游
执行者要使用系统做某个用例,可能会需要一些资源,这些资源的提供 者很可能是该用例的涉众。还是以“内勤→录入保单”为例,保单由业务 代表提供给内勤。如果内勤喝醉了酒乱录,信息错得一塌糊涂,业务代 表的利益就被损害了。考虑上游之后,“内勤→录入保单”用例的涉众如 图6-12所示。
text
图6-12 考虑上游之后的涉众
@startuml
actor "内勤" as 内勤
actor "OA系统" as OA系统
rectangle "保险系统" {
(录入保单) as 录入保单
}
内勤 --> 录入保单
录入保单 --> OA系统
note right of 录入保单
涉众:内勤、业务代表
end note
@enduml
- 涉众来源三:下游
执行者使用系统做某个用例,产生的后果会影响到其他人。受影响的这 些人也是涉众。还是以“内勤→录入保单”为例,如果系统做得不好,没 有检测内勤录保单时是否填了必填项就放了过去,后面负责审核的经理 工作量增加了。
还有,OA系统虽然不是“内勤→录入保单”用例的涉众,但这个用例产生 的结果会影响到OA系统背后的人。假如保险系统不停向OA系统发垃圾数 据包,导致OA系统瘫痪,OA系统维护人员的工作量就增加了。所以OA 系统维护人员也是下游的涉众。考虑下游之后,“内勤→录入保单”用例 的涉众如图6-13所示。
text
图6-13 考虑下游之后的涉众
@startuml
actor "内勤" as 内勤
actor "OA系统" as OA系统
rectangle "保险系统" {
(录入保单) as 录入保单
}
内勤 --> 录入保单
录入保单 --> OA系统
note right of 录入保单
涉众:内勤、业务代表、经理、OA系统维护人员
end note
@enduml
- 涉众来源四:信息的主人
用例会用到一些信息,这些信息可能会涉及某些人。虽然这些人也许并 不知道这个系统的存在,但他们是用例的涉众。还是以“内勤→录入保 单”为例,保单的信息涉及被保人、投保人和受益人,如果信息出错或泄 漏,这些人就会遭殃,所以他们是涉众。因为这类涉众可能和系统没有 接口,比较容易被忽略,要特别注意。考虑信息的主人之后,“内勤→录 入保单”用例的涉众如图6-14所示。
text
图6-14 考虑信息的主人之后的涉众
@startuml
actor "内勤" as 内勤
actor "OA系统" as OA系统
rectangle "保险系统" {
(录入保单) as 录入保单
}
内勤 --> 录入保单
录入保单 --> OA系统
note right of 录入保单
涉众:内勤、业务代表、经理、OA系统维护人员、被保人、投保人、受益人
end note
@enduml
说到这里,也许您已经看出来,业务建模对于识别涉众非常有帮助。如 果我们在需求之前做了业务建模,会更了解一件事情的前因后果,大多 数涉众都能够从业务序列图中看出来。例如,从图6-15的业务序列图中, 业务对象内勤、业务代表、经理和投保人很容易看出来。另外,消息参 数“保单信息”提醒建模人员还会涉及被保人和受益人。这样,图6-14中所 列举的“内勤→录入保单”的涉众就找齐了。
text
图6-15 业务建模可以帮助寻找涉众
@startuml
actor "投保人" as 投保人
actor "业务代表" as 业务代表
actor "内勤" as 内勤
actor "保险系统" as 保险系统
actor "经理" as 经理
投保人 -> 业务代表 : 办理投保()
业务代表 -> 内勤 : 录入保单(保单)
内勤 -> 保险系统 : 录入保单(保单信息)
保险系统 --> 经理 : 审核保单()
@enduml
最后回答一个经常被问到的问题:系统的研发团队成员是该系统的涉众 吗?不是。根据第2章所说的“投币法”,系统是投币得来的,考虑需求时 根本没有“研发团队”。这里的意思并不是说工作性质为软件开发的人就 不能当涉众,当他充当投币者的角色时是可以的。例如,以建模工具EA 为所研究系统时,使用EA来建模的软件研发团队成员是涉众,但EA的研 发团队成员不是涉众。
- 寻找涉众利益
寻找涉众利益时,要“亲兄弟,明算账”,把不同涉众各自关注的利益体 现出来,而不是写成一模一样的。家里两夫妻对同一件事情都还有不同 的立场,更不用说一个组织里面形形色色的涉众了。
司机开车进厂装化肥,工作人员通过地磅系统操纵地磅给车称重。针对 这件事情,不同的涉众可谓是“各怀鬼胎”:
化肥公司老板―担心公司内部人员贪污 地磅操作员―希望操作简便;担心承担责任;担心系统坏掉影响工 作量 仓管人员―担心称不准导致无谓的返工装包 买主―担心进去时称得轻了,出来时称得重了,导致给少了化肥 司机―担心等侯时间太长导致每天拉货次数减少
即使有些利益有时不方便白纸黑字写出来共享,但至少建模人员要心知 肚明,不能一团和气了事。
建模人员要仔细观察和揣摩涉众的痛苦,才能找到真正的涉众利益,否 则写出来的“涉众利益”往往很苍白。例如,前面提到的“储户→取现金”用 例,涉众利益写“储户担心取不到现金”,这就是废话了。
再看下面这个例子,一个输液系统,涉众利益写:
护士—担心出错
正确的废话,谁不担心出错,但为什么还是出错?仔细调研过之后写出 来就生动多了: 护士—担心自己的药理学知识记错,对药物名称相近的药物计算错 剂量,导致给药误错误
- 善于积累涉众利益
需求是不断变化的,新系统肯定在功能或性能上和旧系统有所不同,否 则还做什么新系统?但是,背后的涉众利益要稳定得多。我们来看之前 ATM例子中出现的涉众利益:
储户—希望方便;担心权益受损 银行负责人—希望安全;希望节约运营成本
这些涉众利益不止适用于ATM,也适用于清朝的钱庄柜台、现在的银行 柜台、网上银行和手机银行.
很多需求中的两难,都是因为信息不足导致的。如果我们能善于积累涉 众利益,把目标组织内部各种人的小算盘搞得一清二楚,对方稍微说句 话,我们就已经知道他心里的小九九,而且还知道他的要求对谁有利, 对谁有害,从而可以自如应对。
6.1.3 基本路径
观众已经一排排坐好,接下来就要让演员们上台演戏了。把演戏的场景 描述出来,就得到了用例的路径和步骤。
一个用例会有多个场景,其中有一个场景描述了最成功的情况,执行者 和系统的交互非常顺利,一路绿灯直抵用例的后置条件。这个场景称为 基本路径。
用例把基本路径分离出来先写,目的是凸现用例的核心价值。还是以上 面的ATM为例,发生在ATM上的场景有很多:
(1)张三来了,插卡,输密码,输金额,顺顺利利取到钱,高兴地走 了;
(2)李四来了,插卡,输密码,密码错,再输,再错,再输,卡被吞掉 了;
(3)王五来了,插卡,输密码,输金额,今天取得太多不能取了……
只有场景(1)是银行在大街上摆放一台ATM的初衷。虽然场景(2) (3)是难以避免的,但场景(1)出现得越多越好,这是涉众对ATM的 期望。
书写路径步骤的时候需要注意以下一些要点。这些要点有重叠的地方, 如果违反了其中一个要点,很可能会违反另外的要点。
6.1.3.1 按照交互四步曲书写
执行者和系统按照回合交互,直到达成目的。需要的回合数是不定的, 可能一个回合足够,也可能需要多个回合。一个回合中的步骤分为四 类:请求、验证、改变、回应
在一个回合中,请求是必须的,同时还需要其他三类步骤中的至少一 类。下面展示了一个例子。可以看到,第一个回合只需要请求和回应, 第二个回合则四类步骤都有。
- 回合1
- 顾客请求注册 → 请求
- 系统反馈注册界面 → 回应
- 回合2
- 顾客提交注册信息 → 请求
- 系统验证注册信息充分 → 验证
- 系统创建顾客账户 → 改变
- 系统反馈所创建的顾客账户信息 → 回应
在时间作为主执行者而且不需要和其他辅执行者交互的用例中,可能会 出现不需要回应的情况,而且只有一个回合。
(1)对于时间为主执行者的用例,回合中的请求步骤不写“时间告知时 间周期到了”,而是写“当到达时间周期时”。 (2)验证步骤不写“是否”。第4步写“系统验证注册信息 充分”,不写“系统验证注册信息是否充分”,目的是要表达“充分”是基本 路径期望的验证结果。 (3)系统和辅执行者之间的交互可以看作是一种回应步骤,写成“系统 请求辅执行者做某事”,例如“系统请求邮件列表系统群发邮件”。
6.1.3.2 只写系统能感知和承诺的内容
以上面的“系统请求邮件列表系统群发邮件”为例,写到这里足够了,不 能再往下写: 邮件列表系统群发邮件
这已经不属于系统能感知和承诺的责任范围,不能写在步骤中,否则就 会让人以为只要用上了这个系统,这些事情就一定会发生。这样就模糊 了系统的契约,也抹杀了进一步改进的可能。
例如以下规约片断: …… 4.系统反馈应收总金额 5.顾客付款 6.收银员提交付款方式和金额 7.系统计算找零金额 8.系统反馈找零金额,打印收据 9.收银员找零 ……
顾客付款和收银员找零是系统无法感知和承诺的。如果写在步骤里,会 让人产生误解:只要用了本系统,顾客就会乖乖付款,收银员会乖乖找 零——也许顾客忘记付款和收银员忘记找零正是商场要解决的一个头痛 问题。
6.1.3.3 使用主动语句理清责任
把动作的责任人放在主语的位置,用Alistair Cockburn的话说就是“球在哪 里”。请比较下面两句话。
(1)伊布从瓦伦西亚处得到传球,舒梅切尔扑救伊布的射门。 (2)瓦伦西亚传球,伊布射门,舒梅切尔扑救。
虽然上面一句比较文艺,但下面一句把责任理得更清晰。用例步骤也是 如此: 系统从会员处获取用户名和密码(错) 会员提交用户名和密码(对) 用户名和密码被验证(错) 系统验证用户名和密码(对)
会员要是不提交,就不要怪系统没有动静;会员要是提交了,系统不动 弹,那就要怪系统了。 做到规规矩矩说话,把责任理清楚,其实不容易。经常有人会写:
会员保存订单 会员在哪里保存订单?存在自己的肚子里?应该是: 会员提交订单信息 系统保存订单
类似的还有:
会员查询商品 会员在自己肚子里面查?应该是: 会员提交查询条件 系统查询商品 系统反馈查询结果
6.1.3.4 主语只能是主执行者或系统
写需求,就是要把系统当作一个黑箱,描述它对外提供的功能以及功能 附带的质量需求。系统如何构造,不属于需求描述的范围,除非是涉众 强加的设计约束。所以步骤里不能出现“执行者请求前端系统做某事,前 端系统请求后端系统做某事”“执行者请求客户端做某事,客户端请求服 务器做某事”“执行者请求A子系统做某事,A子系统请求B子系统做某 事”,就算这个系统最终的组成是分解成很多个部分,分布在一百多个国 家运行,需求里也只有两个字:系统。前文已经说过,系统边界是责任 边界,而非物理边界.
可能会有人问“如果我要做的就只是客户端,难道不能写客户端请求服务 器做某事吗?”这时所谓的“客户端”就是所研究的系统,而原来所认为 的“服务器”已经是系统责任边界之外的一个外系统,用例规约里仍然不 会有“客户端”的字样出现。
6.1.3.5 使用核心域术语描述
路径步骤应该使用核心域的术语来描述,也就是说,要说“人话”。
以一个零件采购系统为研究对象,比较以下两句话,哪一句是“人话”, 哪一句是“鸟语”?
(1)系统建立连接,打开连接,执行SQL语句,从“零件”表查询…… (2)系统根据查询条件搜索零件
您一眼就能看出来,第一句是“鸟语”,第二句是“人话”。关键在于:为什 么说第一句是“鸟语”?可能有的人说,因为第一句涉及技术,所以是“鸟 语”。这个解释是有问题的。第2章我们说到要从开发人员使用的术语中 删去“用户”二字,现在我们还要删去“技术”二字。
之前在第3章中也已经提到,不少开发人员说到“技术”的时候,含义就 是“我懂的或感兴趣的那点东西”,不懂且不感兴趣的就称为“业务”,甚 至“忽悠”。例如,程序员认为“Java编码是技术,需求人员做的是业务”; 需求人员则认为“业务建模、需求也有很多技能,我做的当然是技术,我 们的客户——医院的医生做的才是业务”;医院的医生更是嗤之以鼻“老 子一个月拿的红包比你一年薪水都多,还说我做的不是技术?”其实大家 做的都是“技术”,只是领域不同而已。应该用“核心域”“非核心域”来代 替“业务”“技术”。关于核心域和非核心域,本书在第8章还会深入讲解。
如果所研究系统是一个关系数据库的脚本工具,核心域是关系数据库领 域,上面提到的“系统建立连接,打开连接,执行SQL语句”就成了合适的 需求。
如果所研究系统仍然是零件采购系统,不过前排涉众强制要求“一定要这 样实现”,那么“系统建立连接,打开连接,执行SQL语句”也是需求,但 不能写在路径步骤里,只能写在设计约束里。
6.1.3.6 不要涉及界面细节
很多人写需求的时候,会把界面细节带进来,例如:
会员从下拉框中选择类别 会员在文本框中输入查询条件 会员单击“确定”按钮
这些界面细节很可能不是需求,只是开发人员选择的设计方案,应该把 它们删掉,然后问“为什么”,找到背后隐藏的真正需求,也许是可用性 需求“操作次数不超过5次”,也许是性能需求“反馈速度应该在3秒以内”, 也许两者兼有。
如果前排涉众明确要求“一定要用下拉框”,那么“下拉框”也是需求,但是 依然不能写“会员从下拉框中选择类别”,因为这里涉及两类需求,它们 的稳定性和变化趋势不同,应该分开描述:
会员选择类别(这是步骤) 通过下拉框来实现(这是设计约束)
用例的需求组织方式是分层的,从用例->路径->步骤->约束, 需求的稳定性越来越低。这样,稳定和不稳定的需求就分开了。平 时遇到的大部分“需求变更”发生在补充约束级别,例如输入会员信息时 加个微信字段(字段列表变了)、调整结账时的打折规则(业务规则变 了)。级别越高的需求,内容越稳定。
要避免步骤里出现界面的细节,要点是把和核心域无关的内容清除掉, 得到基于核心域视角的描述,例如:
系统显示订单信息→系统反馈订单信息 系统反馈查询到的商品列表→系统反馈查询到的商品 会员拖动商品到购物篮,勾选优惠券,单击结算按钮→会员输入商 品和优惠券信息,请求结算
前面说到“建立连接,打开连接,执行SQL语句”不是零件销售系统的需 求,可能大家觉得比较好理解,毕竟发生在系统“里面”,看不见,但是 步骤中出现界面细节“单击确定按钮”的时候,有的人就觉得这样写好像 可以,因为看得见!在需求规约中,在每个用例最后贴一张或几张界面 图,大家也觉得很正常。
需求判断的标准不是涉众是否看得见,而是涉众是否在意,否则盲人怎 么办?两个非人系统交互怎么办?像之前ATM的例子中,涉众看不见“系 统记录取现信息,更新账户余额”,但是涉及在意,必须写,而“单击确 定按钮”即使看得见,也不能写,因为涉众不在意。
界面组件和数据库组件一样,都是系统设计的一部分。以人体作为例 子,藏在人体内部的心脏是人的设计,露在外面的眼睛也同样是设计。 人体系统的需求是“能看”,未必需要单独分出“眼睛”这样一个器官。如果 有一种新人类,没有分出眼睛耳朵鼻子等器官,只是头上有一个360°接 收器接收各种声光和气味信号并传到内部处理,没准这样的新人类更适 合在这个社会上生存。另外,人光有眼睛这个输入设备,没有血液循环 系统和神经系统的帮忙,也无法让大脑感知到外部信息,达到“能看”的 目的。第一章已经说过,需求和设计不是一一对应,而是多对多的。
可能有的人会想,没有眼睛耳朵鼻子,那还算是人吗?正常的人不应该 是那样的吗?如果先入为主这样想,那就不用做需求了,直接复制现有 系统的文件就行了嘛。新系统要打败旧系统,肯定要和旧系统在某些方 面不同。特别是,软件系统的“新”和实物的“新”要求还不一样。对于实 物,我们可以说“这瓶酒喝完了,开瓶新的”,而以软件系统的标准看, 另一种型号的、口感或包装不同的酒才能算“新”。
6.1.3.7 不要涉及交互细节
在步骤中,除了避免描述界面细节,还要避免描述交互细节。例如,有 人会这样写:
会员每输入账户名称的一个字符 系统在界面中验证当前输入信息合法
写的人有他的道理:系统不是等待提交后才验证输入信息是否合法,而 是随时验证立即反馈,这样使用体验更好。不过,这只是交互设计的一 些技能。忍不住要在需求规约里描述界面和交互的细节,背后的原因和 忍不住要思考内部代码如何实现的原因是一样的,都是对自己的设计技 能没有信心,害怕“现在想到了如果不记下来以后就忘记了”。
交互设计和数据库设计、编码一样,都有特定的技能。例如,针对“一个 订单有多个订单项”这样一个核心域描述,数据库该如何映射,界面该如 何布局,都有特定的套路。这些套路只和数据库和界面平台的特点以 及“一对多关联”的结构有关,和“订单”“订单项”等核心域概念无关。
用例的步骤应该把焦点放在系统必须接收什么输入、系统必须输出什么 信息以及系统必须做什么处理这三个重点上,加上字段列表、业务规 则、可用性需求等约束,足以表达各种需求。
关于用例的交互该怎么写,是一个比较头痛的问题。即使不涉及交互设 计细节的问题,也免不了混进交互设计的成分,例如,为什么分两个回 合交互而不是一个回合?实际上涉众更希望一个回合就能达到用例的目 标。
例如之前提到的ATM的“取现金”用例的步骤:
1.储户提交账户号码 2.系统验证账户号码合法 3.系统提示输入密码 4.储户输入密码 5.系统验证密码合法、正确 6.系统提示输入取现金额 7.储户输入取现金额 ……
可以思考,如果不分多个回合输入和验证,是不是一定会损害涉众的利 益?如果不是,那么可以合并为一个回合,留下余地给更专业的交互设 计人员。
1.储户提交取现所需信息 2.系统验证取现信息符合取现要求 ……
字段列表: 1.取现所需信息=账户号码+密码+取现金额 业务规则: ……
但是这样的写法会使得各种用例的交互最后都长得差不多,区别只在于 输入输出的字段列表和处理的业务规则。这是让人左右为难的问题。我 的观点是在用例规约中把路径步骤删掉,只保留输入输出、涉众利益和 补充约束,交互的路径步骤由交互设计人员决定。
6.1.3.8 需求是“不这样不行”
说到界面和交互,在这里还要多说几句。许多需求人员之所以在需求岗 位上,并不是因为他掌握了该掌握的需求技能,可能只是因为他工作年 限足够长该换到需求岗位了——和许多年龄到了就上岗的夫妻和父母相似。
这样的需求人员硬着头皮做需求时,最常用的一招就是托着脑袋想“这个 东西是什么样子”,然后画一个界面原型拿去和涉众确认。一旦涉众 说“差不多就这样吧”,就把这个界面原型作为需求交给分析设计人员。 在这一点上,互联网公司的产品经理表现得尤为明显。如果侥幸成功, 就拼命鼓吹“原型大法好”,因为他只会这个。
这里就引出一个问题:假如需求人员画了一张界面图,拿去问涉众,界 面这样做可以吗?涉众说可以,甚至在上面还签字确认。那么,这个界 面方案是需求吗?或者我们问得再极端一点,《王者荣耀》是最近两年 最受欢迎的游戏,为腾讯公司带来了巨大的利润(单季度120亿人民 币),请问《王者荣耀》的源代码是需求吗?
以上两个问题的回答都是否。因为需求人员问的问题都是“这样可以 吗”,相当于:
需求人员:界面这样布局可以吗? 涉众:(好用就行,我又不会做界面,问我可不可以我当然说可以 了)可以。 需求人员:代码这样写可以吗? 涉众:(好用就行,我又不会写代码,问我可不可以我当然说可以 了)可以。
如果问的问题改为“不这样可以吗”,像下面这样:
需求人员:界面不这样布局可以吗? 涉众:不可以,这是政府的规定,你们不要自己乱发挥啊! 需求人员:代码不这样写可以吗? 涉众:不可以。这段代码是我小舅子写的,一定要这样,否则不给 钱。
这时,界面和代码就成为了需求,当然,只是补充约束级别的需求。
说到这里,我们归纳出需求的判断标准:需求是 “不这样不行 ”,而不 是 这样也行“ ”。如果需求点没有不这样不行的东西,可以考虑 跟处理交互细节一样留白,自由发挥,反正只要结果达成就行。
大家可以尝试用“不这样行吗”这个问题去过滤一下自己或其他人以前写 的“需求”,可能会过滤出一大堆假的需求,然后问“为什么”,找出背 后“不这样不行”的真正需求。
对于需求的一个误解是以为“写得细的就是好需求”。需求确实要细,但 是很多时候需求人员写的“细”不是需求(问题)的细,而是设计(解决 方案)的细。我看到过不少所谓“需求规约”,篇幅巨大,从数据库每个 字段的设计到界面控件详细布局,甚至编码规范,都包含在其中。作者 也很得意“我这份需求可谓是无二义了吧!”说到无二义,源代码就更无 二义了,但源代码不是需求。
在需求里大量描述设计,相当于医生没有能力去定位患者得的什么病, 干脆拍脑袋开药,然后用正楷把药的说明书抄一遍,抄到自己都感动 了,以为这样就可以治好患者了。诊断能力不足,开的药不对症就不对 症,说明书抄得再认真仔细也没用。
6.1.4 扩展路径
基本路径上的每个步骤都有可能发生意外,其中某些意外是系统要负责 处理的,处理意外的路径就是扩展路径。因为一个步骤上出现的意外及 其处理可能有多种,所以同一步骤上的扩展路径可能有多条。
对于扩展路径及其步骤的标号,本书采用的是Cockburn推荐的方法。扩展 路径的标号方法是在所扩展步骤的数字序号后面加上字母序号,例如2a 表示步骤2的第a条扩展路径,2b表示步骤2的第b条扩展路径。扩展路径 条件的最后加上冒号,接下来是该扩展路径的步骤,标号方法是在扩展 路径编号后面加上数字序号,例如2a1。也就是说,步骤的编号以数字结 尾,扩展路径编号以字母结尾。如果有多重扩展,那就继续按此形式标 注,如图6-21所示。
text
图6-21 扩展路径和步骤
@startuml
[*] --> 1
1 --> 2
2 --> 3
3 --> 4
4 --> 5
2 --> 2a1 : 2a
2a1 --> 2a2
2a2 --> 2a3
2a2 --> 2a2a1 : 2a2a
2a2a1 --> 2a2a2
@enduml
还是以之前的ATM“储户→取现金”用例为例。该用例规约加上扩展路径 之后如下:
基本路径 1.储户提交账户号码 2.系统验证账户号码合法 3.系统提示输入密码 4.储户输入密码 5.系统验证密码合法、正确 6.系统提示输入取现金额 7.储户输入取现金额 8.系统验证取现金额合法 9.系统记录取现信息,更新账户余额 …… 2a.账户号码不合法: 2a1.系统反馈账户号码不合法 2a2.返回1 5a.密码不合法: 5a1.返回3 5b.密码合法但不正确: 5b1.系统验证当日取款累计输错密码次数不超过3次 5b1a.当日取款累计输错密码次数超过3次: 5b1a1.系统关闭账户 5b1a2.用例结束 5b2.系统反馈密码不正确 5b3.返回3 8a.取现金额不合法: 8a1.返回6
从以上例子可以看到,有扩展的步骤2、5、8都属于验证类步骤。验证的 结果有通过和通不过。在验证通不过的情况下,系统肯定要做相应处 理,否则就白验证了。验证类步骤肯定会出现扩展。
和辅执行者交互的步骤很有可能会出现扩展。在系统请求辅执行者做某 事时,如果辅执行者出现故障,系统无法得到想要的结果,很有可能会 导致系统行为的变化。例如: 4.系统请求短信平台发布信息
…… 扩展 …… 4a.短信平台无响应: 4a1.系统反馈短信平台无响应 ……
注意,如果系统不需要从外系统那里得到任何结果,这个外系统就不是 辅执行者,所以它出现故障会不会导致扩展的讨论是没有意义的。例如 下面这一句:
5.系统向经理的电子邮箱发邮件通知有新的待审批申请
系统只是负责发邮件,无法感知经理是否收取电子邮件以及是否审批通 过申请,经理不是辅执行者,更不存在“经理没有收到邮件”或“经理审批 未通过”之类的扩展路径。
除了这两种步骤之外,从其他步骤产生扩展路径一定要非常谨慎,否则 容易让不属于需求的内容混进用例规约中。特别要注意下面几点。
- (1)能感知和要处理的意外才是扩展
不是所有的意外都产生扩展路径,有些意外是系统无法感知和处理的, 不产生扩展路径。ATM例子中,“储户心脏病发作”是意外,会导致“取现 金”用例无法完成,但ATM没有办法感知“储户心脏病发作”事件,也不负 责处理这样的事件。不过,“长时间无操作”则是可以被感知而且可能要 处理的。
可能有人会问,要是有一种高级ATM能感知“储户心脏病发作”呢?没问 题,上面讲的道理依然适用。
- (2)设计技能不足导致的错误不是扩展 即使是系统能感知的意外,也未必产生扩展。这种意外必须要符合需求 的要求才行。例如,经常有人把“系统保存数据失败”当成扩展,这是错 误的。保存数据为什么会失败?程序员编码错误、数据库设计错误或者 网络故障呗,换程序员、数据库设计人员或改善网络环境就能避免,这 和需求有什么关系?根据第二章的“投币法”,做需求时应该把研发团队 看作不存在,系统是投币得来的,不存在程序员编码错误等问题。
用执行者来对比可以帮助理解。执行者是外系统,就算我们的系统做得 没有错误,也无法保证外系统一定会给我们想要的结果。也就是说,这 样的意外和设计错误无关。所以,上面的“系统验证**** ”“系统请求某 某系统****”等步骤会产生扩展路径。
系统的可靠性确实也是需求,不过应该写在补充约束里,而不是写在路 径步骤里搞得到处都是扩展。
- (3)不引起交互行为变化的选择不是扩展
执行者需要从若干选项中做出选择,如果选择不同选项没有引起交互行 为的变化,扩展是不存在的。像下面的写法就是错误的:
…… 4.收银员选择 不让利 单条商品折扣 单条商品折让 削价 …… 扩展 4a.不让利: 4a1.系统按照不让利方式计算应收金额 …… 4b.单条商品折扣: 4b1.系统按照单条商品折扣方式计算应收金额 ……
无论选择哪一个选项,系统都是计算应收金额,只不过适用的规则不 同,在这里加入扩展没有意义,应该把这些选项写在字段列表和业务规 则部分,像下面这样:
4.收银员选择打折方式 5.系统计算应收金额 …… 字段列表 …… 4.可选打折方式有:不让利、单条商品折扣、单条商品折让、削价 …… 业务规则 …… 5.计算应收金额的规则:************ ……
- (4)界面跳转不是扩展
现在软件系统的图形界面上往往布满了链接,执行者在任何步骤都可以 选中某个链接,系统立即跳转到其他用例的界面。不能把这些跳转当作 扩展,否则任何步骤都会有扩展。 在书写用例规约时,应该把具体的界面看作不存在,把其他用例也看作 不存在,专注于典型执行者为了达到本用例目标必须要和系统发生的交 互以及不可避免要处理的意外和分支。看下面的例子:
1.会员选择订单 2.系统反馈订单明细 3.会员可以取消订单 4.会员请求结算 5.系统反馈结算界面 …… 扩展 3a.会员取消订单: 3a1.会员请求取消订单 3a2.系统取消订单
在本书上一版中,我认为这样写是合适的,但现在我认为不合适,因为 这样写很容易掉入“可以这样做”的陷阱(参见第5章取款机治疗小崔失眠 的片段)。事实上,进行到步骤4或5时改主意取消也是可以的。那么, 可不可以像下面这样写呢?
*a.会员取消订单: *a1.会员请求取消订单 *a2.系统取消订单
这样写的意思是在任何一个步骤都可以取消订单,但是这样还是不合 适。如果这样写可以的话,任何一个步骤都可以跳转到“设置账户”也要 写了。“取消订单”是另一个用例。在具体的设计中,只要符合用例的前 置条件,可以在任何地方开始“取消订单”用例,但是这个用例和“会员→ 结算”用例不是扩展关系。
6.1.5 补充约束
路径步骤里描述的需求是不完整的。例如:
用例名:发布讲座消息 …… 1.工作人员输入讲座信息,请求发布 2.系统验证讲座信息充分 3.系统生成发布内容 4.系统请求短信平台发布信息 5.系统保存讲座信息和发布情况 6.系统反馈信息已经保存并发布 ……
步骤1中“讲座信息”包括哪些内容?需要添加字段列表。步骤2中“充分”指 什么?需要添加业务规则。从步骤1到步骤6有没有速度上的要求?需要 添加质量需求。
如果补充约束的内容只和单个用例相关,可以直接放在该用例的规约 中;如果补充约束适用于多个用例,可以单独集中到另外的地方,从用 例规约引用。
补充约束前面的编号不代表顺序,而表示该约束绑定的步骤的编号。以 上面“发布讲座消息”用例为例,如果有这样的补充约束:
5.发布情况=发布时间+工作人员
表示这一条约束是步骤5“系统保存讲座信息和发布情况”的补充约束。 如果某条补充约束不是针对某一步骤,而是针对多个步骤甚至整个用 例,前面的编号可以用“*”。
补充约束的类型可用类图表示,如图6-22所示。
text
图6-22 用例的补充约束
@startuml
hide empty members
class 补充约束
class 字段列表
class 业务规则
class 质量需求
class 设计约束
class 可用性
class 可靠性
class 性能
class 可支持性
字段列表 --|> 补充约束
业务规则 --|> 补充约束
质量需求 --|> 补充约束
设计约束 --|> 补充约束
可用性 --|>质量需求
可靠性 --|>质量需求
性能 --|>质量需求
可支持性 --|>质量需求
@enduml
6.1.5.1 字段列表
字段列表用来描述步骤里某个领域概念的细节。例如上面“发布讲座消 息”用例的步骤中,步骤1、3、5都需要分别添加字段列表。
字段列表可以用自然语言表达,例如:
字段列表 1.讲座信息包括:举办时间、地点、专家信息、主题、简介。专家 信息包括:姓名、单位、头衔。
也可以用符号表达,例如:
字段列表 1.讲座信息=举办时间+地点+专家+主题+简介
1.专家=姓名+单位+头衔 表示的符号可以采用过去数据字典常用的符号。例如:“+”表示数据序 列,“()”表示可选项,“{}”表示多个,“[| | | ]”表示可能的取值。例 如:
注册信息=公司名+联系人+电话+{联系地址} 联系地址=州+城市+街道+(邮编) 保存信息=注册信息+注册时间 客房状态=[空闲|已预定|占用|维修中]
字段列表写到涉众有共识就可以,并不是越“细”越好。例如,说到“电话 号码”,所有涉众都知道指的是什么,不必再做进一步说明,如果写 成“电话号码varchar(255)”,那反而没有共识了,因为涉众不了解这样 做是好是坏。
字段列表不同于数据模型。有的人为了省事,直接贴上一个数据模型 图,这是不正确的。不同的用例,不同的步骤,涉及的输入输出信息不 同。数据模型是设计,设计应该来源于需求,而非空想一个设计,然后 把它当成需求。
字段列表不等于数据字典。过去的开发方法学会有“数据字典”这样的工 件,本书不推荐花时间做这个工件,因为它会容易让建模人员过早把时 间花在细节上,造成一种做了很多事情的错觉,其实还没触碰到核心域 真正的难题。
6.1.5.2 业务规则
业务规则描述步骤中系统运算的一些规则,例如上面“发布讲座消息”用 例的步骤2中的“充分”没有说清楚,需要添加业务规则,例如:
业务规则 2.必须有的项包括:时间、地点、专家、主题
如果用文字说明业务规则比较困难,可以使用一些辅助的手段,例如决 策表、决策树。
只要涉众能理解,行业上适用的任何方式(例如数学、物理公式)都可 以用来表达业务规则。
描述业务规则时要注意的是:业务规则不等于实现算法。业务规则是需 求的一种,也是从涉众的视角看“不这样不行”的。例如,研究一款为盲 人或残疾人而做的语音输入软件,用例规约有如下片断:
3.系统将语音输入翻译为文字 …… 业务规则 3.采用××识别算法 ……
这条业务规则可能是有问题的,如果前排涉众是盲人或残疾人,他们不 知道什么叫“××识别算法”,也不在意是否用了这个算法,所以这不是需 求,删掉它,然后问“为什么”,得到涉众真正在意的需求:“背景噪音强 度为××的情况下,识别率应在××以上”。
当然,如果涉众的排位发生变化,例如该软件的初衷是为某个厂家推广 它的识别技术,那么“采用××识别算法”也可以成为需求,“背景噪音强度 为××的情况下,识别率应在××以上”反而不是了。
6.1.5.3 质量需求
按传统的需求分类,用例、路径、步骤、字段列表和业务规则可以归属 于功能需求。系统满足功能需求,说明系统能把事情做正确。在做正确 的基础上,系统还需要在做的过程中满足一些指标,这些指标就是质量 需求。
“质量需求”在包括本书上一版在内的很多书里被称为“非功能需求”,本书 统一称为“质量需求”。产品的竞争往往先从功能开始,当类似产品越来 越多时,质量需求可能就成为激烈竞争的决胜点。
- 可用性
可用性需求是对人类执行者和系统之间交互质量的度量。如果系统仅能 正确达到用例目标,但交互太繁琐,人类执行者是不喜欢用的。这里提 到“人类执行者”,说明可用性需求仅和主执行者是人的用例相关,毕竟 机器不会因为交互繁琐而感到烦躁。
在表达可用性需求时,仅仅说“系统应容易使用”是不行的。对年轻人容 易的,对老太太容易吗?对篮球运动员容易的,对普通人容易吗?合适 的可用性需求应该是可度量的,例如:
平均5次操作之内能完成客人入住
也要防止另一种错误:直接画一个界面贴上去就当成可用性需求。关于 界面是不是需求,在本章前面部分已经有阐述。
- 性能
性能包括速度、容量、能力等,例如: 系统应在0.5秒之内拍摄超速车的照片(速度)
应允许1000个执行者同时使用此用例(容量)
在标准工作负荷下,系统的CPU占用率应少于50%(能力)
在寻找质量需求时,性能类型的质量需求往往是最多的。
- 可靠性
可靠性表示系统的安全性和完整性,通常用平均无故障时间(MTBF, Mean Time Between Failures ) 和 平 均 修 复 时 间 ( MTTR, Mean Time To Repair)表示。
可靠性需求往往不是针对单个用例,而是针对整个系统,可以在所有用 例规约的最后,单独用小篇幅描述。
- 可支持性
可支持性表示系统升级和修复的能力。例如:
95%的紧急错误应能在30工作时内修复
在修复故障时,未修复的相关缺陷平均数应小于0.5
升级新版本时,应保存所有系统设置和个人设置
可支持性有时会被需求人员写成解决方案。例如,“系统应采用面向对象 的方式开发”,涉众根本不清楚面向对象为何物以及和搞对象有什么区 别,这不是合适的需求,背后的需求还是可支持性。
和可靠性一样,可支持性需求往往不是针对单个用例,而是针对整个系 统,可以在所有用例规约的最后,单独用小篇幅描述。
以上介绍了质量需求的种类。很多时候质量需求不用刻意去寻找,按照 前面说过的“不这样行吗”的标准,把混入需求的设计删掉,然后问为什 么,背后往往隐含的就是质量需求。
6.1.5.4 设计约束
设计约束是在实现系统时必须要遵守的一些约束,包括界面样式、报表 格式、平台、语言等。
设计约束既不是功能需求,也不是质量需求。例如,“用Oracle数据库保 存数据”,其实用DB2也可以满足同样的功能需求和质量需求,但必须要 用Oracle,因为客户已经采购了许多Oracle数据库软件,如果不用,成本 就会增加。
设计约束是需求的一种,也一样要从涉众的视角来描述。在很多需求规 约中,不少来自开发人员视角的设计伪装成设计约束,混进了需求的队 伍。例如前些年相当时髦的说法“系统应采用三层架构方式搭建”,涉众 并不了解“三层”好在哪里,为什么不是四层、五层?或者一层、二层? 删掉它,然后问“为什么”,背后的真正需求可能还是性能需求。
还有这样的假“设计约束”:
录单界面应分为3个页面,每个页面填写完毕,单击“下一步”,出现 下一页面
这也是来自开发人员视角的设计,不是需求。同样问:为什么要分三个 页面?回答是“一个页面放太多信息,加载太慢,涉众等待太久”,真正 的需求可能是以下性能需求:
系统应在3秒内显示录单界面
需求是问题,设计是解决方案,二者稳定性不同。就拿上面的“分3个页 面”为例,过去网速慢,为了快点显示,“3个页面”的解决方案是合适的, 现在网速快了,单个页面更好,这样可以减少操作的次数,但“3秒内显 示”的需求没有变,它只和涉众的耐心有关。
6.2 【案例和工具操作】系统用例规约
结合愿景,我们可以推测“助理→创建公开课”这个用例优先级应该最 高。它的用例规约如下: 用例编号:UC1 用例名: 创建公开课 执行者: 助理(主)、官网服务器(辅)、微信公众号系统(辅) 前置条件: 无 后置条件: 已请求官网服务器接收公开课网页文件 已请求微信公众号系统发布公开课消息 公开课信息以及发布情况已保存 涉众利益: 专家——担心公开课通知中涉及自己的信息不准确,损害自己的声 誉
学员——担心收到太多和自己不相关的信息;担心同样的信息收到 多次
助理——担心工作量大;担心网页文件放到服务器错误的位置;担 心公众号当日发送指标已经用完
官网服务器管理员——担心自己维护的系统受影响发生故障
微信公众号系统管理员——担心自己维护的系统受影响发生故障
基本路径: 1.助理请求开始创建公开课 2.系统反馈可以开课的课程主题 3.助理选择课程 4.系统反馈课程详细信息并要求补充其他公开课信息 5.助理提交公开课信息 6.系统验证公开课信息充分、合法 7.系统保存公开课信息,生成并保存公开课网页 8.系统请求官网服务器接收文件 9.系统请求微信公众号系统发布消息 10.系统保存公开课发布情况 11.系统反馈公开课发布情况 扩展路径: 2a.没有可以开课的课程: 2a1.【创建课程】 2a2.返回4 6a.公开课信息不充分或不合法: 6a1.系统反馈公开课信息不充分或不合法内容 6a2.返回5
字段列表: 4.课程详细信息=课程主题+学员对象+专家介绍+课程大纲+费用+ {报名联系方法}+{交费方法} 5.提交公开课信息=4+开始时间+结束日期+城市 7.保存的公开课信息=5+期号+创建时间+创建人 8.网页信息同5