杨德仁,王晓峰,刘建平,韩 强
(1.宁夏医科大学 理学院,宁夏 银川 750004;2.北方民族大学 计算机科学与工程学院,宁夏 银川 750021)
软件工程的难点在于软件的复杂性[1]和软件需求的不确定性[2]。前者可通过推迟实施及规范化软件过程加以缓解[3],后者可通过应用敏捷框架来解决[2,4]。但规范化软件过程容易导致设计麻痹问题,敏捷化会导致论域模糊化等问题。以用户故事(User Stories)为线索,有机结合敏捷框架与传统软件过程不失为一种选择性优化方法,其应用实践(即工程实践与教学实践)值得探索[4]。
针对软件开发商过分注重软件开发周期的规划与文档化,而忽视了至关重要的问题,即如何满足客户需求,2001 年17 位软件领域的专家提出了敏捷概念,开启了敏捷开发的新纪元,并颁布了敏捷开发宣言。该宣言倡导:个人与交互胜过过程和工具;可工作的软件胜过全面的文档;客户合作胜过合同谈判;响应变化胜过遵循计划,其中3 条涉及客户(用户)及其需求。根据该宣言还制定了12 条敏捷原则[5],其中大多数原则涉及客户(用户)及其需求或敏捷团队,诸如:尽早及持续性交付有价值的软件以满足客户需求;拥抱需求变化,即使在开发后期;通过敏捷过程以驾驭变化,为客户赢得竞争优势;在执行项目过程中,业务人员和开发人员必须每天协同工作;面对面的交流是向开发团队内外传递信息最有效率且效果最好的方法;敏捷过程提倡可持续开发,投资者、开发者和用户应维持稳定的开发速度;最好的架构、需求和设计来自于自组织团队;团队需定期反省如何能更有效地工作,然后相应调整其行为。其余原则涉及到产品的敏捷交付,诸如:频繁地交付可工作的软件,交付周期为几周到几个月,周期越短越好;项目建设要围绕着有推动力的团队成员,提供其所需的环境和支援,并给予信任;可工作的软件是衡量项目进度的主要标准;持续追求技术上的精益求精与良好的设计,以增强敏捷性;以简洁为本,这是尽量减少不必要工作量的艺术。
因此,敏捷框架的核心是以人为本的敏捷团队,需要用户全程参与,以克服传统软件过程因用户的有限参与而导致软件产品与其需求不一致的问题。用户参与的驱动力之一是讲好用户故事,从而更好地探索软件需求及其解决方案[2]。例如,在Scrum 框架中把用户故事作为其产品订单(Product Backlog)项或冲刺订单(SprintBacklog)项[6],在看板中把用户故事作为工作流中的在制品(Work In Progress/WIP)[7]。正是基于用户故事,Scrum 团队可更好地评估与规划sprint 计划,以实现准确的预测及更好的敏捷性,看板团队还可进一步细化其工作流。
用户故事及其成功应用奠定了其在敏捷框架中的核心地位,也启示着其在传统软件开发过程中的扩展性应用,促进了敏捷框架与传统软件开发过程的融合。但实际上,应用用户故事并非一蹴而就,相关机制需要不断进行拓展与细化。
在软件工程中,用户(User)指软件的使用者。用户概念很重要,其是建模的视角之一,但也总是模糊不清,极易与客户、角色等概念混淆。
在敏捷框架语境中,根据用户故事的定义(参见2.1节),用户基于角色叙述使用系统的故事。用户是个抽象概念,不能一概而论,用户因其角色而异。例如,业务人员及其客户在使用购物软件时便扮演着不同角色。
UML 规定了用例用于捕获软件(系统)需求,即系统应该做什么,其关键概念是参与者(Actors)、用例和主题[8]。主题代表用例所应用的待建系统,与该主题交互的用户、硬件及其它任何系统角色都被视为参与者。参与者并非具体的物理实体,而是实体所扮演的角色。实体包括人类用户、外部硬件或其他系统。因此,一个实体可扮演多个角色,一个角色可由多个实体扮演。
Dines[9]提出软件工程的三段论,即(业务)域工程、需求工程和软件设计,建议在开发早期要尽力罗列(业务)域涉众(Stakeholder)及其角色和权益,并基于涉众视角进行建模。其还指出在整个工程期间,要基于具体论域,例如需求域、分析域和设计域,不断更新与修正涉众角色,尤其在需求启发阶段。
Peter 等[10]提出彩色UML 建模方法,并认为(业务)域通用模型包括4 种基本架构型(Archetypes),并用不同颜色表示。其中,时刻—时段(Moment-Interval/MI)代表待处理或跟踪在某时刻或某时段内发生的业务,以提醒建模者寻找问题域中的重要时刻或时段,用醒目的粉色表示,因其将各组件联系在一起,处于核心与灵魂地位。角色(Role)代表参与者的参与方式,用黄色表示。描述(Description)类似于目录和类别,用蓝色表示。角色扮演者(PartyPlaceThing/PPT)指个人或组织、地点或事物,用绿色表示。PPT 和角色具有一对多与多对一关系,例如:一个事物在制造过程中扮演一个角色,而在营销过程中又扮演另一个角色,一个人可能既是雇员又是客户,一个店面既可以是零售店,也可以是批发店。
Jacobson 等[11]提出的用例2.0 软件方法以讲故事和按片构造系统为原则,并把用户故事定义为用例切片以驱动软件开发。在用例2.0 中,用户故事被作为用例切片进行迭代开发,而失去了探索软件需求的意义。
在上述方法中,角色的体现形式及应用范围不一,具体如表1 所示。
Table 1 Roles and corresponding manifestations and applications表1 角色及其体现形式与应用范围
Resketi 等[12]提出一种概括用户故事的方法,借助于修正的词和动词解析器,提取关键字与关键动词的集合,自动生成用户故事,之后由专家进行改进,以备在未来开发相似的系统中重用。
用户故事作为探索需求的基础与手段,也被扩展到传统软件开发过程中。基于MDA 的模型转化理念[13],采用自然语言处理技术,Meryem 等[14]提出一种将用户故事转换为用例的过程,而忽视了用户故事与用例不在一个抽象层次。Samia 等[15]探索直接从用户故事提取设计层次类图的方法,但这种类图缺乏软件的控制类和窗体类,其完整性值得商榷。
上述研究为应用用户故事奠定了基础,但除Peter 等[10]的架构型和Dines[9]的三段论外,其它研究均未涉及业务域。认知与解决软件的复杂性必须基于其应用的业务域,这是彩色UML 建模、领域驱动的设计[16]及三段论等新型软件开发方法所提倡的。
基于笔者提出的双论域层次化软件建模框架[17],本文拟探索用户故事的来源、扩展及其建模机制。
在软件开发与项目管理过程中,需要以日常语言或商务用语编写句子式的用户故事。其只要求写出最有价值而不能被忘记的用户期望,以帮助确定软件需求、估算工作量以及与客户沟通。
用户描述是敏捷框架中最小的工作单元,其是从软件用户角度表达的最终目标,而不是特性(用户需求)。用户故事是从最终用户或客户角度编写的针对软件特性非正式、一般的解释。用户故事的目的是阐明一项工作将如何向客户交付具体价值。
用户故事用简单语句来表示,其定义及模板为:As a[persona],I[want to],[so that][2,4,7],即:作为<某角色>,我<想做>,<以实现>。其语义如下所述:
作为某角色:描述在为谁建造软件,这不是头衔职位,而是人物角色。团队应该对该角色有共识,并希望采访他以了解其工作方式。
想做:描述用户意图,即要达到的目的。其并非使用功能,也无实施细节,例如图形用户界面。
以便:描述待做的事情要符合的大局,即总利益或要解决的大问题,这也是衡量其优先度的标准。
值得注意的是,一个用户故事只能有一个用户角色且只做一件事,以便实现一个用户目标。
用户故事描述用户操作软件的简单情境,以便开发者与客户进行有效沟通,并尽快贴近用户真实需求。通过这种对使用情境的描述,客户可以轻松排定其优先顺序,即按照重要性依次为:必需部分(Must Have)、应有部分(Should Have)和最好有部分(Nice to Have)。在敏捷迭代过程中,先做必需部分,再做应有部分,可暂时不做最好有部分[4]。
用户故事有助于将关注点从编写需求转移到讨论需求。除书面语句外,其作为启发需求的手段,本身只是一个约定,需要与用户展开一系列对话以探索并澄清需求。因此,Jeffries 等[18]总结了开发用户故事的“3C”原则,即卡片(Card)、对话(Conversation)和确认(Confirmation)。要求把用户故事写在记事卡上,以记录概述、估算工作量等,在计划或估算时则需要故事的细节性对话,以测试与验收方式确认故事的完整性和正确性。
用户故事应具备6 个属性,即独立性、可协商性、有价值性、可预测性、短小精悍以及可测试性。Bill 使用这些属性的首字符缩写词INVEST 表示用户故事的评估标准[19]。
独立性:尽可能避免故事之间产生依赖关系,否则会导致优先级和规划问题。
可协商性:故事是可协商的,不必是书面合同或者需求。
有价值性:让用户编写故事,确保故事有价值。
可预测性:开发者应能预测故事规模以及实施所需时间。
短小精悍:应在一个冲刺周期内完成,为此需要分解史诗级用户故事,即epic。
可测试性:故事必须是可测试与验证的。
用户故事通常只是口头性描述而无法精准反映出软件需求,并因碎片化而呈现出一些局限性。具体而言,一是在现实中用户所要非所需,即使所要是所需,软件需求也会随着市场变化而改变;二是在设计系统前,用户故事其实只是用户期盼;三是用户故事没有包含待更正的系统缺陷;四是层次不明,在系统开发之前,其实只有业务工人及客户,即用户的体现因其论域而异;五是用户故事只是零碎的使用情景设想,抽象层次不高,容易陷入细节而难免顾此失彼[4],用户故事也不同于用例,充其量只对应于用例的常用路径,而没有顾及用例的备用路径和容错路径;六是用户故事中的用户与业务脱节而无法溯源。
因此,作为软件需求的探索机制,用户故事及其应用需要进行向上溯源与向下扩展实践探索。
针对用户故事的上述局限性,有必要探究其在软件开发过程中的各种体现形式及其实践机制,以及源泉和演化机制。
若只从软件使用层面描述用户设想,用户故事则显得唐突和不足。其实,用户故事并非只是涉及软件用户的故事,因此“用户”应扩展为“角色”。远离业务的用户故事无助于确定软件需求,况且在业务层面上软件用户角色尚不存在,只有客户角色和业务工人角色。客户有业务需求,业务工人有满足该需求的责任和义务,可借鉴销售员角色加以实施。
在软件需求层次,用户有使用软件的宏观需求,即软件功能。用户来源于上述客户和业务工人,此外还来源于软件维护人员,而这种宏观需求不能脱离其业务语境。在软件分析层次,用户有使用软件的具体路径,这便是传统用户故事或用例事件路径的内涵。如上所述,在用例2.0中,这种用户故事被定义为用例切片[11]。在实施层面,开发者通过编程以满足用户故事,测试者检查软件功能及其缺陷。其中,测试者来源于软件用户和开发者。
经上述拓展与细化,形成了一种扩展的用户故事(an Extended User Stories/EUS),既体现在不同层面(论域),又被分解为各论域中的相应角色,例如业务层面的客户与工人,以及软件层面的用户、开发者与测试者,如图1、图2 所示。
相应地,这种扩展的用户故事格式应有所调整,例如:作为<客户>,我<想>,<以便>;作为<业务工人>,<我想>,<以便>,依次类推。值得指出的是,这种故事还应与其论域及层次性相吻合。
Fig.1 Schematic diagram of RUS and its application图1 RUS 及其应用示意图
Fig.2 Schematic diagram of roles’overlap图2 角色重叠性示意图
基于图1 所示的角色来源及其重叠性,“用户”角色的演变历程如图3 所示。软件用户来源于客户和业务工人,测试者来源于开发者和用户。
Fig.3 Schematic diagram of“user”role and its evolution图3 “用户”角色及其演变示意图
由图3 可知,有些角色出现在不同层次上,其相应的故事粒度也不同,换言之,EUS 具有层次性。例如客户和工人出现在业务域的不同抽象层次上,其故事即要做的事情和目的则各不相同,在软件域中的用户故事也一样。参见本文3.3 节的实践集及其案例中的论述。
在软件工程项目实践与教学实践中,以EUS 为线索驱动软件开发,相关路径需要作进一步探索。
3.3.1 EUS 工程实践路径
在业务域,业务客户和业务工人是关键角色,有必要确定客户的业务需求和业务工人的业务服务。在软件需求域,软件用户是关键角色。基于客户、业务工人和软件管理者等视角,确定用户角色及其软件需求,这种需求是高层次的抽象需求。在软件分析域,让用户叙述传统意义下的用户故事,并实施优先度排序。
若有必要,在设计域,设计师设计软件开发的蓝图,例如面向对象的静态模型(类图)、动态模型(序列图和状态机图)和数据库表模型等。在实施域(编码和测试),开发者(程序员)进行编码,测试者制定测试案例并根据软件分析域中的用户故事(用例切片)进行测试,以发现其缺陷。
3.3.2 EUS 教学实践路径
在软件工程课程实践中一般通过分组实施课程项目,以培养团队的协作精神。根据项目需要,小组成员在各个论域中扮演不同角色,以便讲好相应故事。若扮演角色有困难,可采用业务域的实践集(参见3.3 节)或(头脑)事件风暴会议的形式[20]。
除扮演角色外,项目小组还应设置组长和秘书角色,以便协调团队工作并记录设计结果。
实践集是敏捷框架的关键要素之一,有助于克服传统软件开发过程中的设计麻痹问题[2]。论域建模,即业务域、需求域、分析域和设计域建模都需要相应的实践集[4]。现以业务域为例,探索并给出其实践集。
3.4.1 业务域实践集框架
在业务域,用户角色包括顾客、业务工人(可细分为主控业务工人、辅助业务工人)等,这些用户故事描述相关涉众(或称为参与者)在业务域中的关键行为。相关故事其实在描述涉众及其需求或事务(动作),其中客户故事分为业务需求故事和业务参与故事。实践集主要包括以下内容:
(1)责任驱动设计。每个涉众都有其需求或责任,在业务域中,实现客户需求正是业务服务提供者的责任。各涉众也有其责任或行为,主要分为事务级和动作级两个层次[21]。
(2)业务域建模风暴。具体细化为业务目标建模、业务状态建模、业务事务建模及其编排、业务事务分解及其动作建模等步骤。
(3)业务需求建模。基于客户视角为客户需求建模。
(4)业务状态建模。基于业务实施过程中关键信息子(诸如单据和报表等)的变化,确定业务状态及其转化关系。
(5)业务事务建模及编排。为上述各转化关系指定事务,通过事务的实施促使状态转化,同时识别事务实施者即执行人。事务其实隶属于过程中的主体与变体,即人人都有责任。之后,确定事务顺序和优先级别,一般由主控业务工人确定,如门诊业务中的坐诊大夫。业务事务其实是业务过程的高级抽象,因此还需要进行分解与细化,参见下述的动作建模。
(6)动作建模。参照事务三段论即准备、执行与递交结果,将事务分解为动作集[21],再确定各动作执行者,其参考基线是价值链中的活动。动作还需要完善,如同函数需要参数化,动作需要业务对象和信息子,其结果是业务过程模型。其中,业务对象是软件对象的基础,而业务需求者和参与者、信息子及其信息化处理是获取软件需求的基础。
除普适性业务语言外,业务域建模还可采用UML、BPMN 或CMMN,甚至便签,其它域的实践集可参照业务域的实践集制定[17]。
3.4.2 医院门诊业务实践集案例
以医院门诊业务为例,列出其扩展的用户及其事务。扩展的用户角色为:客户即患者,主业务工人为坐诊大夫,辅助业务工人为收费员、化验员、技师和护士等。相应事务为患者就诊、坐诊大夫接诊与治疗、收费员收费、化验员化验、技师拍片或治疗及护士引导等。
事务分解以化验为例,坐诊大夫开化验单,患者缴费,化验员化验并给出结果[21],其它事务可据此进行相应分解。
软件需求是软件开发的基础,而软件需求通常难以确定,即使用户也难以表述清楚,加上市场竞争等因素影响,软件需求会不断发生变化。在迭代开发的基础上,敏捷开发旨在组建业务(用户)代表全程参与的敏捷团队以拥抱需求变化。敏捷框架已成为软件开发的主流技术,旨在为用户提供最大价值。团队用普适(业务)语言交流,以不断提供的产品增量衡量项目进展。但敏捷框架呈现出模型层次不明晰或缩水等现象,混淆了不同论域的元素,超出了人们理解与解决问题的极限,违背了抽象与层次化设计原理,可能会弄巧成拙,增加软件的偶然复杂性,进而导致软件开发陷入“大泥球”。若基于传统软件开发方法如责任驱动的软件开发方法,融角色责任与软件责任于一体进行探索,则不失为一种有益尝试,将是未来研究方向之一[22]。
目前一些知名的IT 国际咨询机构,如雅各布森国际、Rebecca Wirfs-Brock 协会都在进行敏捷方法与传统方法融合实践的探索及推广。这种敏捷框架与传统软件开发过程的融合趋势值得国内业界、学术界和教育界重点关注[17]。