12-两遍已太多

95 阅读3分钟

当在做增量开发和软件设计时,有一条很关键的原则,称之为“两遍已太多”。

这条原则描述的是如果在实际工作中落地另一条原则,“代码只在必要时才需要通用”。

一旦我意识到自己正打算将同一份功能实现两遍时,就会开始这个步骤。举个例子,假设我正在开发音频录制功能,在项目之初我只打算支持WAV文件格式。随后我又想往代码中添加针对MP3格式的转化逻辑。那么很显然在WAV和MP3的转化代码中存在共用的逻辑部分,此时我不会复制粘贴其中任何一段代码,而是会立即创建一个父类或是工具类库,并将两种实现的交集部分至于其中。

该原则中至关重要的一点是立即采取行动。我不允许代码中存在两种相互竞争的实现。我当下就将它们合并成了一个通用解决方案。另一个重点是我不会把它抽象得过于通用——抽象之后的解决方案只支持WAV和MP3格式,并不会以其他的方式支持额外的音频格式。

基于“两遍已太多”原则,我们能进一步推导出:

理想情况下,开发者修改某处代码的方式不应该与修改另一处代码的方式近似甚至相同。

这也就是说,开发者不应该在修改B类时,必须“记得”去修改A类。虽然系统内重复代码并非总能被合并且共享,但这应该是我们解决问题的方向。

重构

在重构代码时,这条原则能够帮助你找到代码中值得改善的地方,并且能够给予你一些重构方向的提示。例如你在发现系统中存在逻辑重复的地方时,你应该尝试将他们合并在一起。当另一处重复逻辑出现时,继续将该处合并到刚刚的通用逻辑中,如此重复执行。

也就是说如果有太多的代码需要进行合并,你可以按照对每两处执行一次合并的方式进行增量重构。采取什么样的方式并不重要,只要合并的工作确实能够让系统变得简单就好(易于理解和维护)。有时候你需要判断以什么样的顺序将这些代码合并是最有效的,但是如果你无法判断出来也不用担心——直接对每两处执行一次合并就好了,船到桥头自然直,通常重构的所有问题最后都会迎刃而解。

千万不要将不应该被合并的逻辑放在一起。将两种不同的实现合并在一起常常会给系统创造更多的复杂性,或者导致代码违反了单一职责原则,这条原则告诉我们:任意给定的模块、类或者函数在系统中应该只表示单一的概念。

举个例子,如果你系统中用于代表车和人的代码有轻微的相似之处,请不要通过把他们合并为“车人"类来解决这个“问题”。这样并不会降低复杂性,因为车和人的确是两类不同的事物,并且应该由两个独立的类来表示。

"两遍已太多"并不是一则简单粗暴的通用定理。它更类似于在增量开发时,指导我做出设计决策的参考标准。但同时它对重构遗留系统、开发新系统或者只是提升代码的简约性也非常有效。