当前位置: 首页 > 科技观察

程序总是出错,这10个容易犯的编程错误你避免了吗?_0

时间:2023-03-21 01:34:11 科技观察

【.com快译】为什么程序出现故障?自从上个世纪世界上第一位女性程序员AdaLovelace首次看到通用计算的潜力以来,我们已经走了很长一段路,但我们编写的软件仍然充满错误。这些年来,虽然我们开发了很多先进的方法来保证代码的成功,但是程序还是不断的出问题。是什么原因?虽然这个问题有很多答案,但我们决定提供一个务实的答案。程序员会犯错误。他们有时很草率。他们并不总是使用最好的工具或最佳实践。我在加州大学伯克利分校教授面向对象编程课程,我在学校教授良好编程实践的时间与帮助学生理解代码本身的时间一样多。我在课堂上看到了许多常见的错误,本文介绍了其中的一些错误。我还联系了西北工业大学工程学院的JamesA.Connor教授,分享了他的学生常犯的一些错误。让我从几个开始。错误#1:糟糕的注释方法。注释是程序中计算机不执行的那部分文本。它们由程序员以注释的形式编写,以解释代码中发生的事情。我的许多学生都避免评论他们的代码,并且想知道为什么他们应该花时间从实际编码中抽出时间来写一些评论。我最实际的例子来自我自己的生活。早在世纪之交之前,我就编写了ZENPRESS的1.0版,它是最古老的内容管理系统之一。我预计它将带来几年的文章。十四年后,它仍然管理着许多文章,有75,000篇文章和26亿页内容可供使用。最后,它运行的平台变得过时了。我不得不回去深入研究代码。2009年,我将代码从原始平台移植到现代平台。我最近不得不再次改变,因为PHP的一个关键语言特性在版本升级后完全消失了。19年后,我完全不记得所有这些代码是如何工作的,但由于我已经详细评论了代码,我可以说我有一个路线图。我可以查看代码,查看代码中嵌入的注释,然后进行更改。当您在团队中工作时,或者当您的软件不在您的监督之下时,注释也很重要。你的职业可能会改变,其他人可能需要过来理解你的代码。评论会有很大帮助。错误#2:糟糕的变量命名。我将继续探索这个主题:通过语言让代码一目了然。我将用一个例子来说明这一点。假设您驾驶一辆每加仑20英里的汽车行驶100英里。请问你用了多少汽油?这是一个简单的示例,但适用于我们的目的。假设你遇到了a=b/c这一行。是什么意思?b和c指的是什么?它们与您的其余代码有何关系?写一个程序十分钟后,你就会记住一切。更何况还有人过来修改代码或者写更新。现在看看这个表达式:加仑=英里/每加仑英里。每个变量的具体用途一目了然。一个代表加仑,一个代表英里,一个代表英里每加仑。非常清楚。想一想给变量提供清晰的英文(或任何其他母语)名称和注释之间的关系。假设你从别人那里拿了一段代码,看到a=b/c。这段代码是做什么用的?你有什么主意吗?请务必以代表其功能的方式命名变量。那会节省很多时间和很多麻烦。错误#3:没有实验室笔记。我在1997年年中开始编写ZENPRESS,它于1998年1月上线。不幸的是,我仓促完成了这个项目,没有花时间为第一个版本写实验笔记。从那以后我后悔过很多次。自1999年6月(当我开始编写第2版时)以来,我一直在定期做实验室笔记。实验室笔记是除了代码注释之外的记录。科学家们在研究和开发过程中一直在使用实验室笔记、日记或对话。实验笔记用于证明谁拥有科学发现,因为研究过程通常记录在科学家用来记录其进展的日报中。实验室笔记也是程序员的有效工具。我为ZENPRESS写的最后一篇实验笔记是在今年3月,当时我不得不将ZATZ存档从一个托管服务提供商迁移到另一个。我也经常为我的其他项目做实验笔记,并且能够参考我的笔记很多次都是一个巨大的帮助。如果你还没有做实验笔记,现在就开始吧。记下您所做的任何更改、您的原因、您考虑过但随后放弃的代码、您引用的有用资源以及将来对您有帮助的任何其他内容。您还可以帮助未来的同事或继任者——如果您需要证明所有权,实验室笔记也可以作为证明。第四个错误:不是用人类语言写作。我的学生要通过考试,而不仅仅是编程,他们会在讨论区发帖,证明他们熟悉某些编程概念。我们提出这个要求有两个原因。首先,当然,要证明对这个概念的熟悉程度。但更重要的是,所有专业人士都需要具备写作能力。我在这方面遭到了学生的反对。每个学期学生都在哭,“我想成为一名程序员,而不是一名作家”。但是编程、工程、IT和几乎所有专业工作都不可能存在于真空中。你需要写作来解释一个概念、推销一个想法、获得资金、要求澄清、准备一份提案,甚至争取更好的分数。开源项目的参与者在非常大的团队中一起工作,保持他们同步的唯一方法是编写清晰易懂的信息。结论很简单:如果你想专业地工作或从事任何严肃的项目,你需要用人类语言(如英语)来编写,而不仅仅是编程语言。错误5:代码格式不佳。毫无疑问,这里的一个主题是:让代码易于理解。代码维护起来非常耗时且昂贵。坦率地说,这也不是很有趣。最好将宝贵的工作时间花在添加功能上,而不是花数周时间挖掘旧代码,试图弄清楚您(或交给您代码的人)想要完成什么。这发生在我身上,不仅仅是我的旧代码,而是我从别人那里继承的代码。我接手了一个废弃的WordPress开源插件作为副项目。据我所知,我接管的插件比任何人都多。每个插件都是由其他人开发的,为了让插件正常工作,我不得不深入研究陌生人的代码。幸运的是,这些开发人员都是专家,精通编程。否则,我将无法接手这些项目。但即便如此,也很难尽快上手。你能想象如果他们编写结构不良的代码会有多难吗?我所说的结构是指代码的布局方式。我为我的学生制作了一个视频。有兴趣的可以在YouTube上观看(https://youtu.be/0u-I016Hxlw)。想一想您在网上阅读的一篇文章。有些文章格式精美,每个段落之间有一条线,一切都保持一致。但是,有些文章排成一团,看不清楚。每个程序员(或项目)都倾向于拥有一种编程风格。你的风格是什么并不重要,只要它是一致的。您需要让代码格式帮助指导。例如,在我的代码中,我坚持代码段之间不超过一个空行。如果我看到更大的空白区域,我会立即知道:有问题,这个空白区域可能有错误。当你深入研究代码时,要注意你的公司是否有编程风格。考虑为所有程序员定义一种编程风格,并坚持一种清晰且易于维护的风格。错误#6:差错检查。一位名将曾说过,临敌之际,谋划是行不通的。我就在这个基础上做一些改动,你的代码在遇到用户的时候根本就不行。尽管您认为您知道用户将如何使用您的代码,但您不知道,请相信我。用户会弄乱你的代码。正确的方法是进行测试和错误检查。错误检查是指检查代码中每个操作的结果的做法。确保它按照您的预期运行,或者确保您的代码能够处理意外结果。例如,我的学生经常有一个任务:阅读一份文件。几乎所有的学生都会编写调用文件读取例程的代码。他们检查用户是否取消了对话框,但很少检查文件是否真的被读入,或者是否存在某种类型的系统错误。如果他们试图写一个文件,那就更糟了。他们几乎从不真正查看文件是否实际保存。它是可怕的。不难看出这会有多糟糕。处理这种情况,你总是要考虑你是否可以绝对预测行为,然后意识到你不能绝对预测行为。你需要测试。测试不仅仅意味着自己运行代码。测试意味着让您的代码与真实用户(其行为可能无法预测)一起运行。您会发现这提供了很多信息。第七个错误:使用打印输出语句而不是真正的调试器。这些年来我发现的是,使用不同语言的程序员往往具有不同的文化。一般来说,这是因为他们使用不同的工具构建不同类型的解决方案。这方面的一个例子是我的C#编程学生和我一起从事某些项目的开源PHP开发人员之间的区别。很少有C#程序员会考虑在不使用符号调试器的情况下调试他们的代码。那是因为C#本身是使用VisualStudio作为编程环境编写的,并且内置了调试器。相比之下,我看到许多PHP开发人员认为只需插入一条echo语句或var_dump就足以帮助他们调试代码。这部分是由于大多数PHP程序员倾向于在编辑器中而不是在开发环境中编程。两者之间的一大区别是调试器。那么,什么是调试器?简而言之,这是一个允许您在代码运行时查看其内部的工具。它就像编码的X光、超声波或MRI。您可以指示调试器在某些点停止并检查所有变量的状态。您还可以指示调试器在特定条件下停止。您可以更改值,可以查看和分析值(尽管分析有时是另一种工具)。生产力的差异是巨大的。如果您想更快、更准确地完成工作,请务必使用真正的符号调试器。以上是我介绍的一些常见错误。我们来看看JamesConnor教授介绍的几个。第八个错误:使用神奇的数字。许多程序员认为他们可以编写一次代码,然后就完美了。然而,要优化企业软件和工业软件的长期生命周期成本,就必须编写能够承受不断变化的条件的代码。一个很好的例子就是幻数的想法。我所说的神奇数字是指程序员相信永远经得起时间考验的数字。以可能基于客户购买数量的佣金计算为例。截至发稿,佣金率可能是三个百分点,即0.03。现在,想象一下这段代码将如何编写:佣金=.03*销售额。在这种情况下,幻数是0.03。由于程序员认为这会神奇地永远有效,他将数字0.03硬编码到代码中。这一切都很好,但佣金往往每年都在变化。如果明年佣金上涨0.5%至0.035,将很难在数千行代码中找到它。永远不要使用幻数,而是在一个地方定义变量或常量,然后让代码使用这些变量。如果您预定义了commission_rate,那么commission=commission_rate*sale这样的代码不需要更改。另一个需要考虑的方面是,无论您在哪里找到幻数,您都应该找到您想要提供给用户的选项,以便他们可以在首选项部分中进行设置。错误#9:草率地处理日期和时间。这就是谜题:一年有多少天?365天可能是通常的答案,但今年肯定有366天。一天会有365.25天吗?这是不可能的。但是我的一些学生认为,由于闰年每四年出现一次,因此平均年是365.25天。在进行日期计算时,他们使用这个平均值;因此,结果根本不正确。通常最好使用系统库来计算日期,因为您计算的日期可能不是西历日期。考虑一个类似的时间问题。随着地球减速,每隔几年,一天就会多一秒,通常是在6月30日或12月31日。这称为闰秒,因此时钟可能从11:59:59到11:59:60再到12:00:00。这是第二次挑战。在使用夏令时的地方,交易可能会乱序进行。比如事务A先被插入,然后时间重置了1小时,那么事务B就会被插入。但是,如果你对时间序列比较草率,它会被记录为事务B先发生。这种类型的时间错误会导致不必要的罚款和其他各种混乱。同样,有许多优秀的语言和系统库可以处理这两种类型的时序问题。通常使用现有的库比编写自己的时间计算代码要好。错误10:没有选择正确的数据结构。数据结构是一种在程序中表示数据的机制。许多人都听说过链表、树和数组等术语。这些术语中的每一个都是数据的逻辑表示,对应于您试图表示的数据的某种体系结构。我看到程序员(无论是专家还是新手)最常犯的错误之一是很少注意数据结构的选择。由于几乎所有代码都基于您选择的数据表示形式,因此选择错误的数据结构可能会在未来产生严重的后果。下面是这种设计错误的一个例子:选择一个简单的堆栈或队列而不是循环队列。堆栈就像一堆盘子。你取下底板,放上另一个盘子,再取下另一个盘子,依此类推。如果您想拿走盘子,请从顶部拿走。这称为后进先出。但是问题来了,如果你需要把之前放的东西拿走,那就很麻烦了。假设一叠盘子里有10个盘子。要找到第一个盘子,您必须移除所有其他盘子。现在,想象一个队列。如果你在银行排队,你就在队列中。先入先出。一旦第一个人被服务,下一个人就会跟随,并且那个人被服务。出现的另一种情况是,大家往前走一步,在队列中往前走。排队的人多了怎么办?要么他们被拒之门外,要么队伍从门外排了出去。第一个人叫完之后,这些人都得往前走。如果您有大量数据,这种队列可能效率极低。每当从队列头部获取数据时,所有数据都会被移动。我们正处于大数据时代,源源不断的数据流通过我们的系统。在这种环境中,更好的方法可能是实现循环队列。在这种情况下,数据根本不会移动。相反,设置的指针指向队列的开头和结尾;在内部,队列首尾相接,因此数据组织成环形而不是队列。当一个数据元素被使用并从环中移除时,不需要移动环中的所有数据。所发生的只是第一个元素的指针指向环中的新元素。这只是选择正确的数据结构可以对代码效率产生重大影响的众多示例之一。希望阅读本文后,您将成为一名更有效率的程序员,并避免其中的一些严重错误。原标题:软件漏洞?避免这10个代价高昂的编程错误,作者:DavidGewirtz