第4章 系统设计
1. 大话系统设计
(1) 战术编程腐蚀系统:战术龙卷风 => 快速、高产、坑多
(2) 系统复杂化的3个特征:
- 变更放大:看似简单的变更却需要在许多不同地方进行代码修改。
- 认知负荷:开发人员需要多少知识才能完成一项任务,新技术、不恰当的接口设计、混乱的命名、模棱两可的注释等都会增加认知负荷。
- 未知的未知:无法确定需要改动哪些代码才能让程序正常运转,也不知道改动是否会引发新的问题。
(3) 系统复杂化的3个诱因:模糊性(命名模糊)、依赖性、递增性
(4) 复杂化应对之道:
- 合适的架构:如何将系统切分成组件,并安排好它们之间的协作关系
- 遵循设计原则:
-
- 组件层面:复用/发布等同原则、共同闭包原则、共同复用原则、无依赖环原则、稳定依赖原则、稳定抽象原则
- 代码层面:单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特法则、组合复用原则
- 采用设计模式:设计原则是纲领性的指导思想,设计模式是具体的实现手段。
- 避免破窗效应:一旦系统有了设计缺陷,就应当及时进行优化。
2. 总体架构
(1) 什么是架构
- 架构 = 模块或组件 + 职责与关系 + 指导原则
- 系统设计涉及的架构有业务架构、逻辑架构和物理架构
-
- 业务架构:属于问题空间,是基于需求分析和抽象建模结果进一步推导的产物。业务架构可以直观地呈现产品具有哪些业务模块、各个模块提供什么能力及业务模块之间的关系。
- 逻辑架构:属于解决方案空间,关注点在于系统功能或职责的划分。
- 物理结构:属于解决方案空间,关注点在于目标程序及其依赖的运行库和系统软件最终如何安装或部署到物理机器。
(2) 架构推演
- 架构约束是指业务功能需求之外的硬性约束,通常涉及性能、安全性、稳定性、可用性、兼容性等方面
(3) 设计功能域
- 对于复杂的业务,首先应设计、划分功能域,以降低复杂度。每个功能域可视为一个微服务应用。在设计功能域时,主要关注职责、复杂度和性能。
- 以会员体系为例:会员体系中包含权益体系(图4-4),权益体系包含权益投放(图4-5),权益投放域与其它功能域的协作关系(图4-6)
(4) 明确数据边界:功能域服务之间的数据交互定义(请求+响应)
(5) 架构约束考量
4.2章节介绍了逻辑架构的设计过程
3. 内部分层
(1) 什么是分层
- 功能域粒度的逻辑架构比较粗糙,无法直接指导开发,需要对功能域进行展开分层设计。
- 分层可以有效地将复杂地问题分解和简化,同时带来可测试性、可维护性、可扩展性等方面地好处。
(2) 功能域内部分层
- 四层架构:终端显示层(View)、业务逻辑层(Service)、通用处理层( Manager)、数据持久层(DAO)
- 将分层设计映射到图4-6架构模型中,得到图4-13封层架构模型:
-
- 流量分发和投放策略相对通用,将其置于Manager层;
- 权益投放域以权益咨询服务的形式对外,他与业务关系密切,因此置于Service层;
- 依赖其它域的服务则以Client的形式与Manager层协作。
(3) 分层原则
- 组件聚合原则:复用/发布等同原则、共同闭包原则、共同复用原则
- 组件耦合原则:无依赖环原则、稳定依赖原则、稳定抽样原则
4. 详细设计
(1) 设计内容
- 类图设计:将领域模型、模块、组件等以类图的形式来呈现。UML图可以清晰地表达软件设计中类与类之间地关系。
- 数据设计
- 依赖设计
- 方案描述:业务较为复杂时,文字描述难以直观地反映设计方案的细节,需通过流程图、时序图等图表来描述核心处理逻辑。
- 非功能性设计
(2) 设计模式
- 相关学习文档:HeadFirst设计模式、大话设计模式、Go语言设计模式
(3) 详细设计要求
- 完备性:功能描述、性能描述、流程逻辑、接口设计(输入输出)、存储设计、算法设计、限制条件、异常处理等。
- 易理解:特殊名词应辅以注解;复杂逻辑应辅以流程图、时序图、架构图、类图说明。
- 灵活性
5. 一图胜千言
(1) 画图工具选择:
| 工具 | 优点 | 缺点 |
|---|---|---|
| processon⭐ | 有丰富的模板和图标素材 | 收费 |
| excalidraw | 免费,界面简洁美观 | 缺乏丰富的模板和素材 |
| plantUML | (1) 写代码生成更快捷(2) 不用纠结样式问题 | 样式单调且不美观 |
- 熟练掌握任何一款工具,都能满足大多数场景的绘图需要。
(2) C4模型:上下文(Context)、容器(Container)、组件(Component)、代码(Code)