四、组件构建原则
组件构建原则是用来指导如何将各个组件组合成独立完成部署的软件系统,组件聚合是常用的组件构建方法。
在软件架构设计中,组件聚合是指将多个相关的组件组合在一起,形成一个相对独立的、可交付的子系统或模块。它的优点:
- 提高可维护性:通过组件聚合,将相关联的组件放在一起,可以减少代码的耦合度,提高代码的可维护性,当需要修改某个组件时,可以避免在其他模块中查找和修改代码,降低出错的风险
- 提高可扩展性:通过组件聚合,可以将系统拆分为多个相对独立的部分,每个部分都可以单独进行扩展和升级。这使得系统更容易地适应未来的需求变化
- 提高开发效率:通过组件聚合,可以将开发任务分解为多个小的子任务,每个子任务相对独立,可以由不同的开发人员同时进行开发,提高开发效率,缩短开发周期
其中有三个基本原则:
1 、REP(复用/发布等同原则)
REP 是一个关注重用性的原则,他要求在设计组件时,尽可能地提高组件重用性,减少重复劳动。
核心思想是将通用功能和行为封装为可重用的组件,以便在多个应用场景下使用
要点
- 识别可重用的组件:分析现有系统和业务需求,找出具有通用功能的组件,如用户信息、日志记录、数据访问等
- 设计可重用组件接口:为识别出的可重用组件定义清晰的接口
- 实现可重用组件代码:为可重用组件编写高质量代码,确保具有可扩展性、可维护性和可测试性
- 文档化可重用组件:为可重用组件编写详细的文档,包括使用说明、参数说明和示例代码等
软件复用的最小粒度应等同于其发布的最小粒度,一般会要求组件的开发由某种发布流程来驱动,并且有明确的版本号,如果没有,就没有办法保证被复用的组件之间能够彼此兼容。比如某数据平台的通用数据结构处理组件等。
建议
- 模块化设计:将系统分解为独立的模块,每个模块专注于一个具体的功能或领域。这有助于识别和构建可重用的组件
- 设计清晰的接口:在组件内部,确保设计清晰、简洁的接口。这样可以降低组件的使用难度,提高可重用性
- 版本控制:使用明确的版本控制机制来管理组件的发布。确保版本升级时的向后兼容性,以便降低对已有系统的影响
- 自动化构建和发布流程:建立自动化的构建和发布流程,以减少发布过程中的错误,提高组件的发布效率
2 、CCP(共同闭包原则)
CCP 是一个关注耦合性的原则,他要求在设计组件时,尽可能地降低组件之间的耦合度,提高组件的独立性。
要点
- 避免硬编码:将硬编码分解为独立的功能模块,使每个模块具有明确定义的职责和边界
- 使用接口而非实现:通过接口定义组件之间的交互方式,不直接依赖实现类,可降低组件之间的耦合度
- 使用事件或消息传递:通过事件或消息传递来实现组件之间的交互,降低耦合度
- 避免全局状态:全局状态会使组件之间的依赖增强,导致潜在的错误和难以维护
建议
- 松散耦合:使用依赖注入、事件驱动等方式来降低组件之间的耦合度,确保修改一个组件不会对其他组件造成影响
- 接口定义:确保使用清晰明确的接口定义组件之间的交互方式,避免直接依赖实现细节
- 消息传递:考虑使用消息传递机制,通过事件或消息进行组件之间的通信,降低直接调用的耦合度
- 避免全局状态:尽量避免使用全局状态,全局状态会增加组件之间的依赖关系,降低系统的灵活性和可维护性
3 、CRP(共同复用原则)
CRP 是一个关注内聚性的原则,他要求在设计组件时,尽可能地提高组件的内聚性,减少组件内部的复杂度。
要点
- 功能单一化:每个组件应只完成单一的功能,避免将多个功能混杂在一起,如此可以提高组件的内聚性和可维护性
- 模块化设计:将代码分解为模块,每个模块都具有明确定义的职责和边界,提高内聚性和可读性
- 减少条件语句:避免在代码中使用过多的条件语句,尽可能将条件逻辑抽象为函数或方法,可以减少代码复杂度,提高内聚性
- 使用设计模式:用常见的设计模式来组织代码结构,提高代码的内聚性和可维护性
建议
- 功能单一化: 每个组件应该专注于完成单一的功能,避免将多个功能混杂在一个组件中。这有助于提高组件的内聚性
- 模块化设计: 将代码分解为模块,每个模块都应具有清晰定义的职责和边界。这有助于提高组件的内聚性和可读性
- 减少条件语句: 避免在代码中使用过多的条件语句,将条件逻辑抽象为函数或方法,减少代码复杂度
- 使用设计模式: 使用常见的设计模式来组织代码结构,提高代码的内聚性和可维护性
4 、思考:
这里的组件聚合原则和前面的 SOLID + CRAP + LoD 原则的区别是什么?
5 、组件聚合张力图
基于对 REP 、 CCP 、 CRP 三个原则的理解,会发现这三个原则之间彼此存在着竞争的关系: REP 和 CCP 是黏合性的原则,基于这两个原则会让组件变得更大,但 CRP 原则是建议拆分原则,会尽量让组件变小,三者共存,如何取舍?
这时候就需要架构师在这三者之间找到平衡,在团队能力水平、业务场景复杂度、发布流程等因素的动态变化中,根据团队状况进行动态调整。
下图是三大原则的张力图,张力线描述了忽视对应原则的后果。
从图中可见:如果架构设计师过于关注 REP 和 CCP,会导致太多不必要的发布。
总体来说,要在三者之间取得平衡,早起可能需要偏向 REP 和 CCP,后期可以逐渐朝着 CRP 的方向发展。这对架构师的要求是很高的,需要架构师在实际的项目中灵活运用这些原则,结合具体情况做出合理适当的决策。
五、组件耦合原则
组件构建原则指导我们如何设计组件,而耦合原则是用来指导我们如何设计组件之间的关系。耦合是指组件之间相互依赖的程度,耦合度的高低直接影响可维护性、可扩展性和可重用性。
1 、常见耦合类型
- 内容耦合:一个组件直接访问另一个组件的内部数据结构或直接调用其方法,耦合度较高,慎用
- 控制耦合:一个组件通过调用另一个组件的接口来控制其行为,相对较松,是设计中常用的耦合方式
- 标记耦合:一个组件通过一组参数来请求另一个组件执行特定操作,比较灵活
- 外部耦合:一个组件与外部系统或环境进行交互。这种耦合方式通常无法避免,但需要尽量减少它对系统内部的影响
2 、控制组件耦合原则
- 最小化耦合原则:尽可能降低组件之间的耦合度,使每个组件尽可能独立工作
- 接口耦合原则:通过接口来定义组件之间的交互方式,而不是直接依赖实现类,以降低组件间的耦合度,提高系统的可维护性和可扩展性
- 依赖倒置原则:将依赖关系建立在抽象层面上,而不是具体类之间,使系统更加灵活和可维护性
- 单一职责原则:每个组件应该只承担一个职责,避免一个组件承担过多职责而导致其他组件对其产生过度依赖
3 、耦合优化路径
在软件架构设计的过程中,需要定期对系统进行耦合度评估,如果出现高耦合,可以按照以下路径进行优化:
- 分解组件:将高度耦合的组件分解成更小的、更独立的组件,降低耦合度
- 引入接口:通过引入接口来定义组件之间的交互方式,降低直接依赖实现类的耦合度
- 抽象依赖:将具体依赖抽象化,通过抽象层来控制组件之间的依赖关系,降低直接依赖具体类的耦合度
- 重构代码:对代码进行重构,优化代码结构,降低代码的复杂度,提高代码的可读性和可维护性
组件耦合原则对于软件架构的健壮性和可维护性至关重要。通过遵循控制组件耦合原则,软件设计者可以建立灵活且可扩展的系统,提高系统的稳定性和可维护性。在设计和开发过程中,不断优化耦合关系,确保系统在不同阶段都能够维持良好的设计质量。
六、识别软件架构设计的复杂度
在进行软件架构设计时,识别复杂度是非常重要的一环。以下是一些方面,可以帮助你在架构设计中识别和评估复杂度:
1 、需求分析
深度了解业务需求、功能需求和非功能需求是进行架构设计的输入,也是评估复杂度的关键因素。为了更好地分析需求,建议你把需求分解为更小的部分,有助于更好地理解需求和评估复杂度。
2 、关键元素
架构设计时,一般场景中包括以下关键元素,而对这些关键元素的特性、关系和交互方式是评估复杂度的关键:
- 数据库
- 服务器
- 网络带宽
- 安全合规
3 、评估交互
分析不同元素之间的交互同样,也是架构设计过程中进行复杂度评估的一个核心点。比如数据传输、调用方法、发消息等。架构设计时,需要对这些交互方式可以进行识别和评估,比如频率、数据量、时效性等。
4 、性能和扩展性
对于任何系统来说,高性能和可扩展性是基本要求。性能维度主要考虑 RT 、 QPS 等指标。
扩展性是关注你设计的系统架构是否能适应业务增长和新技术引入。
5 、安全性
安全是一个系统架构必须考虑的重要因素,包括系统身份验证、用户授权、数据隐私合规等。
同时安全性还需要考虑潜在的攻击面、敏感数据的暴露程度和合规要求。
6 、技术债
对现有系统进行架构重构和升级时,是一定要了解现有系统的技术债务,比如代码结构、代码规范、代码质量、技术栈的兼容性、测试覆盖率等。这对系统的架构重构和升级至关重要。
7 、人员技能和经验
团队成员的技术能力、技术经验和熟悉的技能、工具、语言等都会影响架构设计的难度和复杂度。
8 、风险评估和管控
在设计过程中识别可能的风险因素,这些风险都会成为架构设计的复杂度,需要对识别出来的风险制定和实施有效的风险管控策略。
9 、迭代和反馈
采用迭代式的研发模式,从每个迭代中学习并及时调整。
通过收集反馈和监控指标,更好地理解复杂度并进行优化。
10 、文档和沟通
确保有清晰的文档记录,包括需求文档、技术文档和代码注释。
有效的沟通可以确保团队对架构设计方案有一致的理解,降低复杂度。
综上所述,通过全面考虑这些方面,才能够更好地识别和评估软件架构设计中的复杂度,并采取相应的优化策略。
11 、思考:
在你现在参与或者负责的系统中,从架构设计角度都有什么样的复杂度?
七、识别软件架构设计的风险项
在软件架构设计过程中,对可能出现的风险因素进行识别、评估和解决是至关重要的,以下是一些常见的架构设计风险和相应的识别与解决方法:
1 、需求变更风险
风险识别
过度的需求变更可能导致架构设计的频繁调整,增加开发成本
解决方法
在架构设计阶段,充分了解业务需求,进行详尽的需求分析和业务建模,以减少对需求变更的敏感性
2 、技术债务风险
风险识别
技术债务可能由于技术决策的短期利益而产生的长期问题。比如选择不合适的编程语言、框架等会都会增加架构设计的复杂度和维护成本
解决方法
在架构设计阶段,对现有系统的技术债务进行评估和管理,确保技术决策考虑了长期影响
3 、性能风险
风险识别
性能是考虑一个软件产品系统的重要指标,如果性能不行,你的架构再厉害都是无稽之谈。性能风险包括响应时间慢、吞吐量低、高并发处理能力不足、大数据处理能力差等
解决方法
在架构设计阶段,需要对产品系统的性能进行充分评估和优化,确保设计出来的架构满足性能需求
4 、扩展性风险
风险识别
业务和技术都是不断往前发展的,要求系统架构是能够适应业务的增长和新技术的引入。如果架构不具备扩展性,就会导致系统架构无法适应未来的业务增长和新技术的引入
解决方法
在架构设计时,设定目标,确保架构在一定时期内不需要变动,并具备在三年内通过配置化、灵活扩展的方式支撑业务变化的能力
5 、安全性风险
风险识别
安全性一般包括身份验证、授权、数据隐私合规、资金安全等,这些一旦出现风险会导致数据泄露、系统被攻击、资金亏损等
解决方法
在架构设计阶段,要对业务场景进行全面的分析,对安全层面的风险进行充分评估和应对方案的设计,确保系统可以具备强安全性
6 、维护性和可读性风险
风险识别
缺乏维护性和可读性会导致系统难以维护和更新
解决方法
在架构设计时,要注重代码的清晰结构、规范和文档记录,确保系统具备良好的维护性和可读性
7 、集成风险
风险识别
与其他系统或组件集成时可能出现的问题,如接口不兼容、数据格式协议不一致等
解决方法
在架构设计阶段,充分考虑集成问题,定义清晰的接口和协议,进行充分的集成测试
8 、项目管理风险
风险识别
成员技能不足、沟通不畅、进度管控不当等问题可能导致项目失败
解决方法
在项目管理中,注重团队成员的培训与技能提升、有效的沟通机制、合理的进度管控和风险管理
9 、思考
在你现在参与或者负责的系统中,从架构设计角度都有什么样的风险?
总结
软件架构设计是一个综合性的过程,需要考虑多个因素。需要遵循设计原则、构建原则、耦合原则,识别复杂度和风险以及有效地解决风险,是构建可靠、灵活和可维护性软件系统的关键。同时,通过团队的不断学习、迭代和有效的沟通,可以更好地适应业务和技术的变化,确保软件系统的长期健康。