当代码变得更复杂时,有什么好的策略来修复错误?

时间:2009-02-13 04:16:04

标签: debugging language-agnostic

我“只是”一个业余爱好者程序员,但我发现随着我的程序变得越来越长,bug越来越烦人 - 而且更难跟踪。就在所有事情似乎都顺利进行的时候,会出现一些新的问题,似乎是自发的。我可能需要很长时间才能找出导致问题的原因。其他时候我会添加一行代码,它会破坏另一个单元中的某些东西。如果我认为一切运转良好,这会让人感到沮丧。

这对每个人来说都是常见的,还是更像新手呢?我听说过“单元测试”,“设计框架”以及各种其他概念,听起来像是会减少烦恼,使我的应用程序“健壮”,一切都很容易理解:)

那么,对于接受过专业培训的人来说,错误有多大?

谢谢 - Al C。

14 个答案:

答案 0 :(得分:24)

“修复问题,在其他地方引起问题”的问题是众所周知的,并且确实是单元测试背后的主要动机之一。

这个想法是,如果您为系统的每个小部分独立编写详尽的测试,并且每次在任何地方进行更改时在整个系统上运行它们,您将立即看到问题。然而,主要的好处是,在构建这些测试的过程中,您还将改进代码以减少依赖性。

这类问题的典型解决方案是减少耦合;使不同的部分相互依赖。更有经验的开发人员有时会有习惯或设计技能来以这种方式构建系统。例如,我们使用接口和实现而不是类;我们将模型 - 视图 - 控制器用于用户界面等。此外,我们可以使用有助于进一步减少依赖性的工具,如“依赖注入”和面向方面编程。

所有程序员都会犯错误。优秀且经验丰富的程序员可以构建他们的程序,以便更容易找到错误并限制其影响。

这对每个人来说都是一件大事。大多数公司在维护上花费的时间多于编写新代码。

答案 1 :(得分:15)

自动化测试吗?如果你不这样做,那么你就是在没有找到错误的情况下注册创建错误。

在修复错误时是否添加了错误测试?如果您不这样做,那么您将注册一遍又一遍地创建相同的错误。

编写单元测试吗?如果没有,则在测试失败时注册长调试会话。

您是在先编写测试吗?如果没有,当您的单位紧密耦合时,您的单元测试很难写。

你无情地重构吗?如果没有,每次编辑都将变得更加困难,并且更有可能引入错误。 (但首先要确保你有好的测试。)

当您修复错误时,修复整个课程?不要只是修复bug;不要只修复代码中的类似错误;改变游戏,这样你再也不会创造那种bug了。

答案 2 :(得分:5)

  1. 有两种方法可以编写无错误的程序;只有第三个有效。 ~Alan J. Perlis

  2. 在程序中发生错误的唯一方法是由作者放在那里。没有其他机制是已知的。程序无法通过与其他有缺陷的程序坐在一起来获取错误。 ~Harlan Mills

答案 3 :(得分:5)

错误对每个人都很重要。我总是发现编程越多,我对编程的了解就越多。我对几年前写的代码感到畏缩!我最初是一个爱好者,非常喜欢它,所以我去了工程学院,获得了计算机科学工程专业(我在最后一个学期)。这些是我学到的东西:

  1. 我需要时间来实际设计我要写的内容并记录设计。它确实消除了很多问题。设计是否就像写下我要编写的内容或完整的UML建模(:()一样简单无关紧要。它的思想和目的的清晰度以及我来时回顾的材料在最重要的一段时间后回到代码。

  2. 无论我写什么语言,保持我的代码简单易读都很重要。我认为不要过度复杂化代码同时不要过度简化代码是非常重要的。 (艰苦的学习课程!!)

  3. 效率优化和花哨技巧应该在最后应用,仅在必要时才应用,并且仅在需要时才应用。另一件事是我只应用它们如果我真的知道我在做什么而且我总是测试我的代码!

  4. 学习语言相关的详细信息可以帮助我保持代码bug的免费使用。例如,我了解到scanf()在C中是邪恶的!

  5. 其他人已经评论过编写测试的禅宗。我想补充一点,你应该总是进行回归测试。 (即编写新代码,测试代码的所有部分以查看它是否中断)

  6. 有时难以记住代码的精神图片,所以我总是记录我的代码。

  7. 我使用方法来确保代码的不同部分之间存在最小的依赖关系。接口,类层次结构等(解耦设计)

  8. 在我编写代码和遵守纪律之前进行思考是另一个至关重要的技能。我知道没有格式化代码的人所以它的可读性(Shudder!)。

  9. 阅读其他人来源以学习最佳实践是好的。制作我自己的清单更好!在团队中工作时,必须有一套共同的组合。

  10. 不要因分析而瘫痪。编写测试,然后编写代码,然后执行并测试。冲洗洗涤重复!

  11. 学习阅读我自己的代码并将其与错误相结合非常重要。提高我的调试技能库是一项很好的投资。通过帮助我的同学定期修复错误,让他们保持敏锐。

  12. 当我的代码中存在错误时,我认为是我的错误,而不是计算机和工作。这是一种真正帮助我的心态。

  13. 一双新眼睛有助于调试。程序员在疲惫时往往会错过自己代码中最明显的错误。让某人显示您的代码非常棒。

  14. 有人向他们提出想法而不被评判是很重要的。我和我的妈妈(不是程序员)交谈,向她提出想法并找到解决方案。她帮我反复反复思考并改进它们。如果她不在,我会跟我的宠物猫说话。

  15. 我不再对虫子气馁了。我已经学会了喜欢删除bug几乎和编程一样多。

  16. 使用版本控制确实帮助我管理了编码时获得的不同想法。这有助于减少错误。我建议您使用git或您可能喜欢的任何其他版本控制系统。

  17. 正如Jay Bazzuzi所说 - 重构代码。我刚刚在阅读完答案后添加了这一点,以保持我的清单完整。所有的功劳归于他。

  18. 尝试编写可重用的代码。重用代码,包括您和代码库。使用无错误的库来执行一些常见任务确实可以减少错误(有时)。

  19. 我认为以下引用说得最好 - “如果调试是删除错误的艺术,编程必须是将它们放入的艺术。”

    任何不同意见的人均不得冒犯。我希望这个答案有所帮助。

    注意
    正如Peter所指出的那样,如果您正在编写大量代码,请使用面向对象编程。代码长度是有限的,在此之后,如果以程序方式编写,则变得越来越难以管理。我喜欢程序化较小的东西,比如玩算法。

答案 4 :(得分:3)

显然,对于任何程序员来说,错误都是很重要的。只需查看Stack Overflow上的问题列表,就可以看到这一点。

爱好者和经验丰富的专业人士之间的区别在于,专业人士将能够以更“防御”的方式使用他的经验编写代码,从一开始就避免出现多种类型的错误。

答案 5 :(得分:3)

所有其他答案都很棒。我会添加两件事。

  1. 源代码管理强制。我假设你在这里的窗户。 VisualSVN Server是免费的,可能需要4次点击才能安装。 TortoiseSVN也是免费的,它集成到Windows资源管理器中,绕过VS Express限制,没有加载项。如果您创建了太多错误,则可以还原代码并重新开始。没有源代码控制,这几乎是不可能的。此外,如果您有笔记本电脑和台式机,则可以同步代码。
  2. 人们会推荐许多技术,如单元测试,模拟,控制反转,测试驱动开发等。这些都是很好的做法,但是不要试图把它们全部塞进你的脑袋里。您必须编写代码才能更好地编写代码,因此请将这些技术慢慢地编写到代码编写中。在跑步之前,你必须爬行才能跑步。
  3. 祝你的编码冒险好运!

答案 6 :(得分:2)

这是一个常见的新手。当你获得更多经验时,你仍然会有bug,但是它们会更容易找到和修复,因为你将学习如何使你的代码更加模块化(这样改变一件事就没有涟漪效应在其他地方),如何测试它,以及如何将其结构化以快速失败,接近问题的根源,而不是在某个任意的地方。一个非常基本但有用的东西,不需要复杂的基础设施来实现,是检查所有具有断言的非平凡先决条件的函数的输入。如果我原本会遇到奇怪的段错误和几乎无法调试的任意行为,这几次就救了我。

答案 7 :(得分:2)

如果错误不是问题,那么我将能够在10分钟内编写100,000行程序!

你的问题就像是,“作为一名业余医生,我担心我的病人的健康状况:有时当我不够小心时,他们会感到恶心。患者的健康状况对你们的专业医生来说也是一个问题吗?”

是的:这是核心问题,甚至是唯一的问题(对于'bug'的任何足够全面的定义)。

答案 8 :(得分:2)

错误对每个人来说都很普遍 - 专业与否。

项目规模越大,分布越广,必须越谨慎。一看任何开源bug数据库(例如:https://bugzilla.mozilla.org/)都会为您确认。

软件行业已经发展了各种programming stylesstandards,如果使用得当,会使错误的代码更容易被发现或限制其影响。

因此,培训对代码质量非常积极......但最终,错误仍然存​​在。

答案 9 :(得分:2)

如果你只是一个业余爱好者程序员,那么学习全口径TDD和OOP可能会花费比你愿意投入更多的时间。所以,假设你不想把时间放在他们身上,一些容易消化的建议,以减少错误:

  1. 让每个功能做一件事。怀疑一个功能超过10行长。如果您认为可以将其分解为两个函数,那么您可能应该这样做。有助于您控制这一点的东西是根据他们正在做的事情来命名您的功能。如果你发现你的名字很长而且不实用,那么你的功能可能做得太多了。

  2. 将魔术字符串转换为常量。也就是说,而不是使用:

    人[ “妈妈”]

  3. 改为使用

    var mom = "mom";
    people[mom]
    
    1. 将您的函数设计为执行某些操作(命令)或获取某些内容(查询),但不能同时执行这两项功能。
    2. OOP的极短且易消化是http://www.holub.com/publications/notes_and_slides/Everything.You.Know.is.Wrong.pdf。如果你得到这个,你就会得到OOP的要点,并且坦率地领先于很多专业程序员。

答案 10 :(得分:1)

普遍的看法似乎是普通程序员每1000行代码产生12个错误 - 取决于你要求的确切数字,但总是每行代码 - 所以,程序越大,越多错误。

Subpar程序员倾向于创造更多错误。

新手经常被语言的特质所困,缺乏经验也会导致更多的错误。随着你的继续,你会变得更好,但你永远不会创建无错误的代码......好吧我仍然有bug,即使在30年后,但这可能只是我。

答案 11 :(得分:1)

从专业人士到业余爱好者都会遇到令人讨厌的错误。真正优秀的程序员被要求追踪真正令人讨厌的错误。这是工作的一部分。当你盯着一个令人讨厌的错误两天时,你会知道你已经成为一名软件开发人员而且在沮丧地喊道:“谁写了这个废话!?!?” ......只是意识到这是你。 : - )

软件开发人员的部分技能是能够将大量相互关联的项目直接保留在他/她的脑海中。听起来你正在发现当你的系统心理模型崩溃时会发生什么。通过练习,您将学会设计不那么脆弱的软件。关于软件设计的主题有大量的书籍,博客等。当然还有Stack Overflow特定问题。

所有这一切,这里有几件事你可以做:

  1. 一个好的调试器是非常宝贵的。通常,您必须逐行浏览代码以找出问题所在。
  2. 如果对您的项目有意义,请使用Python或Java等垃圾收集语言。 GC将帮助您专注于使工作正常而不是因为令人抓狂的内存错误而陷入困境。
  3. 如果你写C ++,学会爱RAII。
  4. 编写大量代码。软件在某种程度上是一种艺术形式。很多练习会让你更好。
  5. 欢迎使用Stack Overflow!

答案 12 :(得分:1)

真正改变了我对代码复杂性和错误的几率是使用编码标准 - 如何放置括号等等。它可能看起来只是无聊和无用的东西,但它真正统一了所有代码,使其更容易阅读和维护。那你使用编码标准吗?

答案 13 :(得分:0)

如果您的组织不善,您的代码库将成为您自己的Zebra Puzzle。添加更多代码就像在你的拼图中添加更多人/动物/房屋一样,很快你就会在你的拼图中拥有150种不同的动物,人物,房屋和卷烟品牌,你会发现它只花了你一周的时间来添加3行代码,因为一切都是如此相互关联,以确保代码仍然按照你想要的方式执行。

最流行的组织范式似乎是Object Oriented Programming,如果你可以将你的逻辑划分为可以相互独立构建和使用的小单元,那么你会发现它们在发生时更不痛苦。