刚工作时,经常听到一句话:不要过度设计。
于是很多人对接口、抽象层、设计模式都保持警惕。
代码一旦多出几层结构,就容易被怀疑是在"过度设计"。
但工作几年之后,我慢慢有了不同的理解:
很多所谓的"过度设计",其实只是设计错误。
"过度设计"是错误的切入视角,因为设计本身并不会"过度"。
真正的问题,是设计落错了地方。
软件系统中,总有一些东西会变化:
-
不同厂商设备
-
不同算法实现
-
不同数据来源
-
不同运行环境
这些地方,可以称为变化点。
如果变化点没有被很好地隔离,变化就会沿着系统结构不断传播。
与变化点对应的是稳定面。
稳定面是系统中尽量保持不变的接口或语义,其它模块依赖这些稳定面,而不是依赖具体实现。
好的设计,本质上只是在做一件事:
在变化点和稳定面之间建立清晰的边界。
当这个边界足够清晰时,变化通常只会影响很小的一部分代码。
可以把这理解为变化传播半径。
如果新增一种算法只需要增加一个类,那么变化传播半径很小;
如果新增一种算法需要修改很多已有代码,那么变化传播半径就很大。
"过度设计",其实只是因为系统并没有真正的变化压力。
抽象存在了,但它没有隔离任何变化。
而另一种更常见的问题恰恰相反:
系统没有识别变化点,导致变化在代码中不断扩散。
从这个角度看,设计问题其实很简单:
-
无变化而抽象,是错误设计
-
有变化而不抽象,也是错误设计
当然,也存在另一种情况。
有时使用某种模式,并不是为了应对变化,而是为了表达结构关系。
软件设计真正困难的,并不是使用多少模式,而是判断清楚三件事:
-
哪里是变化点
-
哪里是稳定面
-
变化会传播多远
当这些问题想清楚之后,很多设计决策就会变得自然。