不会画图? 17 张图教你写好技术方案!

2023年 9月 21日 73.7k 0

横看成岭侧成峰,远近高低各不同。为了更好地理解软件系统,我们需要借助于多种图表工具,从不同的视角出发,全方位的理解系统设计。以便在设计阶段足够充分预估系统瓶颈,实施难度,开发工时等,在业务功能上实现良好扩展性,性能上高可靠,高可用。达到数据绝对安全,性能足够优异。支撑业务需求快速迭代。

软件系统可以按如下分层

  • Iass: 基础设施软件,包括操作系统(网络,存储,计算),虚拟机,Docker等基础软件。
  • Paas 平台即服务: 包括我们日常的消息,缓存,数据库,等中间件。也应该包括框架和 类库。例如ioc,orm,rpc框架; 图片,特殊文件处理的第三方类库等
  • Saas 软件即服务: 我们日常的一些应用,无论是2B,2C都属于此。
  • 以下我们将重点分析借助哪些图表工具 可以分析 应用软件系统(Saas层)。这些图表的阅读者 应该是开发者,产品经理,业务架构师,系统架构师,技术管理者等。

    用例图

    用例图是最清晰,最容易理解的图表,用例图从用户角度出发

    要素

  • 如何使用我们的系统。如果系统已经完成,可以使用简洁版本的 用户使用手册代替。
  • 有哪几种使用流程,哪些应用场景。
  • 每种流程需要做哪些事情。
  • 用例图首先需要分析系统有哪些使用人员,可以借助以下问题分析

    • 谁将使用该系统的主要功能。  
    • 谁 将需要该系统的支持以完成其工作。 
    • 谁将需要维护、管理该系统,以及保持该系统处于工作状态。

    例如简单的用户修改资料
    3251695013532_.pic.jpg

    用例图因为其简单直白,容易被系统设计者忽略,实际上 对于一个完全未接触系统的人,用例图是最友好,最直白的,可以让小白 快速的了解我们的系统 给哪些人提供了哪些功能。功能之间的联系是什么

    用例规约

    用例规约是对用例的详细描述,一般包括简要说明、主事件流、备选事件流、前置条件、后置条件和优先级等

    用例规约既关注主事件流所描述的成功场景,也关注备选事件流所描述的异常场景,有利于促进系统化思维、发现异常场景、完善系统功能和提高易用性;

    后置条件应覆盖所有可能的用例结束后的状态。即后置条件不仅仅是用例成功结束后的状态,还应该包含用例因发生错误而结束后的状态

    示例

    3261695013597_.pic.jpg
    一般情况可以只描述重要需求,关键用例的用例规约。一般需求可以忽略。(PRD里绝对不能忽略)

    用例图和系统页面
    如果有 更详细的使用手册,则可以更快速的全面理解系统的功能。例如展示一下我们的系统页面。更加直观和清晰。

    只有更好的了解系统提供了哪些功能,有哪几种角色,才能理解 系统为什么这么设计?
    某些人之所以会觉得用例图多此一举, 是因为其对系统本身足够了解。但是他们忽略其他人对系统还是完全一片陌生。需要借助用例图,最直白的了解系统

    数据模型图

    程序=数据结构+算法,软件程序就是对输入数据进行处理,按照一定的算法,输出特定的数据。
    数据是程序的核心,也是容易变化的部分,例如最常见的变化: 需要增减字段。

    此时需要对数据进行建模,梳理模型之间的关联关系,为的是把关系最紧密的数据 放到一个模型里,独立扩展。
    数据模型图描述了 模型之间的关联关系,每个模型有哪些字段 。
    三要素
    ● 模型
    ● 属性
    ● 模型间关联关系

    数据模型图包括 E-R图,数据库实体图。等。

    • E-R图使用中文,不涉及表结构,更简单。
    • 数据库模型层: 描述数据库层面的关联关系和表设计, 虽然比ER图更复杂, 但是更全面,适用人群都可以看懂。
    • 大多数情况下 我们的设计文档是给产品和研发,技术管理者看的。使用数据库实体图也可以看懂。(看不懂的让他去学)

    个人认为设计文档里可以忽略E-R图,直接上数据库实体图。但是这就要求数据库实体图 有充分的文字说明,例如属性注释,关联关系说明等。

    E-R 图示例

    3271695013599_.pic.jpg

    数据库实体图(数据库 ER 图)

    3281695013599_.pic.jpg

    数据库 ER 图的梳理过程

    数据库 ER 图,实体图或者 领域模型图的设计非常考验设计经验。需要领域专家根据用例图,用例流程图,反复的需求沟通。不断地推敲以下问题

  • 业务的扩展点,变化方向 在哪里,未来计划的演进方向。
  • 系统的扩展方向是哪里?如何实现扩展性
  • 应该包括哪几个 领域实体。
  • 领域模型的边界 应该在哪里。关联关系是 1V1,还是 1对 N 等等。
  • 数据库 ER 图的分析过程 可以使用 DDD 等设计方法 。

    流程图

    系统设计阶段 只需要覆盖核心和关键的业务流程即可。对于细枝末节的一些简单流程应该忽略。 (有精力和时间可以覆盖非核心流程)

    管理流程和 用户流程

    以营销系统为例,分为管理流程 和用户流程

    • 运营创建了一个营销活动。这个过程是管理流程。这个流程对于性能的要求不高。流量入口不同。
    • 用户下单等行为, 触发了某些营销活动,这个流程对于性能要求,安全性要求就很高。

    不同流程的关注点不同。例如dubbo的rpc系统,也可以分为 初始化流程 和 方法调用流程

    • rpc provider 接口提供者需要初始化时注册接口。rpc consumer需要在初始化时监听接口。
    • rpc调用流程 从consumer端到provider 是调用流程。

    流程图画法

    3291695013601_.pic.jpg
    流程图的画法比较灵活。以下是个人经验和习惯

    • 组件思维: 可以描述 组件之间的控制流调用
    • 数据思维: 可以描述数据之间的数据流变化。

    一般使用方框表示 组件,连线 表示调用方法,动作 或者数据。

    组件思维

    按照组件思维 设计流程图。要求把系统的组件先抽象出来,每个组件处理哪个步骤。淡化了输入输出,
    是简化版的 调用时序图。(时序图描述方法调用层次,更加细化和清晰。)

    以下示例是dubbo Provider端 暴露一个服务的 组件调用的控制流变化图

    3301695013602_.pic.jpg

    数据思维

    按照数据流程图描述,组件之间传递的是 数据,数据流描述了 一个组件或系统的输入 和输出 是什么。
    3311695013602_.pic.jpg
    其实大多数业务系统,使用数据流程图不太好划分,因为 一个业务流程内主要是针对两三个模型进行处理。组件之间的输入输出界限并不明显
    为此可以 将数据流程图和控制图 合二为一。 方框依然表示 组件,但是连线可以同时包括动作和数据

    3321695013603_.pic.jpg

    流程图中的非功能型设计

    高可靠 高可用 性能瓶颈,流程图中可以介绍核心读写流程的高可用,高可靠设计; 即数据可靠性如何保证,系统可用性如何保证。性能瓶颈在流程中哪个节点。如何优化等

    以下仅供参考

  • 数据存在哪里,同步/异步写入,异步写入的一致性保证
  • 并发操作如何保证一致性(例如库存?)
  • 高并发场景如何提高系统可用性,读流程如何优化,写流程如何优化
  • 是否 Stand-by 设计双活。
  • 幂等性,重试策略、负载均衡策略
  • 时序图

    时序图 是更加详细的系统流程图,一般的系统流程图覆盖了关键的系统组件,关键的数据处理节点,但不会具体到哪一个类,哪一个方法。
    时序图要求关注 程序执行时的 控制流,时序的展示更好像是 系统执行时的 方法调用堆栈。

    时序图要素

  • 方法调用堆栈(核心)
  • 分支和循环描述,
  • 方法和入参描述
  • 主要的一些关键节点注释
  • 时序图示例

    3331695013605_.pic.jpg

    可以看到时序图 精确到 某个类 调用了某个类的某个方法,把方法的调用嵌套的深度 和层次 都能展现出来。
    配合 重要的 关键节点注释,可以让读者即使不读代码也可以看到整体的方法调用体系。
    通过时序图我们可以得到

  • 某个类在时序图的哪个位置,负责的工作是什么
  • 在当前流程中,某个类上下游的依赖是什么
  • 类图

    类图描述了类和类之间的依赖关系(组合,继承,接口)

    类图要素

  • 继承、实现、组合关联关系
  • 类的关键核心方法。(记得加注释,用以描述本类扩展了哪些能力)
  • 下面拿一个Spring ioc容器的类图
    3341695013606_.pic.jpg

    类图的箭头关系 描述了 两个类之间是否依赖,集成/组合/接口实现。

    什么时候使用类图?

    简单地业务流程不需要类图

    例如一个接口只有一个实现类,没有复杂继承关系 基本上不用写类图。

    复杂的继承体系需要类图

    类似于 Spring 等极为复杂的框架,为了实现最大程度的复用和可扩展性。使用了大量的继承、接口实现类 提高高扩展性和可复用性。这个时候如果没有类图,根本无法全面的了解 一个接口,一个类的继承体系。不清楚某个类在继承体系中的位置。

    为什么类图不可以归到 流程图里

    一般情况下只有流程图和时序图里面能具体精确到某个类。当读者在流程图、时序图里经常看到某个几个类,就会疑问,这几个类有什么关联关系呢?

    此时 可以择机是否需要 梳理一个 类图展示依赖关系。

    类图和设计模式

    设计模式的具体介绍都会使用类图展示。例如工厂模式 的类图
    3351695013607_.pic.jpg

    系统架构图

    系统架构图为了描述应用内部的组件,模块等。一般情况下分为 全系统架构图,单应用架构图

    全系统架构图

    业务架构图是从业务逻辑的视角出发,整齐地展现出一个企业各类系统之间的层次和关系
    3361695013608_.pic.jpg

    单应用架构图

    单应用业务架构图按照层次结构可以分为经典的三层结构:展现层、业务逻辑层和数据层
    3371695013609_.pic.jpg

    应用架构图

    应用架构图的关注点是 应用 在整个系统的位置。(和上面的全系统 业务架构图类似)。应用架构需要把应用在整个系统的位置描述出来。

    以下为优惠券系统的 应用架构图。基本描述了一个应用服务在整个优惠券相关微服务里 所处于的位置

    例如 CouponJob服务 负责发券,上层会有各种形式的发券活动关联该服务。兑换码,领券页面领券等等都依赖CouponJob发券服务能力。

    3381695013610_.pic.jpg

    应用间依赖关系 最理想的情况是单方向依赖,如果上下游的两个服务存在明显的 循环依赖,此时需要考虑,两个系统是否耦合严重, 两个系统是否实现了类似的功能呢? 是否需要合并为一个服务呢?

    是否可以把关联性很强的业务模块放到一个服务里比较合适呢?

    应用架构重在描述应用之间的依赖关系,以及应用所处在系统的位置。是上层应用还是底层应用? 设计应用架构图时 不建议把 应用内的模块划分也囊括在应用架构图中,这样会导致架构图过于庞大,不利于理解

    一个架构图只需要描述清楚 一个视图即可。(职责尽量单一)

    以下为HBase的应用架构图
    3391695013611_.pic.jpg

    可以从表中看到

    • Zookeeper负责存活性监测等集群管理任务。
    • master不负责数据读写,只负责DDL建表等语句,负责RegionServer故障转移流程
    • RegionServer负责接收客户端读写数据
    • HDFS 作为分布式存储,接收RS读写
      (至于RegionServer内部有哪些模块,如何读写 自然借助于其他架构图。每种架构图只是从一个视角描述 系统)

    部署架构图

    部署架构图重在描述应用在线上部署的情况

    部署架构图核心关注点

    • 流量从管理端还是用户端过来
      • 是否做了鉴权
    • 流量从哪几个 nginx 过来,公网还是内网,域名是哪个(公网内网,域名不同)
    • 应用是否做了负载均衡,策略是什么
    • 是否多机房部署,应用部署在了哪几个机房。
      • 机房之间的流量如何路由的; 是否存在跨机房调用
      • 是否按照用户维度进行了 Set化
      • 是否按照地区维度进行了机房路由
      • rpc调用路由规则是什么,在哪里管理路由规则
    • 部署机房 是虚拟机,物理机,还是 Docker。 私有云,公有云,还是混合云架构
    • 依赖的数据库和应用是否同机房部署?
    • 其他MQ,Redis,Es等中间件 机房部署在哪里。是否跨机房等。

    以下部署架构描述了 应用在容器上部署,用户请求经过 SLB 负载均衡。静态资源访问,数据库服务部署在RDS。

    3401695013612_.pic.jpg

    全链路调用 结构图

    以下场景需要梳理全链路上下游依赖图

  • 接口参数需要变更,接口实现需要变更。确认不影响上游(一般具体实现细节对上游屏蔽。)
  • 下掉接口、迁移到新接口
  • 限流,熔断,降级策略需要通知到上游
  • 当出现以上内容时,我们需要感知到哪些上游依赖了我们,在什么业务场景下依赖,重要性,优先级如何统一的梳理出系统 rpc 接口,http接口,mq消费者,共享数据库,等 上下游依赖。
    可以以表格的形式,例如
    3411695013613_.pic.jpg
    对于项目内部的方法调用,模块依赖,我们可以快速的梳理清楚上游的依赖。例如使用IDE 的快捷键。但是微服务下,需要获取调用链路图,只能依赖于 服务治理框架和代码扫描工具 提供的能力,梳理每一个接口上游的依赖。

    梳理后可能发现需要 对接口进行鉴权,防止任意调用方可以调用我们的服务。至少可以让我们感知到接口被调用,防止大流量,不合理的业务场景 进行调用。也方便我们日后升级。

    每一种架构图都是一个独特的视角

    架构图的视角

    • 用例图: 用户,产品经理,测试人员 可以直观,清晰的了解我们的系统使用场景,能做什么?
    • 数据库实体图: 业务架构师,业务专家,产品经理 更清晰了解 建模的过程,是否存在领域划分不清晰,领域耦合问题
    • 流程图: 给开发工程师,业务架构师,业务专家 更清晰的 了解 核心流程 ,数据如何在组件之间流转的,各组件如何调用的
    • 系统架构图: 开发工程师 可以借助于此快速了解 系统内 共哪几个模块,如何进行分层的。各层职责。
    • 应用架构图: 业务架构师可以看到 微服务之间是否存在耦合,是否依赖不合理,界限是否清晰。开发工程师可以了解负责的系统处于 总体架构的哪个位置。
    • 应用部署架构: 业务架构师,开发工程师 ,以及运维工程师 更清晰的了解 服务部署环境, 流量入口,负载均衡策略,路由策略,中间件部署情况等

    以上我们分析了设计文档应该包括哪些具体的 图表,此外

    设计文档基本原则

    设计文档的编写 应该遵循以下基本原则

  • 文档是给人看的。 要给目标读者 讲的足够透彻,每个读者的视角都要考虑到
  • 可落地。要求文档具备足够的设计细节,能准确预判技术难点,对于技术难点提出明确的解决方案(要覆盖关键需求和流程)
  • 一个架构图只需要描述清楚 一个视图即可。追求大而全的架构图只会让人看不懂,自己也无法再修改。(职责尽量单一)
  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论