- 行业动态 >
- 资讯详情
“整洁代码根本就是个骗局”
我对《Clean Code》(代码整洁之道)这本书又(yòu)爱又(yòu)恨。
多(duō)年以来,在我教授的一门专业软件工程师课程中用(yòng)到了这本书。这本书我反复读了十几遍,每次都有(yǒu)新(xīn)的收获。话虽这么说,但我发现书中有(yǒu)一半的内容都是错误的。我希望涵盖从这本书、其他(tā)人、我的导师以及我自身的经历中學(xué)到的经验教训,但我想从怎样的代码才是“整洁的代码”说起;更准确地说,从怎样的代码不是“整洁的代码”说起。
怎样的代码不整洁?
判断代码是否整洁的问题在于,这个目标完全是主观的。如果你让七位经验丰富、功成名就的软件工程师来定义整洁的代码,那么最终他(tā)们会给你七个迥异的定义。《Clean Code》一书的第七章已经证明了这个观点。
另一方面,脏乱的代码是非常客观的。我可(kě)以编写一段代码,每位看到的工程师都同意这段代码一团糟。
这意味着从脏乱的代码到整洁的代码有(yǒu)一个范围,一端是客观的,而另一端不是客观的。下图简要说明了这一点。
在上图中,一组工程师对几个代码样本进行了评级。然后,将每个样本按平均分(fēn)排序。我们用(yòng)误差范围表示某个等级的一致度。如你所见,随着平均分(fēn)的提高,评分(fēn)的偏差也随之增大。
如果整洁的代码是主观的,那么我们对于编写代码还有(yǒu)其他(tā)更加现实的目标吗?降低代码的脏乱度算不算一个目标?
定义脏乱
在明确定义代码的脏乱之前,我们首先应该在影响代码实际用(yòng)途的因素优先级上达成一致。我认為(wèi)下面是其中一些重要的方面,没有(yǒu)特定的先后顺序。
高效:使用(yòng)最少的资源(时间、内存等)来完成工作。健壮:即便输入有(yǒu)错,也可(kě)以合理(lǐ)地处理(lǐ)。交付:最小(xiǎo)化交付时间。正确:接收到良好的输入时,返回正确的输出。可(kě)扩展:添加新(xīn)功能(néng)的难度很(hěn)小(xiǎo)。可(kě)运行:最小(xiǎo)化為(wèi)代码达到可(kě)运行状态付出的工作。灵活:改变代码工作方式的难度很(hěn)小(xiǎo)。可(kě)靠:我们很(hěn)自信修改代码不会出错。可(kě)读:将另一位工程师理(lǐ)解代码所需的时间降到最低。这些都是人们在定义整洁的代码时常常讨论的方面。你可(kě)以考虑一下在你心目中这些因素的优先顺序。
虽然我说了这些方面没有(yǒu)特定的优先顺序,但其实则不然,上述顺序与我心目中的优先顺序正好相反。如果代码具备可(kě)读性,那么所有(yǒu)工程师都可(kě)以理(lǐ)解代码,这意味着他(tā)们可(kě)以轻松地实现其他(tā)方面。实际上,“阅读旧代码所花(huā)费的时间比例超过了10:1。每次写新(xīn)代码的时候,我们都需要阅读旧代码。”如果代码易于理(lǐ)解,则易于测试、修改和运行。因此,也易于扩展、修复、部署和改进。最后,如果交付到实际客户的手中,则可(kě)以提高某些地方的健壮性和效率。
因此,我们的优先级可(kě)分(fēn)為(wèi)四层:
可(kě)读。
可(kě)靠,灵活,可(kě)运行。
可(kě)扩展,正确,交付。
健壮,高效。
每一层都服務(wù)于下一层的实现。鉴于此,我们可(kě)以将脏乱的代码定义為(wèi)难以阅读的代码。
代码的可(kě)读性因人而异,因為(wèi)每位开发人员的经验水平各不相同,熟悉的软件范式、编程语言、代码库、编译器、操作系统等也不尽相同。而且最重要的是,读代码的人与作者之间从来都没有(yǒu)完全相同的文(wén)化和词汇。我们力求做到為(wèi)大多(duō)数人提供最方便阅读的代码。
Suess博士的著作《The Cat in The Hat》(戴帽子的猫)的读者数量超过了James Joyce的著作《Ulysses》(尤利西斯),也是因為(wèi)这个原因。因為(wèi)前者的受众范围更广,读起来更简单。当然,我们可(kě)以争论哪本杰作更伟大,但是我们不会争论哪本书的阅读难度更高。
我认為(wèi),在审阅代码这件事上,傻瓜比天才更出色(这也是為(wèi)什么我认為(wèi)我很(hěn)擅長(cháng)代码审阅)。当一个傻瓜遇到一段聪明、预料之外、有(yǒu)副作用(yòng)、不容易懂的代码时,他(tā)们会為(wèi)之苦恼,因此他(tā)们会毫不犹豫地指出这些问题。而当一个天才阅读这段代码时,他(tā)们的大脑会飞快地运转,并在短时间内消化所有(yǒu)的代码。尽管傻瓜遇到问题时不一定知道该如何修复,但代码审阅过程中,确定问题确实存在才是关键的第一步。
因此,傻瓜和天才都有(yǒu)各自的弊端。幸运的是,无论你认為(wèi)自己更倾向哪一种,都可(kě)以坚持做好一件事情:不断提高自身,以及编写代码的能(néng)力。
工匠精神
没人能(néng)在學(xué)习建筑的第一天就建造出泰姬陵。无论你身处何处,眼前都有(yǒu)一段很(hěn)長(cháng)的路需要走下去。严格来讲,每个人距离完美都遥不可(kě)及。
作為(wèi)一名作者,是撰写骗取点击量的文(wén)章,还是撰写有(yǒu)意义的文(wén)章,二者之间有(yǒu)本质的區(qū)别。大千世界里这两种类型的作者都不罕见,可(kě)能(néng)骗取点击量的文(wén)章确实可(kě)以获得更多(duō)的点击。但是你想成為(wèi)哪一种呢(ne)?
作為(wèi)一名工匠,你不必担心人们的赞美或衡量最终结果的标准,你应该為(wèi)自己的全力以赴而感到自豪。此外,你还需要不断提高自己的技术力。
工匠的作品会受到同行业中其他(tā)人的称赞,而那些不懂行的人往往会忽视。工匠关心的是作品的质量,对于编写代码来说,就是代码的可(kě)读性。你的代码不一定完美,但你应该努力将脏乱度降到最低。除此之外,你应该原谅自己过去的一无所知。最重要的是,你应该向所有(yǒu)人學(xué)习,甚至是那些不了解你的才能(néng)的傻瓜。
速度很(hěn)重要
你的产品和项目经理(lǐ)会很(hěn)关心你的速度。关心质量是你的本职工作。一位出色的经理(lǐ)明白,无论从时间还是金钱上来讲,工程都是编写代码的过程中最昂贵的部分(fēn),因此优化这部分(fēn)资源在金钱的角度来看也很(hěn)有(yǒu)意义。高质量、可(kě)读性强的代码可(kě)以最大程度地减少繁琐的代码债務(wù)并提高速度。然而,更常见的是幼稚的经理(lǐ)只看重当前冲刺或季度冲刺的收益。
想象一下,你找了一家公司处理(lǐ)税務(wù)。公司就像你的经理(lǐ)一样,希望工作人员尽快完成尽可(kě)能(néng)多(duō)的税務(wù)评估,以确保他(tā)们可(kě)以获得最大利润。但是,如果税務(wù)专业人员的工作质量不佳,那么就让会让公司面临诉讼、声誉受损和長(cháng)期失败的风险。保证工作质量,并防止这种风险是税務(wù)工作人员的责任。每个职业都是如此。律师与服務(wù)的公司,医生与医院,机械师与商(shāng)店(diàn)。如果你事先知道某个员工不愿意坚守工作质量,那么你还愿意雇佣他(tā)们吗?软件工程师也不例外。
工匠应该在不牺牲工作质量的情况下尽快交付产品,他(tā)们对此持有(yǒu)坚定的立场。所以,我们的问题是,如何在编写高质量(具有(yǒu)可(kě)读性)的代码和经理(lǐ)能(néng)够忍受的交付速度之间取得平衡?对我而言,找到最佳平衡的方法是:首先编写代码来解决和理(lǐ)解问题,再经过可(kě)读性的优化后,最后交付代码。通常,我知道我的代码仍有(yǒu)改进的空间,但是就我的技术水平而言,如果这些改进是显而易见的,那么我会在第二次修改代码时改进。而且之后我还会在每次修改代码或添加新(xīn)功能(néng)时,反复改进。
编写脏乱度较低的代码
关于如何编写更好的代码,网上有(yǒu)大量的媒體(tǐ)讨论,例如书籍、博客、视频等等。通常他(tā)们都会列举你需要遵守的一系列规则。然而问题在于,这些规则之间往往是相互冲突的。很(hěn)多(duō)人都认為(wèi)这些规则并没有(yǒu)什么用(yòng),或者是可(kě)以忽视的观点。的确,在软件开发中,每个规则都可(kě)能(néng)有(yǒu)例外,但是不能(néng)仅仅因為(wèi)你无法时时刻刻都遵循这些规则,就否定你应该尽可(kě)能(néng)地遵循它们。
有(yǒu)关这方面的规则有(yǒu)很(hěn)多(duō),我们应该从哪里开始呢(ne)?我的建议如下:
1、有(yǒu)简单的规则,也有(yǒu)复杂的规则。首先學(xué)习简单的规则。这些是你的基础,因此请務(wù)必正确理(lǐ)解这些简单的规则。
2、每个优先级都有(yǒu)各种规则,你首先应该學(xué)习可(kě)读性的规则,然而再學(xué)习第二优先的规则。
3、有(yǒu)些规则可(kě)以频繁使用(yòng),而有(yǒu)些规则仅适用(yòng)于特定情况,请先學(xué)习前者。
4、有(yǒu)些规则是错误的。如果它与许多(duō)更简单、更重要和更实用(yòng)的规则相冲突,那么可(kě)以暂时忽略。
最后,那些相互冲突的规则又(yòu)当如何呢(ne)?作為(wèi)技术人员,这个问题无可(kě)避免,你应该根据需要解决的问题,选择更优先的规则。
今后该怎么做?
逐步建立属于自己的一套规则,在编写代码时遵循这些规则。即便遵循这些规则不一定能(néng)够保证你写出整洁的代码,但是最起码可(kě)以降低代码的脏乱度。