真正的程序员使用调试器吗?[关闭]


15

如果有经验的程序员实际上曾经使用过调试器,以及在什么情况下使用过。尽管在回答这个问题时我曾说过“几个月”,但我的意思可能是“几年”,但实际上我并不使用调试器。因此,我要回答的具体问题是,作为经验丰富的程序员,您将在哪种情况下使用调试器?


14
这就好像在问经验丰富的程序员是否正在使用键盘...我不知道与键盘有什么关系-您认为他们是上帝,并且从一开始就创建了可以正常工作的代码吗?即使是这样,这对您意味着什么-您是否会在需要时停止使用调试器,并开始说:“我不使用调试器,所以我是一名程序员” ... :)顺便说一句。我怀疑任何专业人士都会回答这样的问题……

3
@Wooble:“做有经验的程序员使用调试器”这个基本问题是一个很好的问题。实际上,它引起了一场小型的圣战,这让我感到惊讶。
凯文

19
真正的程序员当然会使用蝴蝶
Rein Henrichs

4
现有的大多数调试器都是老式的,具有糟糕的接口,并且要求程序员了解和理解难以掌握的概念和范例,如今,期望大多数程序员使用或了解它们是不公平的。结果,大多数现代的,经验丰富的程序员都竭尽全力地学习编写很少需要在调试器中进行调试的代码类型所必需的技能,从而避免了这种痛苦。所以“是的,他们使用它”和“尽可能少地使用”
blueberryfields

7
经验丰富的“不使用调试器”的程序员可能会考虑gdb / SoftICE,并且从未使用过实际的集成调试器(因此可能不使用IDE)。他们远远落后于痛苦的时代。
BlueRaja-Danny Pflughoeft

Answers:


44

我会说不使用调试器是缺乏经验的迹象。逐行逐步执行代码是跟踪执行流程的最佳方法。


30
奇怪的是,经过30多年的汇编,fortran,C,C ++等编程工作之后,我觉得自己不想使用它了。

59
长时间做某事并不一定会让你擅长。
ceejayoz

31
能够使用调试器是经验不足的迹象。仅仅通过阅读代码就无法理解程序的流程。当然,经验丰富的程序员有时会需要调试器,但是如果您可以阅读代码,则无需这样做,并且也不会使调试过程更快。
GolezTrol

10
@Karl Bielefeldt:让我举几个著名的程序员例子,他们不使用调试器进行调试。Linus Torvalds,Linux的作者。Larry Wall,Perl的作者。对您来说足够复杂的软件?
btilly

9
@Neil:您花费多少时间来编写自己的代码,以及花多少时间维护其他人编写的代码?特别是,有多少其他人编写的维护代码,这些人本该不应该被允许在编程语言之外的任何地方使用的?
Carson63000

28

我经常使用调试器,因为我在大型系统上工作,因此很烂。 http://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html

无论您的代码有多短且经常阅读,它总是会存在错误。http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html

要犯错是人的,永远不能证明程序是正确的,那么为什么不使用调试器/自动测试之类的工具来帮助自己完成这一困难的业务呢?

如果代码足够短,那么将进行简单的测试。另外,如果代码很短并且您知道错误的性质,那么阅读代码就足够了。但是,一旦代码库很大,将几种语言混合在一起,再加上3层,那么您必须在多个级别上都具有良好的测试覆盖范围,再加上一个非常好的调试器-否则您将浪费大量时间。

那么,什么时候不需要调试器?

我不是最聪明的编码人员,也不是经验最丰富的编码人员,但是,有时候我不需要使用调试器。那时:

  • 该代码是我的或写得很好的AND
  • 它以可读的语言编写,并且
  • 整个项目很小。

什么时候严重依赖调试器?

  • 简短的回答:经常
  • 当应用程序崩溃时。特别是在部署时。在该计算机上安装VS2010可以使“未知错误”和有所不同FileNotFoundException
  • 当第三方库崩溃或行为异常时。
  • 当代码编写不当时。特别是在过去10年中,如果有10个不同的人触摸了同一个文件,其中7个不再属于公司。
  • 当项目很大时
  • 当代码相当单一时。
  • 当涉及多个层(GUI,SQL,BL)时。

请注意,“调试器”可以引用多个工具。我使用Visual Studio调试器,SQL调试器(主要用于存储的proc)和SQL事件探查器(以找出正在调用哪个SP)。我需要编写快速的sysadmin-ish Python脚本的这种能力的工具吗?否。如果我制作了自己的基于GUI的小工具?要看。如果是.Net WinForms-可能不是。如果是WPF-是。

究竟什么定义了“真正的”程序员?一种快速吗?有知识吗?擅长算法吗?写好的文档?刚好一个毕业生毕业于这个新头衔?一个人什么时候越过魔界线?

我要说的是,一个程序员在现有的100多年的人力资源工作中还没有弄糟,就没有机会因其复杂性和自身的局限性而感到谦卑(以及对代码质量的挫败感)。

我个人尝试使用可用的最佳调试器,而且我倾向于经常使用它。如果任务足够简单,并且不需要调试器,那么我就不使用它。很快就可以确定我是否需要一个。

...

现在,从理论上讲,我可以阅读很长时间的代码库,以至于我只能理解它。但是,动手方法效果最好,而且我经常想重新编写我看到的愚蠢代码。不幸的是,清理我所在的代码库需要花费10多年的时间。因此,使用调试器显然是第一步。只有当我发现五百万行代码中的哪一行正在起作用时,我才会上下扫描该文件以试图弄清楚该类在做什么。


+1,出色的答案,我特别同意“何时涉及多个层次”方面,这是“仅阅读代码并发现错误”的提倡者很少提及的一个方面。
Carson63000

很高兴您可以阅读全部内容。
Job

+1是一个不错的答案,它可以用来检查“真正的程序员”的定义。使用此短语会使OP变得狡猾,有趣且具有潜在的炎症性(由于贬低暗示或影射)。
曼多利2011年

1
“永远不能证明一个程序是正确的”这是不正确的。
GManNickG 2011年

1
@GMan,请详细说明一下。据我了解,以前许多证明特定语言的简短代码正确性的尝试都失败了,例如,证明完成后(由专门从事这种证明的教授)发现了几个错误。我想,有些非常琐碎的程序可以被证明是正确的。我很好奇在这里找到您的角度。
工作

17

“我不喜欢调试器。从来没有,也许永远不会。” — 莱纳斯·托瓦尔兹

另一方面,他没有Stack Overflow帐户,所以我不确定您是否对他的意见感兴趣:)


3
我们中没有多少人是Linus Torvalds,对于我们其余的人来说,我们需要调试器。
Nodey The Node Guy

7
内核不太适合调试器。

7
是的,内核编程与用户空间编程是一个不同的领域。我通常不同意Linus关于用户空间的观点,但是在处理内核空间时,它们绝对值得尊重。
选项

16
“我不喜欢调试器”并不表示“我不使用调试器”。Linus实际上说的是:“我不喜欢调试器。从来没有,也许永远不会。我一直都在使用gdb,但我倾向于将它用作调试器,而不是用作可以编程的类固醇的反汇编程序。” (我知道有些人会试图扭曲,以表示Linus不使用调试器,但这并不准确。)
Kristopher Johnson

6
好像是Linus Torvalds,我从没有达成任何共识。
BlueRaja-Danny Pflughoeft

12

因此,我要回答的具体问题是 ,作为经验丰富的程序员,您将在哪种情况下使用调试器?

  • 当您无法通过阅读代码来“调试”时。
  • 当您无法预测某些变量在给定时间内的时。
  • 当您的代码思维模型与代码给出的输出不匹配时

编辑:

我的运气/不幸是在编程过程中不知道如何使用调试器。因此,过去我不得不在没有调试器的情况下进行调试。但是,在学习使用调试器后,> 查找错误的效率提高了100倍


对于“当您的代码思维模型与代码给出的输出不匹配时” +1
用户,

8

给出与当前答案略有不同的观点;作为在经常具有实时组件的系统上工作的嵌入式软件工程师,我很少使用调试器。

有时,调试器可能是一个了不起的工具,每当我能够在台式机上构建和运行代码时,我总是会使用调试器。

在芯片上,由于存在实时限制,因此尝试使用调试器会带来沉重的负担。一旦暂停执行,您很可能会破坏系统其余部分的时序,甚至可能致命。通常在芯片上,非关键代码中的printf和时间关键代码中的IO摆动是最好的,实际上也是最简单的工具。它不如调试器好,但使用实际系统要便宜得多。


1
您可能想研究基于硬件的调试器板
Steven A. Lowe,

@史蒂文谢谢; 不幸的是,虽然我使用的某些系统具有适当的硬件支持,但其他系统却没有。虽然我们通常可以选择逻辑分析仪,但从时间上看,它往往会变得更加昂贵。
卢克·格雷厄姆

我完全相反。我在嵌入式系统上经常使用调试器。不过,我同意这样做会打乱时间。要过滤掉和/或最小化由于将调试器放入循环中而导致的更改,需要花费大量的精力。
Karl Bielefeldt

7

我认为有经验的程序员在需要时几乎只会使用调试器。有什么比实际跟踪代码执行更好的跟踪错误的方法了?

您是否假设世界的Skeets不会犯错误或只知道一切?在某些情况下,除最琐碎的程序外,所有程序都会以意外的方式运行。可以肯定的是,必须对问题进行调查。因此,选择是在频谱的一端使用打印语句,或者查看检查发生了什么,事后验尸,或者在代码执行并找出正在发生的情况时在中间看。

也许更好的思考方法是有经验的程序员知道何时使用调试器。在几乎没有依赖关系的代码中,查看堆栈跟踪可能足以找出问题所在。但是在有些复杂的场景中,您的代码与其他代码一起工作,并且您需要调试器来查看您未编写的内容。


4
好吧,这正是我要研究的内容-我是一位经验非常丰富的程序员,并且从未使用过。

5
@neil,也许您不需要。放心,现在是时候调试器将成为最根本的问题的最简单的方法,无论您最终是否真正使用一个
调试器。...– hvgotcodes 2011年

我可以阅读我也没有写的东西。如果我做不到,那通常是有用的,因为它是错误的代码。在其他情况下,我使用调试器。
GolezTrol 2011年

如果您使用的语言支持异常,并且您在适当地使用它们+日志记录框架(例如log4j或类似的东西),则总会得到指向错误行的堆栈跟踪。99%的时间是您没有想到的空指针异常。调试器还会告诉您什么?现在,当我使用c进行编程时,有些东西如果没有调试器就根本找不到(例如,堆栈损坏)。但是,这些类型的事情根本不会在高级语言中发生。
凯文

1
@kevin,对,我认为这两者之间存在一类问题,其中调试器是解决问题最自然的方法。也许我想看一下动态语言框架(如grails)中对象上的动态属性。也许我想确切地看到我认为不为空的东西变为空(NPE告诉您异常在哪里,而不是为什么为空)。也许我希望调试器在发生异常时暂停,以便我可以查看导致异常的代码组合,而不仅仅是堆栈跟踪中发生的异常。
hvgotcodes 2011年

4

我没有,而且我从事编程已有十多年了。我以前用c / c ++编程时。现在我用Java编程。事实是,如果您正确地进行了日志记录,那么最终将得到堆栈跟踪,这对于大多数熟练的开发人员来说已经足够了。另外,如果您正在编写(好的)单元测试和功能测试,那么可以消除一整类的错误。


如果有更多说明,我知道很多使用调试器的Java程序员。他们大部分时间都在放学。
凯文

1
stacktraces不显示数据-您必须自己添加该信息-但是它们是纯金。

1
@Thorbjørn:实际上,它们可以显示数据:例如,参见Python的cgitb模块。(名称中的CGI主要是残留的,该模块的最初目的是在CGI崩溃时显示可用的堆栈跟踪。)当然,这样做有时会导致获得太多数据,以至于很难导航到堆栈感兴趣的框架。不过我cgitb.enable(format='text')还是爱。
SamB 2011年

我并没有真正使用调试器,而是使用C ++
Nikko

@SamB凯文(Kevin)谈到了Java,但Java却无法做到这一点

4

谁在乎?我想知道的是,从长远来看,使用调试器会阻止我成为更好的程序员吗?当许多有经验的开发人员开始时,调试器的质量可能较低,因此它们是一个障碍。它是否妨碍了人们的深入理解?

一些可能比我们其他人更好的程序员发现需要调试器并构建了一个调试器(不知道是谁创建了第一个)。我敢肯定,这样可以提高他们的生产力。我怀疑这样做的动机是使较少的凡人能够编写代码。


3

很少。

您的方法应该足够小/简单以便可以编译和运行,单元测试应涵盖功能。如果发现错误,请编写测试。运行它,修复它。

仅当ive从无法测试的代码(例如ASP.NET框架)中获得意外行为时,我才倾向于使用调试器。


3
在这个线程中有一些真正讨厌的菜鸟……

2
没有理由对此投反对票-他是对的。
wadesworld

11
-1是因为这种说法就像说在拉斯维加斯赚钱的方法就是赢每一手牌。这并不能反映实际情况,并且声称所有代码都将是简单的仅存在于孤立的小问题中。另外,“运行,修复”声明完全忽略了如何进行修复。我本来打算让它滑下来,但然后暗示所有不同意的人都值得投票。
whatsisname 2011年

2
-1:“您的方法应该足够小/简单,可以被您的思想编译和运行”与现实脱节。这就像说一个超过20行的函数过长。废话。
John Dibling

3

在Smalltalk中,我几乎完全在调试器中进行开发:

  1. 写一个我知道会失败的测试。
  2. 运行测试。失败时,调试器会弹出。
  3. 在调试器中,编写通过测试所需的代码。
  4. 恢复执行。
  5. 如果绿灯亮,请通过新的失败测试转到步骤1。否则,在调试器中找出我做错了什么并修复。

2

我在需要时使用调试器。那不是每天,但是它确实偶尔发生。有时最好逐步浏览代码以查看实际发生的情况。

我必须承认,我越来越少地使用调试器。我在Delphi从事开发工作已超过10年。我也用PL / SQL编写存储过程。几个月以来,我也是PHP开发人员。

如果发现几年前编写的一段晦涩的代码,并且需要对其进行修改,则我主要在这两种情况下都使用调试器。如果难以阅读代码,有时可以帮助找出程序的确切工作方式。在PHP中几乎没有必要,但是在基于事件的Delphi中,当您拥有复杂的框架时,它有时会有所帮助。

但是正如您所说,使用调试器是一个例外。只需阅读代码并修复您(或其他人)犯的任何错误,即可解决大多数问题。

但这是单步执行代码的过程。发生异常时,我经常使用调用堆栈,并且偶尔在某个地方放置断点以检查变量。但是,几乎总是在一段需要无论如何都需要彻底重构的代码中。


2

我有时不使用调试器进行编码,而只是在被迫使用枪口时才进行编码。8051或Z80上的旧式嵌入式枪托。

恕我直言,您需要调试器并登录任何复杂的作业。一次不能替代另一个。如果应用程序塞在驱动程序中,则日志记录系统将无济于事,例如,代码唯一可以做的就是与硬件交互并设置信号灯。

调试器无法解决系统错误,在这些错误中,应用程序可以按照编写方式正常运行,但是由于某些间歇性的通讯协议错误,系统仍然无法正常工作。

因此,我需要调试器来删除愚蠢,明显的错误和硬件故障。我需要良好的日志记录来捕获间歇性的系统集成错误。

我必须同时拥有-我需要我所能获得的所有帮助!


2
z80对于调试器来说足够大。CP / M具有ZSID。

1

当这些步骤失败时,我仅使用调试器:

  1. 获得可重现的错误。认为。通常这就是所需要的。
  2. 检查所有堆栈跟踪和日志。
  3. 在有问题的代码周围添加更多日志记录。

这些步骤可处理所有情况的95%。这意味着我很少使用调试器,而当我这样做时,它往往会给我带来太多信息,并且让我陷入无关的细节中。如果在多线程实时系统上工作,则尤其如此。

因此,明智地放置日志记录语句会走很长一段路。


1

难道仅仅是经验丰富的程序员与非常老的程序员一样,他们学会了编程并养成了习惯,那是在调试器并非总是可用的时候,有时不是很好吗?

如果您真的擅长于printf调试(以及八十年代,我们别无选择,只能真正做到这一点),那么调试器可能并不会增加太多。


0

这是个人选择的问题。

老实说,我认为调试器在某些情况下很有用,在某些情况下,调试器可以帮助您了解程序执行的任何给定步骤中ram的状况。

调试器的主要用途是在不设计程序本身的情况下暂停程序:此功能非常重要。

除了这两个功能外,我认为调试器不是真正必需的;您制作的任何复杂程序都应具有某种“冗长”的模式,即通过printf或std :: cout告诉它正在执行的所有操作,做出的选择以及许多其他参数。

试想一下,如果您编写了一个程序,而用户却在使用它时遇到了问题:如何知道他是否按照设计使用的方式来使用它,或者他抱怨的东西可能是一个错误?

调试器就像您汽车的电动转向器:拥有一个舒适,但不会使您的驾驶感觉更好。

编程是关于设计和逻辑的,工具可以帮助您跟踪事物的方法并不能使您成为更好的程序员。

另外,调试器对编译语言很有用,对解释型语言则少得多。


2
我不明白编译和解释与它有什么关系。
Michael Burr

好问题:我也没有。
11
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.