如何减少调试时间?[关闭]


15

遵循帕累托规则,程序员仅将20%的时间用于真正有用的事情。

我花了80%的时间进行调试,修复一些小问题,以使所有工作正常进行。

有没有办法花费更少的时间进行调试?


9
我不确定这是我如何解释帕累托原则的方法。
c_maker 2011年

6
<meme>看看TDD。</ meme>
StuperUser 2011年

1
调试时您实际上在什么?

3
您需要花更多时间专注于细节

1
只需不时查看代码即可获得很多收益。更好的是,您可以根据自己的需求写评论,这样以后就更容易发现错误。
Joey Adams

Answers:


5

AgdaCoq编码。一旦您的代码编译,它将起作用。如果过于刻板,请选择类型系统较弱的语言,例如Haskell或F#。

但是,在大多数情况下,您将在20%的时间用于编码以及80%的时间在测试和调试上花费更多,从而提高生产力。一周100%远远超过一个小时的20%。如果您需要完成调试工作,那么调试并不是浪费时间,并且您不应该为“提高”这一比例而烦恼。


1
因为某些事情在运行并不意味着它没有错误。错误通常是代码执行错误操作的结果。
HLGEM

3
@HLGEM,在投票之前,您应该阅读有关Agda和Coq的更多信息。如果您的代码可以编译,则可以保证证明 它完全符合其规范所说明的内容。当然,规范中也可能存在错误,但是我不会将解决此类问题称为“调试”。
SK-logic

2
@HLGEM,那么您的“调试”概念非常有创意,远非主流。而且无论如何,使用这种方法,编码和“调试”之间的比例将远非20/80。因此,请介意解释您的反对意见。
SK-logic

1
@HLGEM,它不在OP要求列表中。关于那里有多少开发人员,负责人等一无所知。唯一的问题是“如何衡量20/80的比例”,而使用静态验证的语言显然是最明显的答案。但是,正如我已经说过的那样,此答案仅适用于非常罕见的情况,通常,坚持20/80规则是更好的选择。
SK-logic

1
@ uhbif19 Knuth这么说的意思是幽默。你知道他的意思吗?
Phil

44

单元测试。

在开始进行单元测试之后,我发现编写的代码结构更好。这样就更容易避免和发现错误。我花了更少的时间进行调试,但是花了更多的时间来编写单元测试。

我还认为,在单元测试上投入的时间要比调试好。在调试会话后,我只修复了代码。同一错误可能会在几周后出现,我必须再次调试。如果我编写了单元测试,则该错误将记录为单元测试,之后又充当回归测试。如果该错误再次出现,则单元测试将向我显示此错误。


我使用单元测试并完全同意您的看法。但是,我无法测试所有内容。
uhbif19

5
你当然可以。好吧,不是所有的东西,而是所有重要的东西。通过使用接口,依赖注入,伪造和模拟类/方法,您将能够为几乎所有代码编写测试。
Fredrik

8
@Fredrik,您甚至无法正确地a + b对代码单元进行单元测试(除非您的测试涵盖了算术数据类型的整个范围)。
SK-logic

“在调试会话后,我只修复了代码。” -真的吗?我认为在调试会话后,我只是引入了更多错误-我只是不知道它们在哪里。
B

35
  • 单元测试,以便您首先知道代码是否有效。
  • 至少要进行一些前期设计,以便您知道要编写的内容。
  • 代码审查,因为两个头脑要比一个头脑好,而四个眼睛要比两个头脑好。更不用说即使尝试向他人解释您的代码也会发现许多问题。
  • 版本控制,以便您可以快速隔离可能导致此错误的更改。
  • 进行重构,以使您的代码不会变成可怕的混乱局面。
  • 阅读罗伯特·C·马丁(Robert C. Martin)的“清洁代码”,然后做他告诉你的事情。结果会让您惊讶。

5
的确如此-单一的实践(例如单元测试)不会带来一个数量级的改善,但是实践结合可以。换句话说...没有银弹。
迈克尔

我会添加TDD(如果可能)。
汤姆

1
实际上,我将对干净的代码进行排序并首先进行重构。单元测试对于尽早发现和修复错误很有用,但是它们不会减少错误的数量(它们会减少一点时间,因为当您将所有东西都存储在内存中时,您将修复错误,但仍然如此)。另一方面,编写干净的代码减少了实际的错误数量。
扬邬达克

1
@JanHudec重构+干净代码+测试= TDD
Tom

1
@Tom:是的,但是它的不同部分有不同的效果。学习编写干净的代码将帮助您减少调试时间,而无需进行任何测试。有测试,因此您可以在实现模块使用之前对其进行测试,从而可以验证重构时未修改行为,这是清理旧的混乱代码所必需的。
Jan Hudec

8

如果您引入了错误,它们会在您的生产代码之前被打破,因此单元测试将对您有所帮助-编写得当的单元测试还将告诉您到底是什么导致了错误。

这将为您提供大部分帮助,但是对于99.999%的项目,您仍然需要定期调试。我发现这里要做的最好的事情是做4件事:

  1. 尽可能使用不可变的类型-如果某个值的值有误,您将确切知道立即查找的位置(正在构造的位置)。
  2. 在代码中强制执行不变量-如果您知道绝对不允许使用值,请检查该值并在方法和构造函数的入口点中引发异常。如果将其与不可变类型结合使用,那么您也可以开始对什么有效或无效做出某些假设。
  3. 确保您有足够的日志记录-尽早进行此操作,它将为您提供有关何时出现问题的许多重要信息。AOP在这里非常好用。事后考虑通常会记录日志-在项目设置过程中尽早进行记录。
  4. 如果您的代码库足够大/复杂,请避免使用基元-例如,使用名为“ Age”的类型,而不是仅使用int。乍一看似乎没有意义,但是能够立即跟踪某事物的所有使用是一个巨大的调试胜利。

6

我的80%是调试。我正在修复简单的错误,并试图使所有工作正常。

首先编写单元测试,然后尝试覆盖尽可能多的内容。有人提到TDD,但我会选择BDD

最后,您很可能会花费80%的精力来调试复杂的错误。


6

如何花更少的时间调试?编写更少的代码。

认真地说,只要编写代码,就需要对其进行调试。单元测试等可以极大地帮助您,但是不要以为您会完全不需要它。


4

在开始编写代码之前,先了解什么以及为什么。然后一致地使用一种方法。选择哪种方法并不像持续重复使用该方法那么重要。如果您想要一贯的良好结果,则需要一贯的出色工作,而采取“疯狂的方法”是获得这些结果的第一步。当您确定问题时,可以根据需要调整方法,随着时间的流逝,您将改善开发流程,并希望减少错误,并进行更多有意义的新开发。


3

在编译之前,请仔细阅读代码。请仔细阅读语法和功能。如果一段代码太复杂,它可能会提供令人惊讶的信息,并且也是一个很好的指示。


我完全同意。编写代码后立即读取代码可以很快发现一些明显的错误,例如复制和粘贴错别字(有时很难在以后找到)。
jirkamat 2011年

3

大多数答案似乎都集中在如何减少必须调试的问题上,这很有价值。但是,调试总是必不可少的,因此研究提高调试速度的方法很有用。

  • 知道如何使用版本控制软件。

    • 使用分支将帮助您将开发区域分开,并且您将能够看到哪个开发区域存在错误,哪些没有错误。
    • 了解如何在VCS中使用二等分功能,Git内置了该功能。如果您使用未内置二等分功能的其他VCS,请寻找像git bisect一样适用于您的VCS的工具(我知道SVN和对于其他VCS而言,创建它应该不会太难)。这将帮助您缩小引入该错误的代码更改的范围,从而有助于了解将调试器指向何处。如果您对错误进行了测试,则此二分过程将更快,并且如果您练习原子提交,则知道哪个提交包含有问题的更改将更加有用。
  • 增进您对所用编程语言的了解。

    • 阅读有关编程语言的书籍,博客和代码。
    • 每次修复错误时,请确保您彻底了解为什么代码不起作用以及为什么修复有效。随着时间的流逝,您将学习使用您的语言的许多陷阱,这将帮助您避免它们的问题并在它们再次出现时发现它们的症状。
  • 保持逻辑

    • 不要一次更改多个事物,否则如果行为发生变化,您将不知道是哪个变化导致了行为的变化。
    • 验证您的假设。

2

添加到单元测试的注释中,但这仅在您的代码已被分离以支持它的情况下才是真正的好选择(例如MVC)。如果您无法实现MVC(或类似的项目)(旧项目),则单元测试根本不适用于您的UI。然后,我将添加自动化的UI测试(Microsoft编码的UI测试,WaitN),因为这将减少代码那部分中的错误。

我也强烈建议运行静态分析工具(例如,FxCop / Microsoft代码分析,Resharper,MS World的JustCode)。这些可以发现各种常见的编码问题,这些问题可以减少繁琐的调试任务,而将更多精力放在调试业务逻辑上。


2

使它工作,然后使其快速,然后使其美观。大多数错误来自早期的优化或完全正常的代码行重构。如果您是面向对象的,请不要重复自己,请保持简单,并始终对值范围进行检查,尤其是当您的方法仍然可以在约束条件下工作时。它不会帮助您减少错误,但可能会帮助您更快地发现错误,从而减少调试时间。


1
您的“大多数错误来自...”断言听起来不错,但是您是否有证据支持这一点?如果我说“大多数错误来自指定要求不当或缺乏清晰的设计”,我认为这同样令人信服。您应该添加链接或引用以支持您的陈述的研究。
Caleb

2

最近,我对这个问题有了很多思考-简单的答案是去读唐·诺曼的《日常事物的设计》;像设计产品一样编写代码。

换句话说,好的设计可以最大程度地减少错误。这意味着,您已经完成了一些事情(尽管您可能并不确切知道为什么)。

-名称功能直观。这正式称为负担。也就是说,可以按下按钮,可以切换操纵杆,可以拉动手柄等。

-很难编写错误的代码。请检查输入是否有问题,并尽早(而不是稍后)引发错误,并在适当的时候使用匈牙利语的应用程序,等等。这些称为锁定功能。

-在适当的地方使用抽象。短期记忆力较弱。

-文档显然很重要,但是确保代码正确使用的效率最低。简而言之,精心设计的产品不需要任何文档。(最明显的观察方法是看一些不好的例子:即带有推手的门。)

-单元测试。这些并不能真正防止错误,而要使错误在哪里清晰可见并提供理智。

我确定我缺少更多的原则,但重点是,请阅读有关错误设计的内容。


1

减少调试的最佳方法IMO是在编码时集中精力并放慢速度。这迫使您看到自己可能犯的错误!


1

尽管我完全支持上述建议的单元测试,但是TDD或BDD将非常有价值,因为您需要首先考虑问题和解决方案。

但是对我个人而言,花几分钟时间静静地坐下来思考问题以及如何解决该问题,以及每种方法的优缺点,确实对我的代码质量感到惊讶,并帮助我清除了混乱的头脑。

有时,在纸上快速书写可以帮助您查看拼图中较大的连接部分。

当我刚开始潜水并敲击键盘时,我会编写最糟糕的代码。一点点的思考和沉思就可以改变世界。

PS。我的意思是可能要花5分钟到10分钟,而不是花几个小时编写一个庞大的规范。


1

已经有了一些好的答案,不过除了其他人所说的以外,还提供了更多的食物。

从错误中学习。不要一遍又一遍地做同样的事情。

编程时,请确保掩盖一些极端情况-在那些经常发生错误的地方。

注意要求。即使它可以运行,但没有满足指定的要求,那也是一个错误。

如果从现在起六个月后出现问题,则异常日志可以提供真正的帮助。养成记录异常的习惯。


0

我的两个主要想法是:1)编写更好的代码,当您执行意外操作时该代码将失败2)变得更好地进行调试

我的代码乱七八糟

if(value!=null) throw new NotImplementedException();
if(obj.v>0) throw new Exception(); //sometimes i dont write NotImplementedException
if(value=="thing") throw ...;

每当我执行那段代码时,都会引发异常,这会导致调试器停止运行,这使我可以使用新功能进行编码或避免出现这种情况,而后对正在发生的事情感到困惑/存在错误

为了更好地调试调用堆栈,断点(带有条件),立即窗口(也称为提示或repl窗口),“监视”变量以及其他任何东西,会产生混乱。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.