“我们如何证明,通过遵循“代码整洁之道”(Clean Code)就可以编写更多的代码呢?”
当人们试图将“代码整洁之道(Clean Code)”的原则应用于现有的代码库时,我经常会问这个问题。
我认为这是合情合理的。
当我们开始重构遗留代码时,通常会将内容提取到较小的方法中。然后再将方法提取到类中。很快,我们可能就能感觉到原来30行的方法现在已经分散在不同的类中。
我们想知道的是:这在实际上是否是更容易维护了呢。
也许我们是一个小团队。也许我们必须支持我们继承的一个相对较大(并且没有文档记录的)的代码库。
寻求代码可维护性是一件好事。
错误在于,认为代码可维护性与代码行数(lines of code,LOC)相关。LOC可能是一个有趣的度量指标,但它并不是关键所在!
不要使用LOC作为代码可维护性的度量指标。
如果你对此有所怀疑,那么应该看看“短码之美(Code Golf)”。
当我们进行“短码竞赛”时,我们的目标是找到一些聪明的技巧,用最少的代码字符来实现相同的功能:
// 31 个字符
Math.floor(Math.random() * 100)
// 21 个字符
~~(Math.random()*100)
// 19 个字符
Math.random()*100|0
但当然,这只是一个“strawman”的论点!
我相信我们不会以“短码竞赛”的方式来编写生产中的代码。
然而,有一个重要的原则,我们需要记住:
代码不是我们告诉计算机怎么做的方式;而是告诉另一个程序员我们想要计算机做什么的方式。
简而言之:编写代码是要供他人阅读的。
易于理解的代码才是易于维护的代码。
还是,难道我们还不够聪明,而无法阅读冗长的函数吗?出于可读性的考虑,添加一堆一次性使用的助手函数又有什么好处呢?
如果这些问题能引起我们的共鸣,那么我们需要知道一个秘密……
任何极端的做法都是有害的。
即使是遵循“代码整洁之道”的原则。
我们正在尝试一些事情。当然,我们可以按照最佳实践来重构代码,但这同时也会增加了维护的难度。如果我们为了达到此目的而只是封装了一个条件语句,那么它可能没有帮助!
不,我们不应该为了可读性,而将所有内容都提取到“一次性助手函数”中。如果我们每次阅读代码时都需要阅读这些函数的主体,那么这一点也没有帮助。它只会是阻碍。
我们应该做的是,创建正确的抽象。
正确的抽象,正确地划分职责。它们阐明了代码的意图。它们可以防止代码重复。
当我们找到正确的抽象时,我们会觉得这4个类实际上比原来的30行代码更易于维护。
但是,要找到正确的抽象确实很困难。因此,这就是我们应该关注的重点。
你是否听说过“不要重复你自己(Don’t Repeat Yourself,DRY)”原则?
这是一颗共同发展智慧的明珠,而且非常有效。但它也经常被误解。
两段代码看起来是一样的,但却代表了不同的概念。不同的抽象。在这种情况下,重复是偶然的。保留重复会更好。
“重复与错误的抽象相比,代价要小的多” —— Sandi Metz, 所有的小事
什么时候应该将代码提取到函数/方法/类中?什么时候应该保留重复?我们怎么知道我们有正确的抽象呢?
Also called Write Everything Twice (WET). Pun intended.
这也称为“什么都写两遍(Everything Twice,WET)”。这是个双关语(与DRY原则相对)。
“三次重复攻击,就重构”
重构原则“Rule of Three”是一条经验规则,当我们有疑问时可以使用它。
在引入抽象之前,请等待第三次重复的出现。出现重复的次数越多,就越容易找到要提取的共性。
遵循“Rule of Three”原则。它能使我们更容易地找到正确的抽象。
这里的“Rule of Three”原则是为了提醒我们,重复是可以的。
这也有点教条。就像“代码整洁之道”的原则一样,不要在任何时候都盲目地100%应用它。
有时,即使出现了3次重复,我们也可能找不到正确的抽象。不要强求对代码库进行过度的抽象。如果我们不能给它起一个清晰的名字,它就确实不够清晰。
毫无疑问,违反规则是可以的。等待更多的重复。
宁可重复,也不要错误的抽象。不要为了抽象而创建抽象。
如果抽象不好,则必须使用布尔型的参数和if语句来简化它的实现,以覆盖新的用例。这只是一种暗示、一种警告,告诉你你走错了方向。
如果我们还没有找到抽象的话,那也没关系。当我们有了更多的上下文时,仍可以重构它。等着瞧吧!
原文链接:
https://understandlegacycode.com/blog/refactoring-rule-of-three/
领取专属 10元无门槛券
私享最新 技术干货