在先启阶段,我们确定了 EAS 的问题域与核心的业务流程,然后根据业务期望与愿景确定项目的业务范围,明确史诗级故事和主故事。这个过程既有利于我们对项目的整体理解,以便于确定需求列表、排定需求的优先级从而制订发布与迭代计划,又利于对领域进行建模,确定限界上下文和上下文映射,进而设计整个系统的架构。同时,我们又要准确地把握“故事(Story)”的粒度,不至于沉入到过分细粒度的需求实现细节,影响了先启阶段的实施进度。
所谓故事的层次(粒度)并没有固定的标准,在用户故事地图中,提出了三个层次:
- 用户活动
- 用户任务
- 用户故事
这里提到的用户活动就相当于史诗级故事,组成用户活动的用户任务相当于主故事,再按照 INVEST 原则继续对其进行分解,就可以获得在敏捷迭代中构成开发任务的用户故事。
- 用例尤其是用例图的抽象能力更强,更擅长于对系统整体需求进行场景分析;
- 用户故事提供了场景分析的固定模式,善于表达具体场景的业务细节;
- 测试驱动开发则强调对业务的分解,利用编写测试用例的形式驱动领域建模,即使不采用测试先行,让开发者转换为调用者角度去思考领域对象及行为,也是一种很好的建模思想与方法。
因此,我个人比较倾向于在先启阶段的需求分析过程中,使用用例来表述领域场景。恰好在 Cockburn 的著作《有效编写用例》中,他提到用例的层次包括:概要目标、用户目标和子功能。例如:
这里的用户目标就代表着具有业务价值的领域场景,也就是我们需要识别出来的主用例,它由多个子功能组成,它们之间的关系就是主故事与用户故事之间的差别。结合前面分析的问题域和业务流程,我们可以初步获得 EAS 的史诗级故事与主故事。
史诗级故事和主故事
结合 EAS 的业务愿景和核心流程,我们通过深入地需求调研,获得了 EAS 的史诗级故事和主故事。
管理客户关系
通过对客户全方位信息的统一管理,可以实现市场部工作人员、需求承担部门之间快捷、方便的信息共享,提高工作效率,并且可为集团负责人提供最实时、有效的客户信息,包括潜在客户的信息。这些信息包括客户基本信息、市场部拜访客户的记录还有客户活动记录、客户的背景资料以及客户公司的商务负责人资料。
管理客户关系的主要目的是改进和维护客户关系,因此它包括如下主故事:
- 管理潜在客户信息
- 管理客户信息
- 对客户进行分类
- 查询客户信息
- 客户满意度调查
- 维护拜访记录
- 维护客户活动记录
管理市场需求
市场人员可以收集市场需求,并与客户接触,明确这些市场需求。在创建市场需求后,需要对市场需求进行评估,进行财务核算,从而确定需求订单和客户需求,确定需求承担者。市场人员应随时跟踪需求订单的状态,并及时向客户反馈。同时,市场人员还可以查询市场需求和需求订单。包括的主故事有:
- 录入市场需求
- 查询市场需求
- 修改市场需求
- 评估市场需求
- 创建需求订单
- 指定客户需求的承担者
- 跟踪需求订单状态
- 更新需求订单状态
管理商务合同
签订的合同来自于需求订单,一个需求订单可能会创建多份商务合同。在正式签订合同之前,作为合同的创建者,可以向相关部门的负责人发起合同评审流程,并按照评审后的要求修改合同。为了便于对合同的管理,应提供查询合同与跟踪合同进展状态的功能。合同一旦经过甲方、乙方审批通过并正式签订后,就不允许任何角色和用户修改。如果要修改合同,应该是增加一份附加合同。包括如下主故事:
- 录入合同
- 添加附加合同
- 指定合同承担者
- 更新合同状态
- 为合同添加评论
管理员工
人力资源部负责对员工基本信息的管理,包括员工技能列表、语言技能、项目经验等,还要管理每位员工的日常考勤。根据组织结构的定义与授权,每位员工的直接管理者还要检查员工工作日志的填写情况,了解每位员工的工作状况。包括如下主故事:
- 管理员工基本信息
- 将储备人才转为正式员工
- 管理员工的劳务合同
- 追加员工的项目经历
- 考勤
- 填写工作日志
招聘人才
根据市场部的需求以及集团自我的发展,作为人力资源部的管理人员,需要制定招聘计划,更新和查询招聘状态。每次应聘人员的面试活动(包括电话面试、笔试、技术面试等)以及测评结果都需要记录下来归档。对于每一位应聘者,需要对投递过来的简历进行归档和录入。人力资源部的工作人员可以根据自己需要对储备人才进行分类,从而对简历进行分类管理。包括如下主故事:
- 制定招聘计划
- 审核招聘计划
- 修改招聘计划
- 查看招聘计划
- 删除招聘计划
- 输入面试记录与测评结果
- 管理储备人才信息
- 管理储备人才简历
管理项目
集团的项目有两种类型:承包项目和外派项目。不同项目类型的流程是不相同的。承包项目牵涉到对整个项目进度的跟踪,从需求到设计到开发实现和测试的全生命周期管理;外派项目则是人力资源外包,仅仅需要管理外派人员的工作情况即可。项目管理人员需要创建项目,根据项目类型和管理流程选择计划模板制订项目计划,并通过该模块查询和跟踪项目进展情况,更新项目状态。包括的主故事为:
- 创建项目
- 制订项目计划
- 创建迭代任务
- 分配任务给项目成员
- 更新项目状态
- 更新任务状态
- 为任务添加评论
- 查询项目情况
- 跟踪项目进度
- 查看指定迭代的所有任务
管理项目成员
一旦立项后,就可以为项目分配项目成员以及分配项目成员的角色,项目管理人员可以对项目成员的信息进行管理。包括如下主故事:
- 添加项目成员
- 移除项目成员
- 调整项目成员的角色
- 查看项目成员的任务状态
管理工位与硬件资源
作为服务中心的工作人员,可以管理公司现有的硬件资源信息以及工位信息。通过系统,可以将硬件资源与工位分配给集团的员工,若未分配,则为闲置硬件与工位。包括如下主故事:
- 管理硬件资源
- 管理工位
决策分析
作为集团的管理者,需要查看集团各部门的工作情况,包括需求订单情况、项目进展情况、人员利用率等综合报表,并结合各部门具体情况,定期提供日报表、周报表、月报表、季度报表和年报表。
运用用例分析方法
在先启阶段的领域场景分析过程中,我们可以运用用例分析方法对 EAS 进行需求分析。用例的驱动力是业务流程与参与者,参考的内容则为业已识别出来的史诗级故事和主故事。同时,在识别用例的过程中,还应该尽量通过用例表达领域知识,力求获得“统一语言”。典型的用例描述是一个动宾短语,体现了参与者在业务场景需要履行的职责,又或者是满足用例规格的业务行为。
为了保证用例分析方法的简洁,避免在先启阶段出现“分析瘫痪”,我将传统的用例分析方法分为两个步骤。在先启阶段进行领域场景分析时,只需要使用用例图,而非详尽的用例规格说明。至于用例的流程描述则过于死板和繁琐,我建议使用用户故事对需求进行阐述,并作为第二个步骤放在迭代开始后的领域驱动战术设计阶段。
在绘制用例图时,可以基于识别出来的史诗级故事来绘制,亦可以按照参与业务流程的参与者(Actor)来绘制。无论采用何种方法,这个过程都需要团队与领域专家通力合作,从业务而非技术实现的角度剖析领域需求,最后推导出真正能表达领域概念的用例图。
在这里,我展现的用例分析方法以参与者(Actor)为用例分析的起点,分析步骤为:
- 确定业务流程,通过业务流程识别参与者(Actor);
- 根据每个参与者识别属于该参与者的用例,遵循一个参与者一张用例图的原则,保证用例图的直观与清晰;
- 对识别出来的用例根据语义相关性和功能相关性进行分类,确定用例的主题边界,并对每个主题进行命名。
根据业务流程确定参与者
如果考虑 EAS 的核心业务流程,可以初步识别出如下参与者:
- 集团决策者
- 市场人员
- 子公司
- 财务
- 人事专员
- 招聘专员
- 人力资源总监
- 面试官
- 项目管理办公室
- 项目经理
- 项目成员
- 员工
- 部门经理
- 服务中心
在识别参与者(Actor)时,要注意以下问题。
- 参与者不一定是人,可以是一个系统、服务或模块,也可以是一个部门。例如,定时器可以根据事先设定的规则给相关人员发送通知,此时,定时器作为一个组件成为了参与者;项目管理办公室发起项目的立项,此时,项目管理办公室作为一个部门成为了参与者。
- 当参与者为同一部门的不同角色时,可以考虑参与者的泛化关系,也可以理解为完全不同的参与者。例如,招聘专员参与的用例包括“制定招聘计划”、“修改招聘计划”和“审核招聘计划”,但第三个用例只有人力资源总监才具有操作权限。这时,可以认为人力资源总监是招聘专员的一种特化,但亦可以视为两个完全不同的参与者。当人力资源总监在操作前两个用例时,本质是扮演了招聘专员这个参与者在执行。
- 参与者不同于设计模型中的角色(Role),前者来自领域场景,是真实业务场景的参与对象,后者是对职责的抽象。例如,“评论商品”用例的参与者,可以是买家和卖家,但在设计模型中,可以抽象为评论者角色。
根据参与者识别用例
在识别参与者时,一些用户体验设计的实践是为参与者建立一个用户画像(Persona),即给出更为具体的用户特征和属性,从而得到一个如身临其境一般的场景参与者,然后设身处地思考他或者她是如何参与到这个领域场景中的。无论是否建立用户画像,这种场景模拟的方式对于用例分析都是有帮助的。
市场人员的用例图
让我们首先思考“市场人员”这个参与者。作为一家软件外包的集团公司,它与产品销售公司不同,没有售前和售后人员来负责推销商品和开展售后维护,保持与客户之间的良好关系。市场部作为开拓市场、寻找客户合作机会、维持客户关系、开展需求合作谈判的职能部门,承担了需求管理、客户管理和合同管理的职责,而市场人员作为市场部员工,全程参与了从市场需求、客户洽谈到合同签署的整个市场活动全过程。因此,市场人员参与的用例几乎涵盖了客户关系管理与市场需求两个核心子领域。这些用例关系如下图所示:
在绘制这个用例图时,我主要参考了以下内容。
- 识别的主故事:分析这些主故事的用户目标是什么,进而就可以确定应该是哪个参与者发起该用例。
- 对市场人员的调研:与市场人员进行沟通,了解该角色目前的工作任务。
- 业务流程:从组成业务流程的各个环节判断参与者与功能之间的关系。
子公司的用例图
子公司在 EAS 中,主要作为需求的承担者。承担需求的工作属于项目管理的范畴,真正的参与者是项目经理和项目成员。在核心业务流程中,当市场人员在创建了市场需求后,要由该需求的承担者即子公司负责评估,签订合同时,也需要子公司确认。此时,子公司会以部门作为整体参与到领域场景中,用例图为:
在识别“确认合同履行”用例时,我们仔细分析了业务需求。由于子公司是合同的承担者,因此履行需求合约的乙方是子公司而非集团市场部。市场人员会作为需求的委托者草拟合同,并在 EAS 中负责创建合同及上传合同附件。合同的真正签署者是子公司,但这个签订的过程是线下行为,子公司领导只需要在 EAS 系统中完成合同的确认即可。
在子公司的用例图中,包含了“为合同添加评论”用例,它同时也是市场人员的用例。不同参与者使用相同的用例,这是完全正常的。但它也给我们传递了一个信号,就是在设计模型中,我们可以考虑为该用例抽象一个角色,如“合同评论者”。在编码实现时,该角色可能会作为一个权限角色,用以控制评论合同的功能权限,也可以考虑为其定义一个角色接口。
财务的用例图
财务中心的“财务”参与者也参与了市场需求的核心业务流程:
根据前面对系统上下文的定义,EAS 的业务范围并未包含工资结算、财务成本核算等。因此在用例图中,财务仅仅负责市场需求的财务核算。
人事专员的用例图
我将人力资源部中负责管理员工信息的参与者定义为“人事专员”,员工的基本信息管理与考勤都由他(她)来负责。其用例图为:
对于员工的管理,我最初定义的用例为“管理员工信息”;然而,“管理”这个词语稍显宽泛,无法准确表达领域行为。这种过于抽象的用例描述可能会导致我们忽略一些必要的领域概念,并让领域行为变得模糊化。经过与人事专员的沟通,我们一致认为在员工管理的场景中,对员工的管理其实包括以下内容。
- 办理员工入职:入职体现了领域概念,要好于新建员工的描述。
- 办理员工离职:离职体现了领域概念,要好于删除员工的描述,何况员工的离职未必一定要删除该员工记录。
- 录入员工信息:录入员工基本信息、项目经历、技能、语言能力等。
在主故事列表中,属于人事专员的职责还包括“追加项目经历”。然而,通过深入分析用例,我们发现该用例其实应该发生项目管理过程中,作为“添加项目成员”的扩展用例,一旦员工被加入到项目,就会被触发。
招聘专员的用例图
负责招聘的人力资源部员工被定义为“招聘专员”,用例图如下所示:
招聘专员在制定或修改招聘计划之后,需要由人力资源总监对计划进行审核,这是两个不同的参与者,人力资源总监的用例图为:
除了招聘专员会参与面试过程之外,人力资源部之外的其他员工可能会作为面试官参与面试。无论是招聘专员,还是面试官,都需要在面试之后输入面试记录与面试结果,故而引入了“面试官”参与者:
员工的用例图
集团的每一名员工都需要考勤和填报工作日志。注意在下图,我没有像人事专员与人力资源总监那样,将员工和部门经理定义为两个完全独立的参与者,而是采用泛化关系表达。仔细体味这之间的微妙差别。人力资源总监可以审核招聘计划,但却不会直接去制定或修改招聘计划,他(她)与人事专员之间有一个比较明显的层级关系,对应的是不同的权限。而部门经理就是一名员工,这种泛化关系是确定无疑的。
注意用例图中“查询打卡记录”和“查询出勤记录”之间的差异。打卡记录是考勤机每天留存的信息,出勤记录则是根据集团的考勤制度并结合员工的请假信息和打卡记录生成的记录内容。
工作日志定时器的用例图
这里还有一个特殊的参与者,在之前识别参与者时被忽略了,那就是提醒填报工作日志的定时器:
项目管理办公室的用例图
项目管理办公室是以部门作为参与者在项目管理场景中出现,它是整个项目的发起者、评审者,也只有它才有权终止项目或结束项目。项目管理办公室参与了整个项目管理流程的监督,但并不参与项目的具体活动:
“立项”与“结项”用例是项目流程中的关键节点,由项目管理办公室发起。当立项完成后,一个新的项目就会被创建;项目结项则意味着项目的状态发生变更。如果我们将用例命名为“创建新项目”、“更改项目信息”就不符合项目管理的统一语言。
注意,“通知项目经理”既作为了“评审项目计划”的扩展用例,又作为了“指定项目经理”的扩展用例。当然,在业务上,虽然同为通知,但通知的内容并不相同。在项目管理场景中,所有与通知有关的用例都作为扩展用例出现;事实上,在所有核心领域场景中,通知用例都不是主用例,毕竟它并不参与核心业务。
项目成员的用例图
项目成员与项目经理之间存在泛化关系,因为当项目经理在创建(编辑)一个问题(Issue)时,就是作为一名项目成员执行的操作;二者的差异还是角色不同导致的权限差异。项目成员的用例图如下所示:
我们在识别史诗级故事和主故事时,使用了“任务(Task)”来表达项目管理过程中分配给项目成员的工作;而在用例图中,我们却改为了“问题(Issue)”。“问题”是对任务、史诗故事、用户故事、缺陷的一个抽象,这是在项目管理领域中得到公认的领域概念。任务这个词语其实是与用户故事(User Story)、史诗故事(Epic)、缺陷(Defect)属于同一等级的概念,根据“单一抽象层次原则”,使用“任务”进行抽象显然不再合适。
当我们创建一个问题时,需要指定问题的基本属性,如问题的标题、描述、问题类型等。那么,问题所属的迭代、承担人(Owner)、报告人(Reporter)是否也作为问题的属性呢?我们在设计用例图时,确实困惑不已,甚至考虑过将上图中“指定问题所属的迭代”与“分配问题给项目成员”用例作为“创建问题”、“编辑问题”的包含用例。经过思索再三,最终还是认为这两个用例是有用户目标的,即提供了明显的业务价值,应该将其作为主用例,与项目成员之间存在“使用(Use)”关系。同样的,“更新问题状态”也没有出现在最初的用例图中,但实际上它与“编辑问题信息”有着完全不同的用户目标,有必要成为项目成员的主用例。
项目经理的用例图
在项目经理用例图中,“指定问题报告人”用例也是出于同样的考虑因素:
在项目经理的用例图中,最初我并没有识别出“跟踪问题进度”用例。后来,我发现我将“查询问题”与“跟踪问题进度”二者混为一谈了,这其实是不正确的。“查询问题”用例是查询符合各种搜索条件的问题,例如查询当前迭代的所有问题,查询当前迭代所有未完成的问题,查询项目成员的所有问题等;“跟踪问题进度”的着眼点是了解当前问题的完成情况,是对进度的跟踪;二者有着不同的用户目标。
服务中心的用例图
“服务中心”也是一个部门作为领域场景的参与者,该参与者的用例非常清晰,就是针对工位和硬件资源的管理:
集团决策者的用例图
最后是“集团决策者”,该参与者的用例主要是查看表达供需关系的统计报表:
就像写真时,为求画面的真实准确,必须寻找一个唯一的坐标一样,绘制用例图的唯一参考坐标就是参与者(Actor)。每个参与者的用例图或许大小不一,粒度不均,但自身是完全独立的,参与者之间(除了存在泛化关系的参与者)的用例图互不干扰,清晰地勾勒出各自观察视角得到的领域行为。
如何有效地识别参与者的用例
前述内容通过用例形式将所有的主故事都转换成了与参与者有关的用例,那么,在识别用例时,是否有什么经验可循呢?
用例关系的确定
一个用例图,往往体现了参与者与用例之间的使用关系,用例与用例之间的包含或扩展关系,有时候还存在用例之间的泛化关系,确定用例之间的关系很重要。在识别用例时,思考参与者与用例之间的关系会成为一个不错的设计起点。尤其在先启阶段,我们识别的用例体现了 Cockburn 提出的用例层次中的用户目标层,这恰好对应用例与参与者的“使用(Use)”关系。从领域场景分析的角度看,这个使用关系代表了业务价值。在确定了参与者后,你就可以结合主故事与领域场景,询问自己:“在这个领域场景下,该参与者的用户目标是什么?”由此,可以帮助我们确定该用例是否主用例。
正如对项目用例图中的分析,如果考虑编码实现的本质,则问题所属迭代、承担人以及问题状态都是问题(Issue)的属性;然而在用例图中,我却以“指定问题所属的迭代”、“分配问题给项目成员”、“更新问题状态”此三个主用例与“编辑问题信息”平级,因为它们在项目管理中都具有不可替代的业务价值。
与之相反,包含用例与扩展用例是为具有业务价值的主用例提供支持和服务的,识别它们既可以丰富和完善业务逻辑,又可以在后续的用例边界找到属于通用子领域或支撑子领域的业务内容。这些不直接提供业务价值的用例恰好可能组成单独的限界上下文。例如,在前面给出的诸多用例图中,诸如“上传附件”、“通知评估人”等用例主要以扩展用例的形式呈现,这些扩展用例体现了各自内聚的关注点,即文件共享与消息通知。
包含用例与扩展用例之间的区别在于两个用例之间的“粘性”。包含用例为主用例不可缺少之业务环节,如“指定项目经理”包含用例之于“立项”主用例,如果缺少了指定项目经理操作,立项就是不完整的。扩展用例为主用例功能之补充,如“通知立项”扩展用例之于“立项”主用例,即使没有通知立项的相关干系人,也不妨碍立项工作的完成。作为包含用例或扩展用例本身,又可以有属于自己的包含用例或扩展用例,例如“通知项目经理”对“指定项目经理”的扩展:
从功能相关性看,“立项”与“指定项目经理”用例是强相关的,“通知立项”与“立项”用例是弱相关的。因此,对包含和扩展用例的识别往往会影响到后续对限界上下文的识别。
在识别用例图时,还要注意避免错误的用例关系识别。例如,在项目管理用例图中,团队最初为项目成员参与者识别出“接收问题分配”用例。结合业务场景对此进行检验:当项目经理将问题分配给项目成员后,在业务上确乎存在接受问题的行为;但该行为其实是一个线下行为,属于项目成员之间的一个口头表达;当问题分配给项目成员之后,就已经意味着该问题已经被项目成员接受。因此,这个用例是不合理的。
用例名应字斟句酌
在领域场景分析过程中,如果我们只满足于用例图的获得,无异于买椟还珠。用例图仅仅是我们获得的分析结果,但更重要的是我们获得用例图的过程,这其中的关键在于团队与领域专家的交流与合作。作为UML(Unified Modeling Language,统一建模语言)组成部分的用例图,已经得到行业的认可。无论是没有技术背景的领域专家,还是没有业务背景的技术专家,都能很好理解用例图这种可视化的建模语言。
用例名是领域知识的呈现,更是统一语言的有效输入。用例名应采用动宾短语,描述时须字斟句酌,把握每一个动词和名词的精确,动词是领域行为的体现,名词是领域概念的象征,进而这些行为与概念就能再借助领域模型传递给设计模型,最终通过可读性好的代码来体现。当然,在给出中文用例的同时,还应提倡以英文来表述,毕竟在最终的代码层面,还是用英文来“说话”。
在项目管理用例图中,我们最初给出的用例为“查看问题完成情况”,但在项目管理领域,所谓“问题完成情况”仅仅体现了问题的状态,却没有清晰地表达问题在迭代周期内的过程。准确的术语是“进度(Progress)”,命名为“跟踪问题进度(Tracking Issue Progress)”更加符合该领域的统一语言。在最初识别用例时,对于“创建问题”的包含用例而言,最初命名为“问题检查”。这个描述未遵循动宾短语的形式,而“检查”一词也容易带来歧义,会错以为是项目成员检查问题的完成情况,实则是对创建的问题进行合规性验证,更名为“验证问题有效性”更为合理。
再以员工管理用例图中的“提交工作日志”为例。企业的内部术语为“日志报工”,若以统一语言的角度讲,似以“日志报工”用例名为佳。然而在英文中,并无“报工”的恰当翻译,更为人接受的英文名为“Submit Work Log”,因而用例还是应命名为“提交工作日志”。
显然,通过对用例的不断打磨,对存有疑惑的用例,通过可视化的用例图与领域专家不断沟通,借助用例规格的设计指导,可以帮助我们发现问题,并进一步挖掘出准确的领域术语,建立系统的统一语言,并为后续识别限界上下文以及领域建模奠定基础。
识别用例的主题边界
在绘制用例图时,除了参与者、用例以及用例之间的关系外,还有一个非常重要的要素:主题边界(Subject Boundary)。主题边界包含了一组高内聚的用例,并需要设计者为这个边界确定一个主题(Subject)。显然,主题的确定恰好就是对用例的归类,至于归类的原则,正是[第 3-4 课 识别限界上下文]中提及的两个方面:
- 语义相关性
- 功能相关性
语义相关性
通过语义相关性来判别用例是否存在高内聚,是一种业务分析手段。就好像我们整理房间一般,相同类别的物品会整理放在一处,例如衣服类,鞋子类,书籍类……每个类别其实就是所谓的“主题(Subject)”。在前面识别用例时,我就要求针对用例名要字斟句酌。用例名通常为动宾短语,宾语往往体现了领域概念。显然,在用例名中如果包含了相同领域概念,就可以认为是语义相关的,就可能归类到同一个主题中。
在识别用例的主题边界时,我抛开了用例图的约束,选择将用例图直接以主题边界进行划分,不再继续保留参与者与用例、以及用例之间的关系。如下图是对合同(Contract)主题的识别:
这种对用例的可视化方式可以认为是用例图的另一种视图,即“主题视图”,主要表现用例的分类和相关性,属于领域场景分析中的 Where 要素;而之前给出的用例图则为参与者视图,表现了参与者、用例之间的协作关系,属于领域场景分析中的 Who、Why 与 What 要素。两种不同的用例视图可以提供不同的参考价值,同时又保障了用例可视化的清晰度。
仔细分析合同的主题视图,我们发现在这个主题边界中的所有用例,用例名都包含了“合同(Contract)”这个领域概念,这就是所谓的“语义相关性”。有时候,这种语义相关性并没有这么直接,需要就领域概念的共同特征进行归纳,例如,市场(Marketing)主题:
在这个主题中,包括了市场需求、需求订单、客户需求等领域概念,我们却不能分别为其建立主题,毕竟这样建立的主题太过散乱而细碎。这时,就需要针对领域概念,建立抽象,即寻找这些领域概念的共同特征。显然,无论是市场需求,还是经过评估后形成的订单及客户需求,都是为一种更高的抽象层次“市场”服务的。
通过语义相关性判断用例的归属时,一个用例有可能包含两个语义,这时就需要判断语义与主题相关性的强弱。例如,“从储备人才转为正式员工”用例,究竟属于储备人才主题,还是员工主题?判断语义的相关性强弱时,可以依据用例的业务价值或用户目标,应优先考虑满足用户目标的语义。显然,“从储备人才转为正式员工”用例的用户目标是生成员工记录,储备人才的信息仅仅作为该领域行为的输入,答案不言而喻。
功能相关性
领域概念是名词,而用例则是动词,表达了一种领域行为。在确定用例的主题边界时,如果我们发现一些用例虽然在领域概念上没有明显的语义相关性,但它们却服务于一个共同的用户目标或业务价值,则说明它们是功能相关的。例如,考勤(Attendance)主题:
功能相关性还体现于用例之间的关联与依赖,在用例图中,主要以用例关系的包含、扩展与泛化来体现。例如,人事专员用例图:
与员工管理功能相关的子用例包括:
- 上传员工劳务合同
- 从储备人才转为正式员工
- 录入项目经历
- 录入技能信息
- 录入语言能力
那么,员工主题就应该包含以上功能相关的用例:
在确定用例之间关系时,我提到了包含与扩展不同的“粘度”。在确定功能相关性时,尤其要特别关注主用例的扩展用例。根据我的经验,大多数扩展用例提供了不同于主业务视角的关注点,而这些关注点往往在支撑子领域场景中提供了共同的业务价值,可以对它们做进一步抽象。在 EAS 中,这样的扩展用例主要体现在两个方面:文件上传与下载、消息通知,故而可以为其分别建立主题边界:文件共享(File Sharing)与通知(Notification)。
注意文件共享与通知主题中的用例名,描述了与具体领域场景无关的通用业务。例如,在招聘专员用例图中,定义了“上传储备人才简历”和“通知招聘计划审核人”两个用例,它们实际上分别对应了“上传 Word 文件”与“发送通知电子邮件”、“发送站内信息”用例。之所以这样描述用例名,是因为这两个主题可能会为通过其他主题提供业务支撑,一旦具体化,就无法满足通用要求。
文件共享和通知主题中的用例并没有出现在之前识别的用例图中。通过参与者识别用例图时,我们是根据先启阶段识别出来的核心业务流程、史诗级故事与主故事,并通过设想参与者参与的领域场景,进而驱动得出这些用例。文件共享和通知主题中的用例则是通过寻找所有的扩展用例,进而归纳出它们的共同特征。这是两种迥然不同的用例分析方法。
设计的决策
无论是寻找领域概念的共同特征,还是识别用例行为的用户目标,都需要一种抽象能力。在进行抽象时,可能出现“向左走还是向右走”的困惑。这是因为抽象的层次可能不同,抽象的方向或依据亦有所不同,这时就需要做出设计上的决策。例如针对用例中识别出来的“员工”与“储备人才”领域概念,我们可以抽象出“人才”的共同特征,从而得到人才(Talent)主题:
然而从共同的用户目标考虑,储备人才又是服务于招聘和面试的,似乎归入招聘(Recruiting)主题才是合理的选择:
实际上还有第三种选择,就是将储备人才单独抽离出来,形成自己的“储备人才(Candidate)”主题:
该如何抉择呢?我认为须得思考为什么要识别主题边界?显然,这里识别的主题边界仅仅是设计过程中的中间产物,并非我们最终的设计目标。主题边界是对用例的分类,在用例图中体现了用例的边界,而这种边界恰好可以对应领域模型的限界上下文,并为设计模型的包、模块提供设计指导。因此,究竟为人才主题,还是招聘主题,或者单独的储备人才主题,完全可以从限界上下文或者领域建模的角度去思考。
主题边界体现用例的内聚性
主题边界并不以边界内用例的多寡为设计准则。至少在进行领域场景分析时,不要因为一个主题边界包含了太多的用例,就人为地对其进行更细粒度的拆分,关键还是要考察用例的内聚性。例如与项目管理有关的主题,包含的用例数量就非常不均匀。项目(Project)主题包含的用例为:
问题(Issue)主题包含的用例为:
项目成员(Project Member)主题包含的用例最少:
识别主题边界不是求平衡,更不是为了让设计的模型更加好看,它的设计质量可能会直接影响到后续的限界上下文识别。或许内聚性的识别需要较强的分析能力和抽象能力,但只要我们遵循领域场景分析的设计思想,按部就班地通过业务流程识别参与者,再根据参与者驱动出清晰表达的用例图,最后再根据语义相关性和功能相关性识别主题边界,就能获得一个相对不错的场景分析结果。毕竟,这个分析过程是有章可循的,在知识的积累上也是层层递进的。整个过程不需要任何与技术实现有关的知识,非常利于领域专家与团队的共同协作和交流。