# 架构简洁之道
# Q&A
# Q: 架构师做什么?
创建一个可以让功能实现起来更容易、修改起来更简单、拓展起来更轻松的软件架构。
# 两个价值维度
- 怎么评判价值?
程序可持续产生价值,而不是需求变更价值就归0
- 行为价值: 往往是紧急不重要的事儿
- 架构价值: 往往是重要不紧急的事儿
# 编程范式
用于约束程序能力: 功能性、组件独立性以及数据管理。主要有:
- 结构化编程
- 面向对象编程
- 函数式编程
# 结构化编程
结构化编程(Structured Programming)是一种编程范式,旨在提高程序的可读性、可维护性和可靠性。它通过使用控制结构(如顺序、选择和循环)来组织代码,从而减少或消除对“goto”语句的依赖。
# 面向对象编程
面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它使用对象和类来组织代码。对象是类的实例,类是对象的模板。面向对象编程的主要特征包括封装、继承和多态。
面向对象编程就是以多态为手段来对源代码中的依赖关系进行控制的能力,这种能力让软件架构师可以构建出某种插件式架构,让高层策略性组件与底层实现性组件相分离,底层组件可以被编译成插件,实现独立于高层组件的开发和部署。
# 函数式编程
函数式编程(Functional Programming)是一种编程范式,它将计算视为数学函数的求值。函数式编程的主要特征包括不可变性、纯函数、高阶函数和递归。
# 设计原则
# SOLID原则
作用是告诉我们如何将数据和函数组织为类,以及如何将这些类链接起来成为程序。
- S(SRP): 单一职责原则。一个软件系统的最佳结构高度依赖于开发这个系统的组织的内部结构。这样,每个软件模块都有且只有一个需要被改变的理由。
- 表现为需求变更时不会影响到原有功能
- O(OCP): 开闭原则。如果软件系统想要更容易被改变,那么其设计就必须允许新增代码来修改系统行为,而非只能靠修改原来的代码。
- 表现为需求拓展时不需要大幅修改代码
- L(LSP): 里氏替换原则。如果想用可替换的组件来构建软件系统,那么这些组件就必须遵守同一个约定,以便让这些组件可以相互替换。
- 表现为在衍生类下使用时,接口可替换
- I(ISP): 接口隔离原则。设计中避免不必要的依赖。
- 表现为修改类时,不需要重新编译无关的类
- D(DIP): 依赖反转原则。高层策略性的代码不应该依赖实现底层细节的代码,恰恰相反,那些实现底层细节的代码应该依赖高层策略性的代码
- 表现为具体实现依赖单独抽象类
# 组件构建原则
组件是软件的部署单元,是整个软件系统在部署过程中可以独立完成部署的最小实体。构建组件应遵守以下基本原则
- REP: 复用/发布等同原则。软件复用的最小粒度应等同于其发布的最小粒度。
- 表现为组件每个版本有明确的功能范围
- CCP: 共同闭包原则。将由于相同原因而修改,并且需要同时修改的东西放在一起。将由于不同原因而修改,并且不同时修改的东西分开。
- 表现为代码变更时,只需要修改一个组件
- CRP: 共同复用原则。如果两个类之间没有共同的复用,那么它们就不应该发生直接的耦合关系。
- 表现为组件之间的依赖关系尽量简单,没有无用的依赖
# 组件聚合原则
REP和CCP属于粘合性,CRP属于排除性原则,架构师需根据不同的研发成本和成熟度上,在三个原则间做取舍
# 组件耦合
组件间应该遵循以下原则:
# 无依赖环原则
组件依赖关系图中不应该存在环。当出现环时,可通过引入一个新的组件来打破环,这个新组件负责管理环中的依赖关系
# 自下而上设计
组件结构图会随着软件系统的变化而变化,所以不可能在系统构建的最初就被完美设计出来
# 稳定依赖原则 SDP
一个经常变更的组件不应该被难以修改的组件所依赖,否则会延续这个难以修改的问题。
稳定性指标:
- Fan-in: 入向依赖,一个组件被多少个组件依赖
- Fan-out: 出向依赖,一个组件依赖多少个组件
- I: 不稳定性指标,I = Fan-out / (Fan-in + Fan-out),I=0表示最稳定,I=1表示最不稳定