用例与架构
需求描述了软件系统是什么,架构则提供了系统的低成本实现方案,回答了软件系统如何做的问题。架构依赖需求,需求驱动架构。
目前,用例是大多数项目描述需求的方法,软件分析设计活动(包括架构)的输入就是用例需求规约或者其衍生品(用户故事)。作为架构或者开发人员,我们需要懂得如何从这些规约和故事中获取有用信息,驱动我们的分析设计。
这里根据自己的学习理解,结合以往的实践,总结了几点如何从用例开始架构设计的方法。
从用例开始推导系统结构
系统结构是指系统由哪些组件构成,这些组件的职责以及它们之间的关系。
系统结构是我们通过架构活动创造出来的,没有一个简单、直接、通用的套路得到结构中的组件,但是用例可以启发我们的探索。
用例是从用户和涉众角度对系统的描述,它天然就是对系统的一种划分:每个用例代表了系统的一部分需求,代表了涉众/参与者使用系统的一类场景,从场景的层面看,用例之间没有交集。而在用例内部,场景、业务规则等元素共同定义了一组强耦合的功能需求。
如果我们继续把用例按照参与者进行分组,每个用例组对应一个或若干个类似的参与者。由于参与者是业务领域中的由人或者其它系统扮演的角色,相似的角色意味着它们提出的功能被组织在一起可能是合理的。
每个用例组我们引入一个组件(可能是子系统、也可能是模块),它们实现了用例组包含的用例,这些组件构成了系统。这个时候得到的系统结构实际上就是所谓的“功能架构”,经常出现在系统的售前和宣传文档中。但是我们要认识到,由于“功能架构”没有考虑重用和非功能属性,它不是最终的,可以用于指导开发架构。
但是从用例组得到的“功能架构”在系统划分上有一定的合理性,我们把它作为架构设计的出发点,逐步演进。比如:我们选择一个功能组件(某个子系统或者模块),从对应的用例组中找到若干个用例,分析它们的功能需求和非功能需求,引入新的组件实现公共的功能需求;引入新的组件或者精化已有组件实现非功能需求。
从用例推导领域模型
我之前参加过 UMLChina 潘加宇的“软件方法”培训,里面介绍了由用例建模的方法。这里简单介绍下。
我们要明确这里的领域模型只描述领域概念,不考虑具体的技术要素(比如:并发、事务等)。
从用例可以推导出边界类、控制类和多个实体类,它们之间的关系如下:
这些类之间的协作如下:
为用例定义控制类
一个用例最多一个控制类,一个控制类只关联一个用例,负责接收所在用例对应的业务事件,协调内部的处理。是业务用例的调用入口。
这个控制类不是必须的,如果发现不需要协调,所有逻辑可以由实体类完成,可以不需要这个控制类。
从业务实体、业务处理功能和业务约束条件推导实体类
用例和实体类之间是多对多的关系。从用例中获得实体类的方法这里不展开了,直接由业务实体映射可以作为一个起点。但是要得到高质量的领域模型,还需要在这个基础上进行抽象和挖掘,这个过程我总结不出,不过这里给大家推荐几本书:
软件方法(下)(潘加宇)
彩色 UML 建模(Perter Coad)
Domain driven design(Eric Evans)
另外,还可以参考一下别人在分析和概念层面总结的领域设计模式。
为参与者定义边界类
边界类对应用例的参与者。
从我自己的体会来看,有必要为每一个辅助参与者(Supporting Actor)建立一个边界类,这个边界类的职责是和系统依赖的外部系统通信,比如:发送通知、调用某个功能等。
对于主动参与者,只有这个参与者是由时间系统承担的角色时,为这个角色建立一个边界类才是有价值的。
从用例推导设计
当我们用具体的语言/框架去实现之前推导出的领域模型时,必须考虑具体的技术问题,包括:并发、事务、性能等,实际上这些就是用例的质量属性。
如何实现这些非功能需求呢?肯定有很多方法。我个人比较倾向于通过增加一些新的类/组件,在不修改之前的的领域实体类的前提下实现。实际上在目前的领域驱动设计的相关书籍里,有很大一部分就是介绍如何在技术层面实现领域模型,帮助领域模型落地。
比如:我们要实现数据库的访问,不是在领域实体类增加类似查询、保存的方法,而是增加一个形如:xxxRepository
的类。
再比如:某个功能需要可伸缩,这个时候可以在架构层面引入新的组件负责该功能,组件支持多实例部署,组件内部仍然使用原有的相关领域模型。
评论