概要
软件的可变性,是在设计过程中,开发人员必须处理的核心难题。
如何提升软件的可变性,以便应对不断变化的业务需求?又如何在不穷尽各种变化的情况下,轻松应对真正的变化?这对开发人员提出了更高的挑战。
接下来,让我们探讨一下,在开发设计过程中,我们应该如何应对不断变化的软件情况。
核心思想
- 识别变化,封装变化,扩展变化。
- 通俗点讲,就是在多变中找到不变,封装不变的部分,同时允许对可变的部分进行扩展。
策略1:消除重复
- 核心思想:抽象相似代码逻辑,进行统一处理
- 说明
- 重复是拥有良好设计系统的天敌。它代表着额外的工作,额外的风险,额外且不必要的复杂度。
- 重复的代码,意味着,低内聚,高耦合。也意味着,长期维护成本高。
- 重复的代码,表达的是同一个内容,当这个内容发生变化时,这些重复的代码统统都要修改。
- 因此,消除重复可以提高系统的内聚性,降低系统的耦合性。
- 另外,消除重复的过程,正是一个提高系统可重用性的过程。
- 特别注意:需要适度重用,粒度越小,可重用性越高,但粒度过小,会影响组合复用的效率。
- 以乐高积木玩具为例来解释适度重用
- 一个最小尺寸的1x1的乐高积木,带有一个标准的凸起接口,通过它几乎可以与任何其它乐高积木拼装出任意可以想想的物体,其广泛的重用性是不言而喻的。
- 但是,当你真正尝试用这种粒度的积木完成一个复杂物体拼装的时候,你会发现这是多么痛苦的一件事。
- 因此,我们在一心希望构建美好的重用世界之前,需要先掂量清楚颗粒度的选择。
- 这是DRY原则的一种体现。DRY原则是Don’t Repeat Yourself的缩写,不要重复自己。
- 适用场景
- 当发现 代码结构完全相同 和 代码逻辑结构相似 的情况时,此时可以用「消除重复」治之。
- 常见技术
- 抽象、封装、继承、多态、模板、泛型等
- 统一参数校验、统一异常处理、自定义注解、AOP、核心流程抽象、工具类等
策略2:分离变化
- 核心思想:分离不同的变化方向
- 说明
- 分离不同变化方向,目标在于提高内聚度和可扩展性。
- 分离变化,使得变化局部化,可以降低影响范围,也意味着各个变化方向职责的单一化。
- 在变化的世界里,本质上只存在三个数字:0,1,和N。
- 0,意味着,当一个需求还没有出现时,我们不应该在系统中编写一行针对它的代码。
- 1,意味着,某种需求已经出现,我们只需要使用最简单的手段来实现它,无需考虑任何变化。
- N,意味着,需求开始在某个方向开始变化,次数可能是2,3,…N。
- 不管次数是多少,我们都应该在由1变为2时,就解决此方向的变化。
- 最终,无论N为何值,我们都可以稳坐钓鱼台,通过一个个扩展来满足需求。
- 这是单一职责原则的一种体现。
- 适用场景
- 当一个业务,从1种行为变为2种行为时,此时可以用「分离变化」治之。
- 常见技术
- 模块化设计、模板方法模式、策略模式、SPI机制等
小结:
- 消除重复和分离变化是两个高度关联的策略,它们都是关注如何对原有模块进行拆分,以提高系统的内聚性。
- 接下来,我们关注模块之间如何协作的问题,也就是,如何组合模块来降低耦合度,减少变化扩散。
- 模块之间的耦合点,我们称之为API。
策略3:缩小依赖范围
- 核心思想:降低模块之间的依赖关系,减少变化传播
- 说明
- 依赖关系越大,意味着,耦合度越高,变更的成本也越高。
- 因此,耦合点要尽可能小。因为耦合点的任何变化都会导致双方变化。
- 我们希望任何变化,对当前软件的影响,都可以控制在一个尽量小的局部范围。
- 因此,我们应当隐藏系统的复杂性,调用方知道的越少越好,当变化发生时,调用方的变化也越小。
- 这是最少知识原则的一种体现。
- 特征是,不依赖不必要的依赖。
- 适用场景
- 当一个业务或模块,因为依赖的耦合点过大,而导致随着一个小小的变化而变化时,此时可以用「缩小依赖范围」治之。
- 当一个业务或模块,被强迫依赖不需要的东西时,此时可以用「缩小依赖范围」治之。
- 常见技术
- 中介者模式、外观模式、接口、抽象类、封装等
策略4:稳定依赖原则
- 核心思想:依赖关系应该建立在稳定的方向上,最大限度的降低变更带来的影响
- 说明
- 耦合点的变化,会导致依赖方跟着变化。变更越少,意味着越稳定,变更越多,意味着越不稳定。
- 换句话说,耦合点越稳定,依赖方受耦合点变化影响的概率就越低。
- 因此,我们要站在客户的角度来定义API,而不是站在技术实现是否方便的角度来定义API。
- 其实,这是简单原则的一种体现,也是对极简用户体验的一种追求。
- 一个组件或模块,越抽象,越稳定,越容易扩展。
- 稳定依赖原则,通俗地说就是,组件不应该依赖一个比自己还不稳定的组件。
- 特征是,不依赖不稳定的依赖。
- 适用场景
- 当一个业务或模块,依赖的耦合点变化频繁,且自身跟着变化时,此时可以用「稳定依赖原则」治之。
- 常见技术
- 接口、抽象类、依赖注入(DI)、控制反转(IoC)等
最后
一个容易应对变化的软件设计应该遵从:高内聚低耦合原则。
因此,我们应以实际业务需求的变化,来帮助我们识别变化,管理变化。
架构设计系列文章
- 架构设计系列:什么是架构设计
- 架构设计系列:几个常用的架构设计原则
- 架构设计系列:高并发系统的设计目标
- 架构设计系列:如何设计可扩展架构
- 架构设计系列:如何设计高性能架构
- 架构设计系列:如何设计高可用架构
- 架构设计系列:如何应对软件变化
- 架构设计系列:常用设计模式的实践