如果你以团队一员的身份编写代码,你所编写的代码很可能建立在其他工程师编写的代码层次的基础上,其他人也可能以你的代码为基础构建新的代码层次。如果你在工作期间解决了各种各样的子问题,并将其分解为清晰的抽象层次,其他工程师也有可能重用其中一些代码,去解决你可能没有考虑过的、完全不同的问题。
为了说明这一点,想象你在一家运营在线杂志的公司工作,用户可以在该杂志上查找和阅读文章。你的任务是编写文本摘要功能,在用户查找阅读内容时为其提供文章的摘要。你最后写出了我们在第2章中看到的代码——包含TextSummarizer
和相关的几个类。(如果你不记得确切的代码或者跳过了第2章,无须担心。)图3-1展示了你编写并最终在软件中使用的文本摘要代码。可以看到,你的代码依赖于其他工程师编写的低层次代码,其他工程师反过来依靠你的代码解决更高层次的问题。还可以看到,你的代码在多项功能中得到重用。你最初可能只预计到它在文章摘要上的用途,但其他工程师继续重用它(或者它的一部分)来摘要评论和估计文章的阅读时间。
另外值得注意的重要问题是,需求一直都在变化和发展:优先考虑的事项发生变化、需要增加新功能、系统有时需要采用新技术等。这意味着,代码和软件也总是在变化。图3-1展示了软件的快照,软件不太可能在一年甚至几个月内完全保持这种面貌。
图3-1 你编写的代码很少是与世隔绝的。它依赖于其他工程师编写的代码,相反,其他工程师编写的代码也可能依赖于你的代码
一组工程师在持续修改代码库,使其成为一个热闹的地方。与任何热闹的地方一样,脆弱的东西很容易被打破。当你举办一场大型聚会的时候,有理由把精美的玻璃器具收起来,同样,体育馆的栏杆用金属制成,并固定在地板上:脆弱的东西不适合于热闹的地方。
为了经受住其他工程师的这种“踩踏”,代码必须鲁棒且易于使用。编写高质量代码时的主要考虑因素之一就是理解和预判在其他工程师做出更改或者必须与你的代码打交道时,可能出现什么不良状况,你又该如何应对这些风险。除非你在只有一位工程师的公司工作,而且从来不会忘记任何事情,否则要编写出高质量代码就不可能不考虑其他工程师。
编写代码时,考虑如下3件事是很有帮助的(后面的内容将详细探讨):
〓● 对你来说显而易见,但对其他人并不清晰的事情;
〓● 其他工程师无意间试图破坏你的代码;
〓● 过段时间,你会忘记自己的代码的相关情况。
当你着手编写代码时,可能已经花了几个小时甚至几天的时间考虑所要解决的问题。你可能经历了设计、用户体验测试、产品反馈或缺陷报告等多个阶段,对其中的逻辑十分熟悉,一切看起来似乎都是显而易见的,你几乎不需要思考情况为何是这样的,或者你为何要这样解决问题。
但请记住,在某个时间,其他工程师可能需要与你的代码打交道,对其进行修改或者改变代码所依赖的因素。他们不可能像你那样花费大量时间去理解问题、思考解决方案。在你编写代码的时候觉得显而易见的事情,对他们来说很可能不那么明显。
始终考虑这一点,并确保你的代码能够解释其使用方法、功能和开发这些功能的原因。正如你在本章及随后的章节中将要学到的,这并不意味着写一大堆注释。使代码易于理解、不言自明往往是更好的办法。
假设其他工程师无意间试图破坏你的代码,这看起来似乎过于悲观,但正如我们刚刚看到的,你的代码并不存在于真空中,它可能依赖于多个其他代码段,而这些代码段又依赖于更多的代码段,同时,可能也有更多的代码段依赖于你的代码。由于其他工程师添加功能、重构和修改,有些代码段将一直处于变化中。所以,你的代码远非在真空中,实际上处在不断变化中,而以它为基础构建的部件也在不断变化。
对你来说,你的代码可能就是全世界,但公司中其他大部分工程师可能对它并没有太多的了解,当他们偶然看到这段代码时,也不一定预先知道它存在的理由和功能。其他工程师很可能在某个时间添加或修改一些代码,无意间破坏或误用了你的代码。
正如我们在第1章中所见到的,工程师通常对代码库的本地副本进行修改,然后将其提交到代码库。如果代码没有编译或者测试失败,就不可能提交他们的更改。如果其他工程师的更改破坏或者误用了你的代码,你应该确保在他们修复所引发的问题之前,更改不会提交到代码库。只有两种可靠的方法能做到这一点:在发生破坏时,要么停止编译代码,要么测试失败。围绕高质量代码编写的许多考虑因素,最终都是为了确保出现破坏时能发生上面的两种情况之一。
现在,代码细节在你的脑海里如此新鲜和重要,以至于无法想象会忘记它们,但经过一段时间,它们不再新鲜了,你就会开始忘却。如果一年以后出现了新功能或者你被安排去解决一个缺陷,你可能不得不修改自己写的那段代码,或许再也记不清所有细节了。
3.1.1节和3.1.2节所说的情况——对其他人不是那么显而易见,或者其他人破坏你的代码——可能在某个时间适用于你。查看一两年前自己写的代码和查看其他人写的代码没什么两样。因此,必须确保你的代码即使对毫无背景知识的人来说也是容易理解的,并使其难以遭到破坏。你不仅要做有利于其他人的事情,也要做有利于未来的自己的事情。
当其他工程师需要利用你的代码或者修改一些对其有依赖的代码,就必须领会你的代码的使用方法及其功能。具体地说,他们必须理解如下要素:
〓● 在哪些场景下,他们应该调用你提供的各种函数;
〓● 你创建的类代表什么,应该在什么时候使用;
〓● 他们应该以什么值调用;
〓● 你的代码将执行什么操作;
〓● 你的代码可能返回什么值。
正如你刚刚在3.1节中看到的,经过一年,你很有可能忘记了自己的代码的所有细节,因此,为了理解本书的所有内容,你可以从本质上将未来的自己当成其他查看你编写的代码的工程师。为了领会代码的使用方法,其他工程师可以做如下事情:
〓● 查看代码元素(函数、类、枚举类型等)的名称;
〓● 查看代码元素的数据类型(函数和构造程序参数类型与返回值类型);
〓● 阅读所有文档或函数/类级注释;
〓● 当面或通过聊天程序/电子邮件询问你;
〓● 查看你的代码(你所写的函数和类的实现细节)。
在后面的内容中我们将看到,上述方法中只有前3种切实可行,其中代码元素的名称和数据类型往往比文档更可靠。
在实践中,观察代码元素的名称是工程师领会新代码段使用方法的主要手段之一。包、类和函数的名称有点像书的目录:它们是查找解决子问题代码使用方法的便利、快捷手段。使用代码时,很难忽视元素名称:removeEntry()
函数不容易与addEntry()
函数混淆。
因此,恰当地命名代码元素是向其他工程师传达代码的使用方式的手段之一。
本文摘自《好代码 ,坏代码》
软件工程师在不断积累经验的过程中会发现,日常编程中所做出的决策对于软件的正常运行、工作的顺利开展以及其他人的维护有很大的影响。学习编写(从软件工程角度来看)优良代码需要花费许多年的时间。这些技能的获得过程往往很缓慢。工程师从自己的错误中吸取教训,或者不断从团队的资深工程师那里得到建议,以特定的方式得到这些技能。
本书旨在帮助刚入门的软件工程师获取这些技能。它将传授一些非常重要的经验教训和基础理论,帮助读者编写可靠的、易于维护且能够适应不断变化需求的代码。
本书分享了编写鲁棒、可靠且易于团队成员理解和适应的代码的实用技巧。内容涉及如何像高效的软件工程师一样思考代码,如何编写读起来像一个结构良好的句子的函数,如何确保代码可靠且无错误;如何进行有效的单元测试,如何识别可能导致问题的代码并对其进行改进,如何编写可重用并适应新需求的代码,如何提高读者的中长期生产力;同时还介绍了如何节省开发人员及团队的宝贵时间,等等。