译者 | 陈峻
审校 | 梁策 孙淑娟
众所周知,干净的代码不但能够让阅读者方便理解程序的意图,而且也方便维护与迭代。总的说来,它能够给软件的开发与升级带来如下好处:
- 在维护上花费更少的时间。干净的代码更易于被阅读和领会,您可以花费更少的时间去弄清楚实际问题的来龙去脉,进而为修复、修改、以及扩展等操作留下更多的时间。
- 更清晰地交流想法。程序开发离不开协作。而干净的代码往往可以减少项目成员之间可能产生的误解。而且从长远来看,这也意味着更少的错误,更快地解决问题。
不过,正所谓“知易行难”,从某种程度上说,编写干净的代码就像学绘画、烹饪或摄影那样--看起来比较容易,实践起来则比较困难。下面,我将和您讨论能够编写出优秀且干净代码的十大技巧。
1.使用描述性名称
程序中的变量、类和函数,往往是给其他程序员、以及应用程序底层逻辑之间的接口调用的。因此,当您对变量、类和函数使用不明确且非描述性的名称时,实际上就是在扰乱阅读代码者(包括开发人员自己)对应用程序逻辑的理解。例如:您能一眼看出一个名为dxy的变量的实际含义吗?想必,您必须阅读整个代码块,才能对其含义进行“逆向工程”吧。不过,对于变量distanceBetweenXY,你我都能够马上领会到它代表的含义。
同理,类和函数也是如此。请尽量避免使用CalcTan(),而应当按需采用CalculateTangent()或CalcTangentAngle()。总之,使得代码看起来整洁的基本技巧之一便是使用描述性名称。
2. 让每个类/函数都有实际意义
您一定看到过那些长达数百甚至数千行的函数吧?想必,您在浏览、理解、甚至是编辑的时候会觉得无比痛苦。就算行间有相应的注释,其实际效果往往也是“杯水车薪”的。而干净的代码则不然。它们会被分解成不同目的的代码块。其中,每个子函数都被设定为完成某个具体的任务,而每个类也都代表了一个特定的概念。由此带来的简洁性,更适合局部调整,也更适合问题的定位与排查。
例如,在实践中,诸如GetCreditScore()之类复杂的功能,有必要被分解成为GetCreditReports()、ApplyCreditHistoryAge()、以及FilterOutstandingMarks()等多个辅助函数。您可以参考《每个程序员都应该知道的基本编程原则》一文,来进一步了解相关做法。
3.删除不必要的代码
不知您是否有过这样的体验:在修复或优化某段代码的过程中,您特意将其注释掉,并在其下方开始动手重写新的代码。而且,您这样做的目的,只是纯粹为了保留旧的代码,以备不时之需。不过,随着时间的推移,您可能会不知不觉地积累了大量的、不再需要的、被注释掉的代码块。这些代码块无疑会让您的源代码变得混乱不堪。而且,多数实际情况往往是:由于周围的相关代码、及其环境也早已发生了迭代,因此这些被注释掉的代码,其实并不可能再被恢复使用了。
当然,这种注释掉旧代码的做法,完全可以被如今时尚的源代码控制系统所取代。您可以通过使用Git或Mercurial之类的工具,及时、准确、自动化地开展源代码管理工作。
同时,为了让应用服务轻便而敏捷,您也可以有意识地通过现成的Web框架,避免“重复造轮子”,进而利用由框架提供的类库,来简化自己的代码。对此,您可以具体参考《一些值得开发人员学习的Web框架》一文。
4.可读性
大多程序员会把“干净的代码”和“聪明的代码(clever code)”混为一谈,并简单地认为“把十行代码压缩成一行,以减少屏幕空间的占用”,便是干净的代码。其实,在大多数时候,这样的代码不一定真的容易被理解。
在我看来,此类可解决某些专业难题的代码,属于“聪明的代码”范畴。程序员们可以将其视为自己的独门秘籍。它们往往被用来证明自己的编程技能,甚至被用作炫技之需。而对于干净代码的编写,您应该保持开放的心态:代码量的多少,并非代码是否干净的唯一衡量标准。除了实现代码的功能,您的代码还需要保持一定的可读性。毕竟下一次阅读该代码段的很可能不是别人、正是你自己。毕竟,谁都不想给自己的将来刨坑埋雷。
5. 保持一致的编程风格
每个程序员都有自己的编程风格。在此,我并不想推荐或强求大家去遵从某种所谓最佳编程风格。如果您习惯在行间使用大括号,如果您想在方法调用之前加上空格,如果您更喜欢使用制表符而不是空格的话,这些都可以。只不过,请保持此类用法的一致性。
同时,如果您打算将camelCaseNaming用作变量,那么就请不要将其与underscore_naming混为一谈;如果您在某个地方使用了GetThisObject(),那么就请不要在其他地方采用FetchThatObject()。
此外,诸如Python和C#等编程语言,本身就带有各种需要遵循的样式规范,包括:绝不允许制表符和空格的混用等。
6. 选择正确的架构
您可以使用各种现成的范例和架构来创建不同的项目。当然,前提条件是,请选择最适合的,并不是所谓最好的。例如,模型-视图-控制器(Model-View-Controller,MVC)模式一直是Web开发领域最流行的架构。毕竟,它不但有助于您保持代码架构的清晰合理,而且能够使得后期的维护工作量最小。类似地,实体-组件-系统(Entity-Component-System,ECS)模式在游戏开发界也非常流行。毕竟它能够协助实现模块化的游戏数据和逻辑,使得维护更轻松,同时能够生成更加易读的代码。
7. 掌握语言中的惯用法
我们所熟悉的Python、Java和JavaScript等不同的语言,都有着不同的编程思想与习惯。它们之间的差别或是巨大或是细微。例如:Python代码会完全依赖紧凑代码和鸭子类型(duck typing,基于“当一只鸟走起来像鸭子、游起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”的逻辑,我们不必关心对象是什么类型,只要关心它的动态行为即可。);而Java则更倾向于冗长和明确的代码。同时,每一种语言都会鼓励使用自己的惯用法,例如Python中的列表推导式。
与此同时,我们也要警惕所谓的“反面模式(anti-patterns)”。虽然那些由前人积累的、解决某些软件开发特定问题的模式,会让后辈获益无穷;但是如果它们是一些狭隘的、仅对特定需求有效的模式的话,那么就应该被避免继续沿用。
8.学习大师写的代码
俗话说“有样学样”,如果您想编写出干净的代码,那么您首先就要知道干净的代码应该是什么样子。而一些大师级前辈的程序作品,就能起到很好的示范作用,学习他们背后的编程思想、逻辑、以及代码习惯。
显然,您不可能随便跑进微软总部去“偷师”他们的项目,但是您可以通过Github上的各种展示性项目,随时浏览到典型的行业应用、以及各个开源项目的源文件代码。毕竟,这也是开源项目的一个初衷:让更多的人可以从中学习编程。通过这种社区互助的方式,您的代码质量会得以迅速提高。
9. 写好注释
“附上注释”是编程世界中最古老的一项建议。不过在实际编程中,新手程序员一旦被建议要尽可能地留下注释,他们就会乐此不疲。当然,那些不必要的描述、甚至会透露敏感信息的过度注释,也可能会带来适得其反的效果。
我们该如何恰如其分地点到为止呢?我的一个经验法则是:注释是被用来解释为何需要这段代码,而不是讲解代码实际能够做什么。如果您的代码写得足够干净的话,其作用是不言自明的。例如:我们虽然可以用注释来解释“删除它就会破坏A、B和C”的警告,但是在大多数情况下,我们应该用注释来揭示诸如:“使用此参数,是因为X、Y和Z”之类,读者无法从代码中立即获悉到的内容。
10.重构
正如编辑属于文字写作过程的一部分那样,重构也应该是编程过程的一部分。其实,重构能够起到协助优化代码的作用,而不会影响其实际行为。同时,重构也有利于提高代码维护的效率。我在此方面的经验是:“不要仅仅注释掉那些让你觉得混乱、或者不够好的代码,请干脆重写它们吧。”毕竟,随着时间的推移和经验的积累,您在回顾或维护整个软件项目时,总能发现一些对于首次编写不满意、且值得重构的代码。
小结
正如我们学习如何写出言简意赅的说明文那样,干净的代码本身并没有绝对正确的参照标准。希望上文和您讨论的十项技巧,能够成为您避免写出冗长且臃肿的代码的实用参考。
译者介绍
陈峻 (Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验;持续以博文、专题和译文等形式,分享前沿技术与新知;经常以线上、线下等方式,开展信息安全类培训与授课。
原文标题:10 Tips for Writing Cleaner & Better Code,作者:JOEL LEE