作者丨Erik Dietrich
翻译丨雁惊寒
摘要:作者通过形象的比喻介绍了劣质代码产生的五个原因,并且说明了劣质代码是开发过程中的必然产物,而消除劣质代码则是一场持久战,需要花时间花精力去解决。以下是译文
人们可能会认为判断代码质量的标准是主观的。当我使用Pascal变量命名法时,你却使用驼峰变量命名法,有人会用这些术语来谈论代码的“质量”,但是我并不想这么做。
所以,让我们来根据可观察到的结果来谈谈代码质量吧。在阅读代码的时候,你可能会根据经验来判断某个陌生的代码质量很差。这是谁写的代码?!你并没有去详细地了解一些情况就非常武断地就做出了这个判断。这段代码在生产中出的问题是最少的吗?应用程序的功能是否满足需求?项目团队是否能够按时按预算持续地进行交付?最好的情况就是,在你阅读代码的过程中得到这些问题的答案。
我个人在学习代码方面有一定的优势。因为我是一个顾问,专门从事代码评估、开发人员培训和团队战略方面的工作。所以,当客户的代码存在很多问题、应用程序不能满足要求、项目超期或者预算超支的时候,我就会接到来自客户的求助电话。事实证明,没有哪个客户会打电话来说:“嘿,我这里一切都很好,但你能来看看我们到底做得怎么样吗?”
所以,对于已经有了坏味道的代码,我不会再去阅读。对此我进行了评估和分析,发现某些代码总是与坏味道有关。下面是我总结出来的导致代码质量变差的五个因素。
1. 可变的全局状态
在你定义了一个作用域是整个应用程序范围的变量时,就会产生全局状态。整个应用程序的作用域范围被称为“全局”,而在其中存储的信息就是“状态”。当这些变量发生变化时,就产生了“可变的全局状态”。
对于这个的优缺点,人们可以没日没夜讨论个不停,你经常会听到有人把全局状态称为“邪恶的化身”。在这里我不会涉及神学或道德,而是从使用效果来谈论可变全局状态。全局状态会使你的代码难以理解。
我来打个比方:假设有人蒙上你的眼睛,然后要求你根据开关的状态来推断房子里的灯是否亮着。卧室是否亮着?它的开关是在“开”那个位置吗?是的。那么厨房里的灯呢?噢,这有点棘手,因为有两个开关可以控制那个灯。但我们仍然可以推断出灯的状态。
现在想象一下,假使城里的每一个人都有一个控制灯的开关。如果你试图根据开关的状态来推断灯是否亮着,那你会很快就会放弃,因为最好的办法就是直接观察灯的状态。这个例子很形象地描述了什么是全局状态。任何人都可以随时随地改变它。所以如果你想推断它的值,则你需要运行代码,看看会发生什么。
2. 代码重复
受代码折磨的第二个因素是代码重复。你可能会把这个称为“复制粘贴式编程”。它就是通过简单地复制粘贴代码块来实现同一个功能,达到重用代码的目的。
这种行为会给代码库带来噪声。如果你将相同的代码复制10次,而不是将其抽象出来以供调用,那么就会产生10倍的代码量。代码越多,意味着复杂性越高,出错的几率也越大。要让代码经受得住时间的考验,就需要尽可能地降低代码的复杂度。
除了噪声问题之外,重复的代码也会引入错误,并带来更多的工作。它会引入错误,因为它会让你忘记调整你需要调整的东西。它会带来更多的工作,因为当这段代码需要修改时,你必须记住在10个不同的地方同步做出修改。但是,维护者们经常会忘记一两个地方,并且这些重复的代码会随着时间的推移而发生变化,对于相同的问题留下了10个并不完全相同的解决方案。
3. 无人关心的依赖关系
有一种说法,软件架构的核心是对依赖的管理。我个人认为这是软件设计的核心以及最困难的问题。依赖管理存在于你写的每一个类、每一个函数,以及你所做的一切。如果你看一下OOP的SOLID原则,你会发现这所有的一切都与依赖管理相关,而且有两个直接与之对应(分别是I和D)。
糟糕的代码杂糅在一起。模块之间互相依赖,仅仅是因为一些无聊的方法调用。你导入整个的JavaScript框架,只是为了执行最基本的计算。有人甚至会在代码中引入与程序集的循环依赖。
请把代码和架构看作是对抗某一种熵的永无休止的战斗。默认情况下,如果没有特意地进行干预,代码就会变成意大利面条。所以,在无人关心依赖关系的代码中,你会发现代码质量很差。
4. 不透明
在讨论代码质量时,通常会听到有人谈论代码的可读性。对于质量差的代码,那些不熟悉并试图阅读它的人简直就是在煎熬。糟糕的命名、奇怪的格式和大量的代码都会让可读性变差。
这里,我要概括一下这一点,并谈论一下代码的不透明。显然,难以阅读的代码是不透明的。但也存在其他形式的不透明。比如代码的抽象很难理解,或者也许你有一个类,其方法之间调用复杂,从而使调用该类的逻辑不透明。
一般来说,人们希望能看到能够清晰地表达其意图和目的的代码。而不透明性掩盖了这一点,导致代码质量变差。
5. 缺少自动化测试
是的,自动化测试可以帮助你发现错误。但在我看来,它对代码质量的最大影响并不是这个。一个健壮、维护良好的自动化测试套件能让你对修改代码充满信心。
修改代码的信心并不会直接转化为代码质量。但是,它能让你更加方便更有信心地重构代码,以改善上面所提到的所有问题:远离全局状态、消除重复代码、最小化依赖关系、并使你的代码更清晰更干净。
如果没有自动化测试套件,人们就不会有这种信心。他们会将代码看成是一种古老的设备,“它目前工作的很正常,所以,无论如何都不要去碰它”,这实际上就是代码质量差的标志。
避免劣质代码是一场战争
在谈论代码质量的时候,似乎代码的质量很容易判断。我花了很多时间与团队一起降低代码的总体拥有成本,因此客户那里的开发人员通常认为我是根据他们所做的工作来判断代码质量的。
但真的,我做得越多,我判断的就越少。首先,我不知道他们遇到了什么样的困难,代码是如何成为现在这样子的。代码库会很自然地变得乱七八糟,除非你认真努力去防止这种情况的发生。劣质代码是默认状态。所以并不是说他们写了劣质代码,而是他们没有时间和资源去阻止代码变差。
认识到这种观点对团队和管理者都是有益的。除非你投资于你的团队、你的教育和你的发展过程,否则代码的维护成本会越来越高,而且质量也会越来越差。所以,请立即行动起来吧,防止出现我在这里讨论过的问题。