第 1 周架构方法总结
软件架构设计分为三个阶段:
需求分析阶段:通过用户、场景、需求的分析确定系统(或产品)功能的范围与优先级(用例图)。
概要设计阶段:根据系统功能,设计出系统的实现模型(部署图和组件图)。
详细设计阶段:根据组件图完成类的设计,用来指导并约束代码落地(类图)。
一、需求分析阶段
需求分析阶段的主要任务是:通过用户、场景、需求的分析确定系统(或产品)功能的范围与优先级。
产品和系统:架构师和开发者喜欢称呼为系统,产品经理更喜欢称之为产品,其实二者是一个东西,都是给用户使用的东西,必须满足用户在一定场景下的一定需求。
功能范围的限定:系统的功能其实是由用户在特定场景下的特定需求来限定的。我们搞清楚了我们的系统是给谁用的、他们在什么场景下使用、要满足他们的什么需求之后,也就搞明白了系统的功能是什么(功能的范围)。
功能优先级的限定:有时候我们确定的系统功能可能很多,有些系统是必须一次性交付的(例如 B 端或 G 端的定制系统),而有些系统是必须尽快上线,但是允许后期逐步迭代升级的(C 端产品的系统)。无论是哪一种,我们都应该给我们限定的这些系统功能排出一个优先级。通过优先级的确定,让我们知道应该优先把资源集中起来完成哪些功能,尤其是对于 C 端产品,不可能一上线就尽善尽美,一般都是快速上线、小步迭代的,这个时候优先级就更为重要了,只要我们把核心功能做出来了,就可以先拿到市场上做 MVP 验证了,后面的功能到底要不要做、怎么做,完全由市场说的算。
系统的功能一般通过用例建模(用例图)来描述。
用例图是用来描述系统如何通过各种功能对外提供业务服务的。如下图所示,用例图中主要有 4 个组成部分:角色/第三方系统(下图中的小人),系统的功能(下图中的椭圆)、系统的边界(下图中的方框,也称为用例的边界)、用例关系(使用关系和扩展关系)。我们要做的这个系统包含哪些功能,它的边界在哪里,这些功能如何对各类角色或第三方系统(如下图的记账系统)提供服务(用例关系)
这里需要注意的是用例关系:使用关系和扩展关系的区别:
使用(包含)关系:基用例必须使用(包含)子用例,一般是两个用例中共用一组相同的动作,就可以将这组相同的动作抽象出来作为一个独立的子用例。注意这里子用例是必须被调用的,这里是和扩展关系的区别。例如上图的风险分析用例和交易评估用例都有评价的动作,就可以抽象出来作为评价用例。
扩展关系:基用例在满足某种条件的情况下使用子用例(不一定使用),基用例是一个完整的用例,即使没有子用例的参与,也可以完成一个完整的功能,在基用例中存在一个扩展点(条件),只有当扩展点被激活时(条件满足),子用例才会被执行。例如上图中超越边界检查用例中存在一个扩展点(条件),当满足这个条件时,就执行子用例:进行交易
如果需要进一步描述我们要开发的系统和第三方系统之间的调用关系,可以用时序图来表述。
如果需要进一步描述用户在使用系统时具体要执行什么样的操作,可以用活动图来表述(这里按照角色/系统来划分泳道)。
如果需要进一步描述系统中某个对象的状态变化,可以用状态图来表述。
二、概要设计阶段
概要设计阶段的主要任务是:根据系统功能,设计出系统的实现模型(部署图和组件图)。
首先要搞清楚系统需不需要拆分子系统实现,如果拆分,各个子系统和物理设备之间的部署关系如何,他们之间的连接结构应该是怎样的,系统(简单系统不拆分)或子系统逻辑上应该分成哪些模块(逻辑组件)——部署图。
然后要搞清楚各个逻辑组件(模块)之间的静态关系(依赖 关联 聚合 组合 继承 实现)--组件图(概要)
进一步,如果我们想要描述服务器、子系统之间的调用依赖关系,组件之间的调用依赖关系,可以用时序图;
如果我们想要描述子系统或组件之间的活动执行顺序,顺便检查我们子系统或组件的划分是否合理,可以用活动图。
一般情况,我们会针对系统主要的功能场景,作出时序图或活动图,用来进一步详细说明各个功能场景是如何实现的。
三、详细设计阶段
详细设计阶段的主要任务是:根据组件图完成类的设计,用来指导并约束代码落地(类图)。
类图其实脱胎自详细的组件图。
我们在概要设计阶段完成了组件图(概要)的设计,表述的是逻辑组件之间的逻辑结构。但是逻辑组件,跟开发阶段的包或类并不一定是一一对应的关系。因为有些系统比较复杂,还需要把一些共性功能提炼出来,做成工具类或通用类,供其他类调用。这就需要我们要在概要组件图的基础上完成详细组件图的设计。
详细组件图,其实内容上跟类图已经差不多了,改变下变现形式就可以了。
当然有的人还喜欢用概要类图去表示概要组件图,也可以,但是我觉得没有太大必要。在概要设计阶段其实并不需要设计类图,类图放到详细设计阶段做就好。
类图的主要功能就是指导并约束代码落地。
当一个项目组开发人员很多时,可能每个人只负责几个类的开发,那么通过类图,开发人员可以清晰地知道自己要开发的类处在整个系统的什么结构位置上,它需要和哪些类进行交互合作,它有哪些属性、方法,都一目了然。
进一步,如果我们想要更加清晰地表述类之间的调用依赖关系,可以用时序图;
如果我们想要更加清晰地表述类中的复杂方法的处理流程,可以用活动图;
如果我们想要更加清晰地表达某个类对象的状态变化,可以用状态图。
附录:UML 图
静态关系有 4 种:(描述元素之间的关联关系,软件要素中不变的逻辑结构)
用例图:描述系统如何通过各种功能对外提供业务服务,需要在图上展示使用系统的所有角色、系统的功能以及系统的边界(可能会有第三方系统,每个系统都需要用方框框住自己的功能,表示边界)
部署图:描述系统各个子系统、组件之间的关系。一般系统都会划分子系统或者模块,组件一般包含在子系统或者模块中,子系统或模块用立方体表示。当然对于比较简单的系统或者是子系统,可以直接画组件图。
组件图:系统组件之间的关系(组件又称为系统的软构件,组件图和部署图都是系统的实现模型,用来描述系统实现时的特性。组件包括逻辑组件和物理组件,逻辑组件(模块)一般用于概要设计阶段:系统逻辑上应该分成哪些模块;物理组件(包/类)一般用于详细设计阶段:一般跟包、类一一对应,落地就是一个文件,例如 windows 打包出来的 dll 文件,java 打包出来的 jar 文件。逻辑组件和物理组件的区别:逻辑组件是从业务逻辑的角度去思考系统的各个功能哪些能够组成一类打包在一起形成组件(即模块),而物理组件需要从代码实现的角度对逻辑组件进行细化,把一些共性的功能提炼出来形成工具类或通用类,一般对应着具体的包或类。先构思逻辑组件,再细化物理组件,其实也是从整体到局部思路的应用,方便我们后面更好的去完成类图)
类图:系统类之间的关系(类图一般是在详细设计阶段去画,因为类图和物理组件图基本上是一一对应的,是用来指导并约束代码落地实现的。)
动态关系有 3 种:(描述元素之间的调用关系,软件实体在执行过程中的变化过程)
时序图:描述对象之间的动态交互行为(调用依赖关系),着重提现对象间消息传递的时间顺序,其中水平轴表示一组对象,垂直轴表示时间。时序图在需求分析阶段可以描述我们要开发的系统和现有系统之间的调用和依赖关系;在概要设计阶段可以描述我们的服务器和子系统之间的调用依赖关系、组件之间的调用依赖关系;在详细设计阶段可以描述类之间的调用依赖关系。总之,当你需要描述对象之间的调用依赖关系时,就可以用时序图。
活动图:实际上就是带有泳道的流程图,用来描述系统中各种活动的执行顺序。泳道是一种分组机制,相当于把一个活动流程拆分成几个领域或维度,比如按照角色分,按照子系统分,按照模块(逻辑组件)分,按照类分等等。一般我们可以先做好流程图,然后划分泳道,就做成了活动图。在需求分析阶段,我们可以按照角色/系统来划分泳道,利用活动图描述用户使用系统时需要做什么操作;在概要设计阶段,我们可以按照子系统/模块划分泳道,利用活动图检查我们的子系统/模块划分是不是合理、边界是不是清晰;在详细设计阶段,对于类中的一些复杂方法,我们可以按照类来划分泳道,利用活动图描述方法内部的处理流程。
状态图:描述对象的状态的变迁过程。每个对象都有状态,状态是对象执行了一系列活动的结果。当某个事件发生后,对象的状态可能发生变化。状态图就是用来描述对象的状态是如何发生变化的(事件触发)。在需求分析阶段,我们一般需要对某个对象的状态变化用状态图表述,例如电梯的运行状态。在详细设计阶段,我们就要对类进行设计了,这个时候对象一般是类的对象,状态一般用枚举值或者整型值类表示,这些状态如何变化,触发条件是什么,也可以用状态图去表述。
推荐阅读书籍:《UML 精粹:标准对象建模语言简明指南》
架构设计文档模板参考:https://kdocs.cn/l/cnRl43S6xzJL [金山文档] 架构设计文档模板.pdf
版权声明: 本文为 InfoQ 作者【Richard】的原创文章。
原文链接:【http://xie.infoq.cn/article/491c2991b12521f8acd5288b6】。文章转载请联系作者。
评论