模块化工程
动机
人类对事物的认知过程是递归的。举个例子,我们如何识别一个物体是汽车,先看到一个物体,它有底盘、车架、外壳、内饰,看到这些我们觉得这可能是汽车,也可能知识汽车的模型。再打开机盖能看到发动机、变速箱,车底能看到车轮,我们进一步识别到这是一部真实的汽车。

随着我们一步步深入看到更多的汽车组成部分,我们便更确定这是一台汽车,这就是对一部汽车的递归认知过程。
而对于天气,它是一个异常复杂的系统,我们很难直观的对其进行递归分析,这也是我们无法精准预测天气的原因。人类对事物的认知能力是有极限的。
一辆汽车由数万个独立部件组成,很难说它不是个复杂系统,为什么我们可以很容易对它做递归分析。我们可以看到汽车是个高度模块化的系统,我们对它做递归分析的过程,实际上就是对其进行模块化拆解的过程。
直接分析复杂系统很困难,但只要它能够拆解为独立的更小的模块,我们总能够将之拆解到一个简单系统层次,然后再去分析识别,最终实现对这个复杂系统的完全认知。
一个系统越容易进行递归分析,我们越容易理解它,进一步,也越容易改造它。对于汽车如此,对于软件系统亦如是。
软件工程的一个重要目标就是要令开发的软件系统更易扩展和维护,通过模块化方式构建一个系统,会令该系统易于理解,也就更容易实现这一目标。
额外的好处
除了令系统更容易被递归分析外,还具有以下好处:
- 可重用:具备抽象良好接口的模块,可以很容易被重用,特别是基础组件。业务系统研发过程中,通过不断优化模块最终沉淀到最下层的模块通常与具体具体的业务语意无关了,自然而然就变成了可被重用的公共组件。
- 可以灵活部署:不同的模块可以打包在一起部署,也可以利用SOA工具分布式部署。
- 富有弹性:模块可以独立进行资源伸缩,提升整个系统的弹性。例如:汽车动力不足,可以加装一个发动机,实现四驱(这也是现在大部分电动车的四驱方案)。可以提供备胎,替换破损的轮胎。
模块化的障碍
循环依赖:
如果两个模块间有循环依赖,那么当我们通过递归分析时将陷入无限递归,永远得不到结果。两个模块如果有循环依赖,那么他们是无法拆分的,实际上他们只能作为一个模块来使用。
封闭性不足:
如果一个模块不仅开放有限的接口,那么它将可能被其他模块随意依赖,其自身难以被修改,因为它被迫与其他模块进行深度绑定,最终仅能作为其他模块的一部分存在。
例如:如果车轮直接依赖变速箱齿轮进行传动,那么我们只能将变速箱和车轮安装在一起,可以想象这种结构是非常难加装转向装置的。
实际上模块应当遵循所有SOLID原则。
S:Single responsibility/单一权责
O:Open/Closed/开放封闭
L:Liskov Substitution/替换原则
I:interface-segregation/接口隔离
D:Dependency inversion/依赖反转
无法自我管理:
如果一个模块无法管理自身的组件及其数据,那么它将不得不与能够管理这些的模块集成在一起。也就是说它必须与管理这些内容的组件集成在一起。
例如:如果汽车内燃气燃烧室的大小必须由底盘决定,那么我们永远无法制造出可以安装在任意车辆中的发东西。
模块提供的能力特性,必须由自身定义,而不取决于外部环境