首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

软件设计实践

前言

拿破仑曾经说过:“不想当将军的士兵不是好士兵”。而在软件行业中,几乎每个程序员心里都有一个成长为架构师的梦想。程序员与架构师之间,不仅仅是角色的转变,更多的是知识的积累,以及架构,设计能力的转变。最近有幸参与了一些设计工作,系统算不上复杂,庞大。但在这过程中将自己的不足暴露的淋漓尽致,如同裸奔,有着凉飕飕的感觉。记录这篇文章,算是一次小结,同样也给自己之后系统设计时留下一丝指引。

愿景

愿景二字其字面意思是:希望看到的场景。这一词在潘加宇老师的《软件方法》中解释为:我们希望新系统 / 服务 是怎样的 ?也就是为以下几点:

我们为谁编写系统?也就是寻找到业务 “老大”,可以理解为解决XX的问题?这个 XX 就是老大。

我们编写该系统的目的是什么?

希望通过它能够解决什么问题?

没有该系统前,业务是怎样运行的?(现状)

有该系统后,业务会发生怎么样的变化 ?(改进后)

在愿景中,个人建议添加适量的可量化值,以及图(交互图)等更直观的表达体来体现两者之间的差异。例如:

改进前:TPS 是 1000,改进后:TPS 是 2000 等。

改进前:对接新产品需要 40天, 改进后:对接新产品只需要 20 天。

业务用例

技术人员一直有个不愿承认的事实是:技术是为业务服务的,而技术是一种业务实现的手段/工具。在这样的前提下,我们在做新系统设计时,优先需要理清业务,先做业务分析设计。在进行业务分析设计时,我们以组织为研究对象。组织提供的价值称之为业务用例,组织外部与系统交互的人或组织称之为业务执行者,组织内的人称之为业务工人,组织内非人系统称之为业务实体。

进行业务设计分析时,常用工具有:用例图时序图

用例图

其表达的核心价值是:业务组织向业务执行者提供哪些价值,而这些价值通常用业务用例表示。在用例图中用到的元素有:业务执行者,组织,业务用例。例如:腾讯这个组织,向微信支付用户,提供小程序支付这个价值的业务用例。如下图所示:

图(1) 业务用例图

时序图

在UML中,时序图是动态的交互图。其表达的核心价值是:业务执行者,业务实体,业务工人之间在完成该业务时的交互。如下图所示:

图(2) 业务时序图,来源于微信支付官方

其中:

业务执行者:微信支付用户

业务实体:商户系统,微信后台, 微信小程序

在上图中,并没有业务工人。

系统用例

上面介绍了业务用例,接下来就是系统用例。上面说到,业务用例是以组织为研究对象,对外提供的价值称之为业务用例。而系统则是以系统为研究对象,与系统交互的人或系统称之为系统执行者,系统提供的价值单元称之为系统用例。在系统用例中,比较常用的工具有:用例图,时序图

以上面例子所述,系统用例图,如下图所示:

图(3) 系统用例图

解释:微信支付系统向微信支付商户提供:统一下单,订单查询,订单关闭,查询退款,下载对账单 等等系统价值,而该价值称之为系统用例。

其中:

系统:微信支付系统就是我们研究的对象。

系统执行者:微信支付商户。

系统用例:统一下单,订单查询,订单关闭,查询退款,申请退款,下载对账单 等称之为系统用例。

如果说:每个系统用例是系统提供的价值封装。而系统时序图:则是系统在完成该价值时的内部交交互。

包图

包图是最容易忽略的,恰恰它在项目中发挥着极其重要的作用。倘若一个系统没有使用包进行归类,其可维护,可扩展性是不可想象的。例如:我们熟悉的 java.util 下的简易包图,如下所示:

图(4) java.util 包图

仔细看看上面的包图,其实不难发现,每个包做的事情都是原子的,如同设计模式中的单一职责一样。我们在使用包图时,也要遵循这样的设计思想。

包的分类

项目中按照模块进行划分,每个模块就是一个包。

在模块内部,则按照职责进行划分,相同职责的类放在同一个包中。

当然,在使用包图时,我们还需要注意包与包之间的关系。

(在这里就不展开了,请自行查阅文档)

类图

类图是UML中常用的静态结构图,在系统设计时,我们需要用类图来表达类的构成,以及类与类之间的关系。

如下所示:

图(5) ArrayList 类图

在UML中类图由以下几点构成:类名,类属性,类方法。

常用的类与类之间的关系有:

实现:

继承(在UML工具中用:

Inheritance 或 Generalization 表示)

关联

聚合

组合

类图对编码工作有着非常大的指导意义,在前期捋清楚类与类之间的关系,编码时,就可以按照设计进行编码。

状态设计

在核心对象的状态变化,需要设计清楚。

该对象有哪些状态?

状态的转换条件是怎样的?

在UML中状态设计中常用的工具有:状态图

例如:订单有:未支付,支付中,支付完成,支付失败 等状态。

用户下单完成,但未支付时为未支付状态。

用户正在支付时,从未支付状态转换为支付中状态。

用户支付完成后,从支付中转换为支付完成状态。

由于系统原因或其他原因,从支付中转换为支付失败状态。

关键算法

在进行系统设计时,如有关键算法,也是需要在设计文档中体现的,并需要举例说明。

数据结构设计

数据结构设计包括以下几点:

使用关系型数据库,还是非关系型数据库?(具体到某个实际的组件,例如:MySQL)。

使用什么存储引擎?是Innodb还是MyISAM ?

使用什么字符集,是 utf8 还是 utf8mb4 ?

例如:

表名:t_user

存储引擎:Innodb

字符集:utf8

图(6) 表结构设计

在数据结构设计中,需要注意的是:每个表结构中的公共字段名,类型统一。例如:创建时间,修改时间,逻辑删除标识,主键等等。

部署图

部署图,表达的是部署结构,也就是说系统部署态是怎样的。如:

部署到云服务商,还是自建机房?

从用户请求到服务中,执行全过程是怎样的?

非功能性设计

在非功能性设计时,需要考虑的点有以下几点:

监控体系 :监控体系通常包括 系统监控,业务监控。

性能指标 : 例如 TPS 等等。

无论是监控体系,还是性能指标,其实都是相辅相成的。一来能够知道系统在运行态的情况,二来可以根据监控,性能指标数据来辅助系统的迭代,完善。

陷阱列表

在做系统设计时,时常会遇到一些”陷阱”。之所以称之为”陷阱”,因为这些点足够小,在不经意间就会入坑。例如:

业务分析用例时,掺杂着系统用例。

缺少关键状态变化设计。例如:订单状态由未支付到支付中,再到支付完成。这些状态由谁触发?在什么条件下触发?

数据结构设计时,公共字段属性不统一,例如:A 表的创建时间使用 created_at, B 表的创建时间为 created_time,A 表的主键是自增,B 表的主键又是另外一种等等。

缺少监控以及性能监控。

一份好的设计文档,对编码工作有着非常大的指导意义,既能提高软件质量,也能提供交付效率。在这方面,我自己也是非常薄弱,在此将自己的一点经验和感想记录成文,希望对之后的系统设计能有所启发!

参考文献:

1. 潘加宇 《软件方法(上) 业务建模和需求》

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20191201A0FU8L00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券