大规模软件系统的产品周期
随着产品的不断发展,复杂度不断增加,生产率(Features数量)下降,质量(Bugs)不受控制,稳定性(Fluctuation)变差,架构变得腐化。
原则、模式、最佳实践和工具集
架构优化原则
1.单一职责
2.领域内聚
3.抽象接口隔离
4.重用
5.管理架构资产
模块解耦模式
1.模块重新划分
表现:
一个模块在领域中内聚性不强,而和某个领域的耦合性很强
解决方案:
模块重新划分领域,保持领域及模块的内聚性,必要的情况下可以拆分该模块到不同领域。
2.通用抽象模式
表现:
各领域实现了相同或相近的业务逻辑,导致维护工作量大,架构不一致
解决方案:
抽象出各领域的通用逻辑,并在应用框架(Application Framework)上进行实现,各领域继承该通用逻辑,并且可以插入扩展点,各领域实现差异化实现插件。
3.消除强耦合(循环依赖)
解耦方式:根据耦合关系的处理方式,分为
- 耦合上升
- 耦合下沉
- 回调
- 依赖倒置
- 消除耦合关系
数据解耦模式
1.数据共享模式
表现:相同或相关数据在跨领域被创建、转换或传输,存在重复、冲突等问题
根据策略提供多种解决方案:
1)数据重新划分领域,如足够通用的数据划分到通用基础数据供各业务领域共享,而错误划入通用基础数据的业务数据被重新划入业务领域;
2)跨领域的复杂数据,划分抽象通用数据及和业务领域相关数据,采用通用数据共享,而和业务相关的数据则分业务领域存储;
3)通用数据分领域视图,对有领域通用并且有业务组织权限的数据,对各不同领域提供不同视图
2.数据拆分模式
表现:
集中数据方式下,当企业的业务量激增后,导致集中式数据库成为整个系统的性能瓶颈
解决方案:
分领域拆分各自的数据Schema,逻辑上进行拆分。可以根据业务量的需求,部署在一个数据库实例,或者分领域部署在不同的数据库实例中。
架构最佳实践
1.API抽象(服务)层
问题:
各领域之间存在直接调用,互相循环调用,甚至不合理调用的情况,各领域之间蜘蛛网式的耦合关系,导致一个问题互相影响,问题跟踪起来困难,各领域之间很难独立发布版本。
解决方案
各领域之间的调用都采用标准的API方式服务接口,领域调用采用服务接口消费的调用方式统一管理,各领域之间存在了一个接口隔离层,不会导致互相影响或影响比较小,各领域在接口稳定的情况下可以独立发布版本。
2.事件总线(EventBus)
问题:
原来的应用框架采用继承方式来提供扩展性,导致继承层次很多,逻辑复杂,框架的可维护性差,可演进性差,同时在分析问题时不知道问题出在框架还是业务,诊断成本高
解决方案
采用EDA架构,EventBus构成框架的核心交互组件,通过事件分类应用的不同扩展点,各层的业务根据事件定制自己的可插拔扩展插件,降低了各领域系统和框架的依赖关系,增加了框架的可扩展性和可演进性。提供框架的API及通用的服务实现,各业务领域可以跟进各自的需要进行重新实现和替换。
工具集
1. 模块代码依赖关系分析工具,分析各模块的依赖关系,可以生成依赖关系图
2. 模块代码耦合分析工具,分析各模块的实际代码依赖的调用
3. 依赖关系管理插件(开发工具)及持续构建依赖管理工具
4. 数据审计工具,可以分析模块依赖的数据是否是本领域还是跨领域
分析问题制定优化方案
分析问题
1.通过工具,协以分析代码的方式,找出各领域(进一步是各模块)之间的依赖关系
2.数据的依赖通过使用的ORM和SQL进行分析
3.分类是数据依赖,还是代码层次的依赖;是领域间依赖还是模块间依赖
4.依赖是否是必须的依赖,不必要的依赖后面都会消除依赖关系
制定方案
1.根据解耦模式,制定各个模块对应的解耦方案,以消除强耦合依赖关系
2.对于不必要的依赖,必须给出消除的方案,如依赖关系下降到通用模块,完全消除依赖关系等等
3.数据依赖比代码依赖更难处理,谨慎处理数据依赖,包括数据的转换、迁移的成本,影响到对客户迁移的成本
4.需要权衡利弊,并不是完美的解耦就好,而是权衡的结果
制定治理策略,防止架构腐化
1.服务的治理
- 构建统一的服务管理平台,每个领域把自己的服务注册发布服务到服务中心,而消费方领域则注册消费服务到服务中心。
- 跨领域必须提供服务平台进行服务调用,禁止直接调用。根据需要各领域可以集中部署,采用Local调用,或者分布式部署,采用Remote调用。
- 服务的调用提供统一的平台进行监控和管理。
2.依赖关系管理
- 为防止系统的进一步腐化,模块之间的依赖必须管理起来。依赖不能随意添加,必须通过在设计层面统一考虑。
- 持续集成代码构建时检查依赖关系,不符合依赖关系的会导致构建失败。
- 开发工具Eclipse需要安装依赖管理插件。
总结
系统优化重构是一个不断分析、实现、稳定的过程,因此制定出一套符合企业架构优化的方法、模式、工具及规范非常有必要。