软件架构要分层、分模块,具体该怎么做?

道哥分享
关注

(4) 规则配置用例描述

(5) 规则触发用例描述

三、概要设计

可以把概要设计理解成一个粗略、抽象的架构图,用来体现高层组件,以及它们之间的联系。那么应该怎么做,才能得到这样的一张架构图呢?

我们现在的掌握的材料就是:用例图和(关键用例的)用例描述,而且在用例描述的基本事件流中,把要设计的系统当做一个黑盒子进行描述。

现在我们需要做的事情,就是打开这个黑盒子,进入其中内部,从执行过程上来分析:需要哪些模块完成什么动作。

注意,这是我们的目的。要达成这个目的,使用鲁棒图这个工具。

也就是说,我们现在需要通过鲁棒图这个工具,去拆解用例描述中的事件流,把系统内部的、为了完成这个用例所需要的参与元素,全部都找出来,并标注它们之间的关系。

1. 对每个关键用例的用例描述,画出鲁棒图

先说一下容易混淆的概念:鲁棒性,也称作健壮性,是指程序在运行过程中,即使出现了一些错误的状况,也已让能够顺利的执行下去。它描述的是程序的容错性。

鲁棒图是指:用图形建模的方式,来描述一个用例描述是否正确、是否完善。

主要通过 3 种元素:边界对象,控制对象和实体对象,来画出一个用例描述中,待设计的系统内部各功能模块之间的交互关系。

边界对象:在系统内部,需要与外界进行交互的元素。它负责接收外部的输入、向外部输出内部的处理结果;控制对象:描述动态的控制行为,强调从一个执行环节进入另一个执行环节;实体对象:对一个信息内容进行描述,比如:网关中的一个设备描述信息、一条规则配置信息等;

关于边界对象,在 Web 类项目中,可能比较好理解,就是与用户、外部系统所交互的界面。但是在嵌入式系统中,大部分情况下是没有界面的,但是我们只要抓住一个根本的东西:接收外部的输入、向外部输出数据。

我们这里就简单画一下添加设备、控制设备和规则触发,这 3 个用例描述对应的鲁棒图(先忽略这几张图中的颜色):

添加设备:

控制设备:

规则触发:

关于添加规则的执行过程中,大部分工作是在手机 APP 上完成的(选择源设备--触发条件--目标设备),网关中只是把配置好的这条规则存储一下而已,没有其他过多的操作。

规则中更重要的部分是规则触发的处理,例如:当红外设备(源设备)检测到人体时,如果当前处于布防状态(触发条件),就启动声光个报警器(目标设备),因此下面这张图是描述执行一条规则的执行过程,这个过程的执行链条比较长,能把很多的模块串接起来。

2. 对鲁棒图中的模块进行归类,归纳出子系统

假设我们现在把所有关键用例的鲁棒图都画出来了,下一步的动作就是对这些模块进行分类。上面几张图中,有些模块被标记了不同的颜色,相同的颜色表示它们是属于一类的。

黄色部分的模块都是与无线通讯相关的,那么这些模块就可以归类为无线通信管理子系统;绿色部分的模块都是与设备相关的,那么它们就归类为设备管理子系统;蓝色部分的模块都是与规则相关的,那么它们就归类为规则管理子系统;继续找出其他的子系统。。。

最终,我们把这些子系统(或者称之为功能组)画到一张图中如下:

这张图就从上层组件的视角,把整个系统划分为几个子系统,每一个子系统都是一个独立的、可以交付的实体模块。

这张图的作用还是挺大的,可以用于向领导进行汇报(领导才没有时间看详细的设计),也可以用于产品说明书中的技术架构描述部分,还可以用于团队成员分工,因为每一部分都是一个独立的单位,与其他子系统之间的耦合性,从静态和动态两方面都隔离开来了(待会在后面的开发架构设计中进行说明)。

这些子系统之间是需要通信的,因此,在画出这个设计图之后,我们还需要做出下面的几个决策:

使用的技术栈:开发语言 C,进程之间的通信方式:消息总线;并发:每个子系统以进程为执行单位运行在系统中,通过 MQTT 消息总线的C语言实现 mosquitto 库,来接入到总线系统上;系统不支持二次开发

四、详细设计

在上面的概要设计图中,已经把所有的功能模块划分到不同的子系统中,也可以称之为功能组。下一步的工作,就是把每一个功能组中的内部对象、需要完成的功能、交互流程找出来,具体来说,就是要分析出系统的逻辑架构、运行架构和开发架构。

1. 逻辑架构

逻辑架构就是把每一个子系统再分为粒度更细的功能块,如果想粒度更细的话,也可以拆解到类这个级别。此外,还需要定义好各模块之间的交互接口。

根据上面的描述,我们已经决定把各子系统设计为一个独立的进程,各进程之间通过消息总线进行数据交互,而这个消息总线,是基于 topic 主题来进行消息路由的,因此,下面就要设计好每一个进程需要处理哪些数据交互:

入口:对其他哪些模块的请求进行响应;出口:为了完成自己的工作,需要依赖其他哪些模块提供服务;

一句话总结:就是找出每一个模块,为了完成自己的工作,需要与其他哪些单元模块之间进行交互?交互的接口(函数、方法或者协议)是什么?

那么怎么来找到这些对象和接口呢?用序列图或者类图来完成。下面是控制设备的一个简单序列图:

图中的每一个箭头,都代表一个接口,对于这个网关来说,就代表处理的一个 topic 主题。

如果用类图来分析,对于面向对象的开发语言来说,可能会更容易理解,比如:可以明确的定义出每一个对象的属性,私有函数,共有函数,并且能够清晰的构建出对象之间的关系。

2. 运行架构

运行架构描述的是每一个执行单元的动态状态、执行时的控制流程,需要考虑的重点是:系统是否安全?性能是否满足质量要求?可扩展性如何?

具体到网关来说,每一个子系统是以进程为执行单位的,每个进程通过一个第三方的附件(也就是动态库),挂接到消息总线上,如下图所示:

系统的并发性,是通过多进程来实现;系统的安全性,主要通过消息总线的安全机制来管理。

比如在开发阶段,消息总线允许系统外的其他客户端接入,这样就可以在 PC 机上写一个调试程序,接入到总线中,可以监听所有的数据,此时数据可以不加密,全部是 human readable 的;但是在项目 release 阶段,那么就关闭这个权限,PC 机上的客户端就不能接入总线,并且总线中所有数据的需要加密、压缩,进一步提高系统的安全性。

3. 开发架构

作为以撸代码为主力的我们来说,开发架构就容易理解了,无非就是定义好项目结构、编译流程、测试步骤等等。

具体来说,我们可以从下面几方面来做出规定:

并行开发:每个子系统是一个独立的进程,因此可以划分为一个独立的项目,提高开发效率;第三方库:作为基础的公共模块来使用(SSL加密、消息总线接入、通信协议解析);代码安全:每位开发人员只能有权限拿到自己负责的代码,只有管理员有权限获取所有代码;代码管控:使用 git、svn 等工具进行代码版本的管理;集成编译:使用 Jenkins + git  module 功能,自动拉取所有的子系统代码,自动编译。如果需要自动部署的话,也可以使用脚本来实现。

五、架构验证

终于来到最后一个环节了,其实项目经历多了,以上设计出来的架构,是否能满足需求中提出的功能和质量要求,我们在心中已经大概知道答案了。

为了保险起见,我们还是需要对其中的某些关键部分进行验证。这个验证过程是有价值的,或者说可以把这个验证过程所得到的成果,作为正式的代码进行提交。

验证的大方向有 2 点:系统的框架是否合理、稳定;一些技术瓶颈是否可以搞定。如果这两部分都没问题,那后面就可以大胆的往前走了。

六、总结

经过 2 篇文章的介绍,我基本上把自己在平常工作中,对应用程序架构设计的这个思考过程描述了一遍。

佛经里说了:渡人就像帮助一个人过河,过了河上了岸,就应该把乘坐的木筏丢掉,心中不要再想着木筏。

这篇文章介绍的设计流程,也是一个套路而已。这个套路在面对一个新领域、新项目时,就像一个脚手架一样,告诉我们这一步该做什么,下一步该做什么,应该使用什么样的工具。

在僵化的运用这个套路之后,你可以继续改造、优化,然后丢掉这个套路,从而形成适合你自己的套路,从此走向思考致富的道路!

声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存