错误的抽象

重复是比错误的抽象更便宜。看到重复事物,我们总是试图从重复中抽象出共同点,这其实属于过度设计,反而给代码带来更高的维护拓展成本。

duplication is far cheaper than the wrong abstraction

prefer duplication over the wrong abstraction
宁愿重复而不要错误抽象。

来看看下面的模式:

1.程序员A看到有重复代码。

2.程序员A提取重复并给它一个名称。
这创造了一个新的抽象。 它可以是一个新的方法,或者甚至一个新的类。

3.程序员A用新的抽象来替换了重复。
啊,代码是完美的。 程序员A快乐地走了。

4.时间流逝一段时间以后。

5.一个新的需求出现表明当前的抽象几乎不是完美的。

6.程序员B被赋予需求实现执行的任务。
程序员B觉得保留现有的抽象有价值,但由于对于每种情况不完全相同,他们改变代码采取一个参数,然后添加逻辑基于该参数的值进行有条件地做相应的功能。

一个普遍的抽象现在对于不同的情况表现不同。

7.另一个新的需求又来了。
程序员X.
增加另一个附加参数。
增加另一个新的条件。
这种情况不断重复,直到代码变得不可理解。

8.你如果出现在这个故事里,你的生活就会变得更糟。

存在即合理?因为现有代码施加强大的影响。 它的存在证明它是正确和必要的。我们知道代码代表了我们付出的努力,我们非常积极地保持这种努力的价值。 但是,不幸的且可悲的事实是,越是复杂和难以理解的代码,也就是花费更多努力去创造它,维护拓展它就越感到压力。潜意识告诉我们,“天啊,这是如此混乱,它一定是花费了很长时间才到达现在正常运行状态。这真的很重要。如果抛弃它将是一种罪过,让所有的努力付诸东流。”

当您出现在此故事中上述步骤8中时,这种压力可能迫使您前进,即通过更改现有代码来实现新需求。 然而,这样做更是残酷的。 代码不再代表单个、共同的抽象,而是成为一个依靠ifelse条件判断的过程化程序,交错一些模糊的相关想法。 这是很难理解和容易打破。

必须采取以下操作让错误不再循环下去:
1.通过将抽象代码重新放回每个调用者,引入重复。
2.在每个调用程序中,使用传递的参数来判断该是哪段重复代码片段执行。3.删除调用者不要的代码。

删除了抽象和条件语句,并减少代码,保留调用者只需要的代码。 当你以这种方式回滚决策时,通常发现尽管每个调用者都表示调用了一个共享抽象,但它们运行的​​代码是相当独特的。 一旦你完全删除旧的抽象,你可以重新开始,重新隔离重复和重新抽取抽象。

但是,人们总是试图勇敢地推进错误的抽象,却很少有成功。 添加新功能是非常困难的,每次成功进一步促成更复杂的代码,这使得添加下一个功能变得更加困难。 当他们从“我必须保护我们对这段代码的投资”改为“这段代码有一段时间,但也许我们已经从中学到了所有东西”,并允许他们根据当前要求重新考虑他们的抽象,一切都变得更容易。 一旦他们撤回抽象代码,前进的道路变得明显,添加新功能变得更快更容易。


The Wrong Abstraction — Sandi Metz