我们都做得到了:当妈妈不看时,就给它塞了一个饼干,晚餐吃了太多酒,计程表过期后,让汽车停在停车位。 我们甚至绕过Deadman's Curve有点太快了。 是的,我们都违反了许多编程的基本规则,每个人都认为这是不好的。 我们暗中喜欢它。
我们对良好的编程规则不屑一顾,输入了完全不好的代码,我们就活了下来。 没有编程之神的闪电。 我们的台式机没有爆炸。 实际上,我们的代码已编译并交付使用,客户似乎很满意。
那是因为糟糕的编程与舔电围栏或拉老虎的尾巴不在同一个联盟中。 大多数时候,它都可以解决。 该规则通常是准则或风格建议,而不是必须遵循的一成不变的指令,否则将导致代码死亡。 当然,您的代码可能被嘲笑,甚至可能是公开的。 但是,您违背约定的事实给颠覆(甚至是无意间)带来了一点刺激,这种颠覆(通常(通常是))构成了令人愉悦的代码的社会风尚。
为了使事情变得更加复杂,有时最好打破规则。 (嘘!)代码更清晰。 它甚至可以更快更简单。 规则通常太宽泛,熟练的程序员可以通过破坏规则来改进代码。 不要告诉老板,但是有时候用自己的方式编码是有意义的。
以下是九条规则的列表,有些规则可能被认为是不可逾越的,但我们中的许多人经常打破成功,并获得成功。
不良的编程习惯1:复制
在学校做错了。 在工作中,规则不太清楚。 当然,有些代码块不应该被盗。 如果它来自专有代码,请不要将其折叠到堆栈中,尤其是当它标记有版权信息时。 编写自己的版本。 这就是他们付钱给您的事情。
当原始创作者想要共享时,棘手的问题就来了。 也许是在那些在线编程论坛之一上。 也许它是带有许可证(BSD,MIT)的开放源代码,允许使用一个或三个功能。 没有法律理由阻止您。 而且您有报酬解决问题,而不是重新发明轮子。
在大多数情况下,复制的优点非常引人注目,而缺点可以通过一些注意加以限制。 从信誉良好的来源获得的代码已经至少应用了一轮思路。 原始作者寻找解决方案并找到了一些东西。 循环不变式和数据流已经计算出来。
棘手的问题是关于角色或基础数据是否存在一些未发现的错误或某些不同的假设。 也许您的代码混入了空指针,而原始代码从未检查过它们。 如果您能够解决问题,那就像您的老板正在从两位程序员那里得到建议。 它是没有高级办公桌的双人编程。
不良的编程习惯2:非功能代码
在过去的十年左右的时间里,功能范式一直在上升。 用嵌套函数调用程序来构建程序的助手引用了很多研究,这些研究表明,与旧式的变量和循环相比,代码更安全,更无错误,并且以任何使程序员满意的方式捆绑在一起。 奉献者满怀真心的信徒的说话,在代码审查和请求请求中cha毁非功能性方法。 他们甚至对优点是正确的。
但是有时您只需要弄出一卷胶带即可。 精心设计和精心计划的代码需要时间,不仅需要想象,还需要构建和稍后导航。 所有这些层都增加了复杂性,并且复杂性非常昂贵。 漂亮的功能代码的开发人员需要提前计划,并确保所有数据都通过正确的途径传递。 有时,更容易接触和更改变量。 也许发表评论以解释它。 即使在注释中为后代添加了冗长而晦涩的道歉,也比重新设计整个系统以正确的方式更快。
错误的编程习惯3:非标准间距
软件中的大多数空格都不会影响程序的性能。 除少数使用间距指示代码块的语言(如Python)外,大多数空格对程序行为的影响为零。 尽管如此,仍然有一些强迫症的程序员认为他们很重要。 其中一位曾经以最严肃的口吻告诉我的老板我正在写“非标准代码”,他可以立即看到它。 我的罪过? 未能通过在等号的两侧放置空格来违反ESLint space-infix-ops规则 。
有时,您只需要考虑比放置空间更深的内容。 也许您担心数据库过载。 也许您担心空指针可能会使您的代码崩溃。 几乎所有代码的一部分都比空格更重要,即使是浮夸的标准委员会也已经填写了有关这些空格或制表符位置的规则页面。
令人惊讶的是,有几个好的工具可以自动重新格式化您的代码,以遵守任何定义良好的插入规则。 人类不需要花时间思考这个问题。 如果它是如此重要,他们可以通过该工具运行它来解决问题。
不良的编程习惯4:使用goto
禁止使用goto
可以追溯到许多结构化编程工具还没有出现的时代。 如果程序员想创建一个循环或跳转到另一个例程,则需要键入GOTO
后跟一个行号。 几年后,编译器团队允许程序员使用字符串标签而不是行号。 当时,该功能被认为是热门新功能。
有人称结果为“意大利面条代码”。 任何人以后都不可能阅读您的代码并遵循执行路径。 那是一团混乱的线程,永远缠在一起。 Edsger Dijkstra以题为“ Goto声明被认为有害 ”的手稿拖拉禁止了该命令。
但是绝对分支不是问题。 这就是纠结。 通常,巧妙的break
或return
将提供有关该位置的代码执行情况的非常清晰的陈述。 有时将goto
添加到case语句中将产生比级联if-then-else块的结构更正确的列表更容易理解的内容。
有反例。 苹果SSL堆栈中的“ goto fail ”安全漏洞是最好的例子之一。 但是,如果我们谨慎地避免了一些case语句和循环的棘手问题,则可以插入良好的绝对跳转,使读者更容易理解正在发生的事情。 我们可以把一个break
或return
是更清洁和更赏心悦目的也许每个人-除了goto
仇敌。
不良的编程习惯5:不声明类型
热爱打字语言的人们很有意义。 当我们为每个变量的数据类型添加清晰的声明时,我们会编写更好,更无错误的代码。 暂停片刻来说明类型,可以帮助编译器在代码开始运行之前标记愚蠢的错误。 这可能会很痛苦,但会有所帮助。 这是一种束手无策的编程方法,可以阻止错误。
时代变了。 许多较新的编译器足够聪明,可以通过查看代码来推断类型。 他们可以在代码中前后移动,直到可以确定变量必须是string
或int
或其他类型。 而且,如果这些推断出的类型不对齐,则编译器会引发错误标志。 他们不需要我们再键入变量。
这意味着通过省去一些最简单的声明,现在可以更轻松地节省一些代码。 代码变得更简洁了,读者通常能够猜出for循环中名为i
的变量是整数。
不良的编程习惯6:溜溜球代码
程序员喜欢将其称为“悠悠球代码”。 首先,值存储为字符串。 然后将它们解析为整数。 然后将它们转换回字符串。 这是非常低效的。 您几乎可以感觉到CPU在所有额外负载下都处于挣扎状态。 编写快速代码的精明程序员会设计其体系结构,以最大程度地减少转换。 由于他们的计划,他们的代码运行得更快。
但是,不管您信不信,有时候这是有道理的。 有时,您有一个“狂飙”库,可以在其专有的黑匣子中执行大量的智能操作。 有时,老板写了一张七位数的支票来许可黑匣子中的所有天才。 如果库需要字符串形式的数据,则即使最近将其转换为整数,也要以字符串形式将其提供给库。
当然,您可以重写所有代码以最大程度地减少转换,但这会花费一些时间。 有时代码可以额外运行一分钟,一小时,一天甚至一周,因为重写代码会花费更多时间。 有时候,增加技术债务要比一开始就建立技术债务便宜。
有时该库不是专有代码,而是您很久以前编写的代码。 有时,将数据转换一次比重写该库中的所有内容更快。 这样您就可以编写悠悠球代码了。 可以,我们都去过那里。
不良的编程习惯7:编写自己的数据结构
标准规则之一是,程序员在大二学完数据结构课程后,切勿编写用于存储数据的代码。 已有其他人编写了我们将需要的所有数据结构,并且这些代码经过了多年的测试和重新测试。 它与语言捆绑在一起,并且可能是免费的。 您的代码只能包含错误。
但是有时候数据结构库有点慢。 有时,它们迫使我们进入标准结构,但对我们的代码却是错误的。 有时,库会迫使我们在使用结构之前重新配置数据。 有时,这些库包括带有线程锁定等功能的皮带和吊带保护,而我们的代码不需要它们。
发生这种情况时,就该编写我们自己的数据结构了。 有时会快很多。 有时它使我们的代码更简洁,因为我们没有包括所有额外的代码来精确地重新格式化数据。
不良的编程习惯8:老式循环
很久以前,创建C语言的某人想将所有抽象可能性封装在一个简单的构造中。 在开始时,有一些事情要做,每次循环都需要做一些事情,还有一些方法可以告诉一切何时完成。 当时,这似乎是捕捉无限可能性的完美语法。
那是那时。 现在,一些现代的批评只看到麻烦。 发生了太多事情。 所有这些善良的可能性也同样具有善恶的能力。 它使阅读和阅读变得更加困难。 他们喜欢更具功能性的范例,其中没有循环,仅将函数应用于列表,将计算模板映射到某些数据。
有时候,无环方法更干净,尤其是当只有一个整洁的函数和一个数组时。 但是有时候,老式的循环要简单得多,因为它可以做的更多。 例如,当您找到第一个匹配项后就可以立即停止搜索,这样比较容易。
此外,当要对数据执行多项操作时,映射功能会鼓励进行更严格的编码。 假设您要取绝对值,然后取每个数字的平方根。 最快的解决方案是先映射第一个函数,然后映射第二个函数,将数据循环两次。
不良的编程习惯9:在中间摆脱循环
沿着这条线的某个地方,一个规则制定小组宣布每个循环都应该有一个“不变式”,这就是说在整个循环中都是正确的逻辑陈述。 当不变量不再为真时,循环结束。 这是考虑复杂循环的一种好方法,但它会导致疯狂的禁止,例如禁止我们在循环中间使用return
或break
。 这是禁止goto
语句的规则的子集。
这个理论很好,但是通常会导致更复杂的代码。 考虑以下这种简单的情况,它扫描数组以查找通过测试的一项:
while (i<a.length){
...
if (test(a[i]) then return a[i];
...
}
循环不变的恋人宁愿我们添加另一个布尔变量,将其称为notFound
,并像这样使用它:
while ((notFound) && (i<a.length){
...
if (test(a[i])) then notFound=false;
...
}
如果这个布尔值是好名字的,那将是一段很好的自我记录代码。 它可以使每个人都更容易理解。 但这也增加了复杂性。 这意味着分配另一个局部变量并阻塞寄存器,编译器可能会也可能不够聪明,无法修复。
有时goto
或jump会更干净。
错误的编程习惯10:重新定义运算符和函数
一些最有趣的语言使您可以做一些真正曲折的事情,例如重新定义看起来应该是常量的元素的值。 例如, Python使您至少在2.7版及TRUE=FALSE
版本中输入TRUE=FALSE
。 这不会造成某种逻辑崩溃和宇宙的终结。 它只是交换TRUE
和FALSE
的含义。 您还可以使用C预处理器和某些其他语言来玩这种危险的游戏。 还有其他语言允许您重新定义加号之类的运算符。
这是一个延伸,但是当更快地重新定义一个或多个这些所谓的常量时,一大段代码中就会包含点。 有时,老板希望代码执行完全不同的操作。 当然,您可以检查代码并更改每次出现的情况,也可以重新定义现实。 它可以使您看起来像个天才。 无需重写巨大的库,只需翻转一下即可,相反。
在这里划清界限也许是件好事。 无论多么聪明和有趣,您都不应在家中尝试。 这太危险了-真的……诚实。
From: https://www.infoworld.com/article/2992566/10-bad-programming-habits-we-secretly-love.html