开发设计实践:如何应对软件变化

软件的可变性,是在设计过程中,开发人员必须处理的核心难题。

如何提升软件的可变性,以便应对不断变化的业务需求?又如何在不穷尽各种变化的情况下,轻松应对真正的变化?这对开发人员提出了更高的挑战。

接下来,让我们探讨一下,在开发设计过程中,我们应该如何应对不断变化的软件情况。


核心思想

  • 识别变化,封装变化,扩展变化。
  • 通俗点讲,就是在多变中找到不变,封装不变的部分,同时允许对可变的部分进行扩展。

策略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)等

最后

一个容易应对变化的软件设计应该遵从:高内聚低耦合原则。
因此,我们应以实际业务需求的变化,来帮助我们识别变化,管理变化。

你可能感兴趣的:(架构设计系列,设计规范,开发设计)