开发者常见的十种不良编程习惯
通常,编程规则只会规定程序员在编写代码时,需要遵守的准则、以及建议采用的风格,而不是那些细枝末节需要遵循的、一成不变的指令。因此,就算您偶有“犯规”也并不可怕。可怕的是不去认真总结,甚至置若罔闻。下面,我将和您讨论十种常见的不良编程习惯。
不良的编程习惯1:直接复制操作
请不要直接将他人的代码整块地复制、粘贴到自己的程序中,特别是那些已经标记了版权信息的专有代码。请最好在理解的基础上,动手键入自己的版本。毕竟,您的老板或客户并不是花钱来请你专门进行复制、粘贴的。
当然,从代码的可靠性来说,我们通常应当从信誉良好的来源,获取那些经过原创作者深思熟虑、以及反复测试的源代码。为了避免重复造轮子,许多原始创作者会在各种在线编程论坛上共享、并开放自己的源代码。不过,有时候他们可能会带有许可证(如BSD或MIT)、以及使用范围的限制。
另外,有些程序往往是针对某个特定的棘手问题所开发的。其中难免会存在着一些未被发现的错误、或是对具体情况的假设与限制条件。如果您只是将其简单地添加到自己的代码段中的话,很有可能会出现空指针、或是死循环之类的潜在错误。而由于原始代码并未预见到您的使用环境,因此可能会出现“水土不服”,甚至是实现效果并不理想的情况。
不良的编程习惯2:非功能性的代码
在过去的十年间,功能性范式有了长足进步。有多项研究证明:使用嵌套函数调用程序来构建程序的方法,与旧式的变量和循环模式相比,程序代码本身会更加安全,错误也会更少。因此,资深程序员往往会通过审查代码、以及推拉请求的方式,来发现那些非功能性的代码,进而让程序的结构更为合理且协调。
请不要妄想一次性设计出全面的架构。毕竟,精心的分层设计、复杂的界面导航、以及用于构建的配套代码,都需要事先向程序员提供充裕的时间、以及昂贵的费用。因此,为了确保所有必要的数据能够正确地被定义,并能够通过准确的途径进行传递,进而让整个系统能够以高效的方式运行起来,我们应当尽量保持代码的简洁与直观,不要遗留各种冗长的非功能性代码。
不良的编程习惯3:非标准的间距
众所周知,除了诸如Python之类少数编程语言使用空格间距来标识代码块之外,大多数程序中的空格一般都不会影响软件的行为效果、以及整体性能。尽管如此,我们依然需要抱着“强迫症”的态度,苛求自己不要写出“非标的代码(Non Standard Code)”,特别是在等号的两侧不要留下空格,以至于违反了ESLint space-infix-ops规则。
有时候,过多的空格会导致数据库的过载,甚至是由于空指针导致了程序运行的崩溃。因此,在某些要求严格的软件开发企业中,他们会专门成立标准委员会,以规范各种空格、或制表符在代码、以及页面中所允许出现的位置。
在实际编程过程中,开发人员往往更专注于程序的功能与效果,而忽略了间距与空格之类的格式问题。不过,值得庆幸的是:目前有好几种工具可以帮助您自动化地规范代码的格式,并能遵守各种预先定义的插入规则。
不良的编程习惯4:goto的使用
人们使用goto的历史可以追溯到那些早于结构化编程工具的时代。当时,如果程序员们想创建一个循环,或是跳转到另一个例程,就需要键入goto、且后面跟上行号。若干年后,编译器出现了,它允许程序员使用字符串标签,而不再是行号。当时,此类功能曾经被认为是一种热门技能。
如今,有越来越多的人将此类编程习惯所产生的代码称为“意面式代码(spaghetti code)”。此类混为一团的线程纠缠在一起,他人完全无法读懂,而且其本身很可能会陷入遵循执行的路径。结构程序设计之父Edsger Dijkstra曾经针对此现象发表了《Goto声明显然有害(Goto Statement Considered Harmful)》的文章。
作为解决方案,您可以巧妙地使用break或return,来清晰地声明代码执行到此处的后继行为。当然,我们有时候也可以把goto添加到case语句中,将产生比级联“if-then-else”块结构,更为正确的列表,以及更容易理解的内容。
作为一个反例,您也许听说过苹果SSL堆栈中的“goto fail”安全漏洞。如果我们能够谨慎地避免case语句与循环相关的棘手问题,只插入break或return之类有效的绝对跳转,那么就会让整个问题容易处理得多。
不良的编程习惯5:未声明的类型
有经验的程序员都知道:只有为每个变量的数据类型都添加清晰的声明,我们才能编写出更优秀,bug更少的代码。我们只有提前完善了类型的声明,编译器在执行程序代码时,才不会碰到某些“愚蠢”的错误。这种编程习惯的养成虽然可能很痛苦,但是它绝对会让您受益。
当然,随着技术的发展,如今许多新式的编译器已经足够聪明,能够通过查看代码的上下文,来推断变量是否属于string、int或其他类型。如果编译器实在无法推断出正确的类型,它也会抛出相应的错误。
不良的编程习惯6:yo-yo代码
“yo-yo代码”是指:作为字符串存储的数值被解析为整数,接着又被转换回了字符串。显然,这是一种非常低效的方式。它额外地耗费了大量的CPU资源。因此,经验丰富的码农会通过合理的程序结构,来大幅减少转换所需的工作量,进而提升代码的运行效率。
如今我们时常听到业界有人谈论偿还“技术债”的说法。它在此处可以被理解为:程序员通过重写所有现有的代码,清除yo-yo代码,以最大限度减少数值类型转换的成本与时间。
不良的编程习惯7:编写自己的数据结构
一些初出茅庐的程序员往往喜欢自行编写某种用于存储数据的代码。而这些数据结构难免存在着他们考虑不周的潜在漏洞。其实他们应该明白:作为一种成熟的编程语言,各种常见的数据结构已有前人提前准备好了。而且这些程序代码往往与语言捆绑在一起,经过了多年的测试与检验,开发者可以放心大胆地免费使用。
当然,有时候现成的数据结构库为了标准化的需要,而在存放之前迫使我们重新配置输入的数据。因此,我们可以适当地针对线程锁等功能进行代码级别的调整,去除不必要的、数据格式化之类的代码,以使得整体结构更加简洁。
不良的编程习惯8:老式循环
很久以前,C语言的缔造者希望将所有的抽象可能性都封装到一个简单的构造之中,这就导致了每次调用都需要循环地进行各项操作,并需要告知操作的完成。显然,这会让程序的可读性变得很差。如今,人们更趋向具备功能性的范式(paradigm),直接将功能函数应用到列表中,将计算模板映射给某些数据,而不再使用循环。
在只有一个整洁的函数和一个数组的时候,使用不带循环的方法会让程序变得更加易读且简洁。但是在需要首次找到匹配项就立即停止搜索的场景下,老式的循环仍然会让程序既简单又高效。
当然,映射函数更适合您对数据执行多项操作。例如:您想先取绝对值,然后取每个数字的平方根。那么最快的方法就是:先映射第一个函数,然后映射第二个,接着将数据循环两次。
不良的编程习惯9:从循环中跳出
有些程序员在编程的时候,喜欢在每个循环中都使用一个变量,并且在该变量为真(true)的时候,就结束循环。虽然这是处置复杂循环的一种好方法,但是它会在某种程度上禁止我们在循环中使用return或break。
不良的编程习惯10:重新定义运算符和函数
对于某些初级程序员而言,由于知识与经验的不足,他们可能会重新定义运算符和函数。例如,在Python 2.7、及其之前的版本中,您可以指定TRUE=FALSE。这将导致的结果是:它会在您的代码中将TRUE和FALSE的含义进行互换。同时,在C语言预处理器、以及某些其他语言中,您也可以去重新定义加号之类的运算符。
当然,此类重新定义也并非百无一用。面对巨大的既有库,您可以在无需重新改写代码的情况下,临时借用一下该“反转”功能,来简化大段的代码。