百科问答小站 logo
百科问答小站 font logo



只靠读代码 debug 不会单步调试能当编程高手吗? 第1页

  

user avatar   serenayu 网友的相关建议: 
      

上个月刚接手一个祖传代码库,几千行python没有定义任何数据模型,没有任何类型标记,没有文档,所有数据都是dict, kwargs,用字典key自由发挥,山舞银蛇,原驰蜡象,欲与天公试比高。来来来,键盘给你,你来读 [狗头]


user avatar   s.invalid 网友的相关建议: 
      

有些语言(的调试器)压根就没有单步跟踪功能。比如TCL,事实上它压根就没有可用级的调试器(更不要说“好用”了)。


另一些场合,比如线上跑的服务代码、比如跑在集群上的多机协作功能、比如多进程/多线程代码,往往也不能调试或者没有条件调试。因为调试或者会影响它的时序,从而改变问题性质;或者,某些大吞吐量业务中的偶发故障,计算机一秒钟响应几千个请求你能看清一个不能?那么,如果一个bug每周/每月发作一次呢?


然而单步跟踪仍然是程序员一生中能得到的最好的礼物——我有点犹豫是否应该加之一。


这是因为,单步跟踪给了你一个“实实在在、细致入微的观察程序在CPU上的执行过程”的机会。它可以显著增强你对程序执行过程的理解、促进你对各种side-effect的了解和掌握——将来,别人只看到一行代码,你能看到这行代码执行时,从数据源到CPU标志位再到中间变量、输出区的一切影响。


只有掌握到这种程度,你才可能有效分析那些无法跟踪的、时序相关的bug。

尤其如c/c++这样硬件紧密相关的语言,没有这种程度的理解,那就是还没学会。

Java要稍微好一些,达到入门级语言律师的水平就足够了。反正文档里都有讲。

python之类就随意了,它把一切都封装起来不希望你看;你本来也没必要甚至不应该挖它内部的东西。


但,哪怕没办法单步跟踪的TCL,你也应该对每行代码对你自己的数据、你声明的每个变量的所有影响一清二楚。否则就不可能写出可靠的、不隐藏bug的程序。

事实上,对初学者来说,单步执行自己写过的每一行代码是提升最快的实践。

哪怕是老手,写一个过于精巧的算法时,单步执行一下其中难度最大的代码、看看每个变量每个标志位是否按自己的预期变化、有没有预料之外的side-effect,也是最为有效的debug手段之一。


——事实上,有人建议,对每个程序员,只要有条件,就应该在敲完代码后把自己的每行代码单步执行一遍:你设计的代码你最清楚,看一眼它的执行,你几乎立刻就会发现疏漏之处。

——我从学习C/C++开始就一直坚持这么做。若干年后,其结果就是……没错,还是那句话:“我写的2000行代码以下的小程序,包括C/C++编写的、涉及多线程协作的代码,都经常可以在写好后首次编译就0 error 0 warning 0 bug的通过”:很简单,长期这么做,使得我对每一行代码可能产生的任何影响,包括CPU标志位、包括可能的时序故障,甚至包括编译器经常会做什么优化,全都了如指掌。


甚至于,虽然服务器代码难以调试;但代码崩溃时你还是能得到一个core;你可以把GDB附加上去,查看“吐core”点前后的每个细节……而要能看懂这些,对每一个瞬间程序应该处于什么状态你就必须了如指掌。


就好像刑侦学一样:没有DNA没有显微镜没有监控的时代,我们照样能破案;但有些案子没有DNA测序没有显微镜没有监控还真就破不了——而几乎所有的案子,DNA显微镜监控拿出来都能极大幅度的降低它的侦破难度、把过去三五天甚至三五年解决不了的问题瞬间解决。

就好像二十多年前的白银案在DNA测序普及后被直接侦破一样。


总之,我无法理解“不会单步调试”是一种什么样的神奇状态。如果你真的有能耐只靠读代码就能把一切side effect说的清清楚楚,那么你怎么可能不会单步调试?如果21天真的能学会c++的话,单步调试至多是第三天的课程啊。第三天你都掉队了、而且再也没跟上;结果21天后,你不光会了,还学成了人肉编译器人肉CPU?


user avatar   Ivony 网友的相关建议: 
      

老实说我没看懂这个问题,

这个问题像是在说:


我只会广义相对论,完全不懂经典力学,能做物理科研吗?

我只会百米短跑,但是不会走路,能参加田径队吗?

我只会高台跳水,不会爬泳梯,能参加跳水队吗?




你是怎么做到能读懂代码却学不会单步调试的


user avatar   windoze 网友的相关建议: 
      

我不是很明白“不会单步调试”是个啥意思。

现在常见的IDE里单步调试也就是加个断点点个运行然后看看变量值啥的,这也算是个专门的技能吗?打把撸啊撸都比这复杂多了好吧。

如果连这都不会,我脚着编程还不是你最应该担心的事。


user avatar   zorrolang 网友的相关建议: 
      

这一个问题实际上包含两个问题,分别简要回答如下:

  1. 高手不可能“只”会靠读代码debug。
  2. 不能单步调试不能阻挡你成为高手。

关于debug我想说以下几点个人看法:

  • (1)读代码

初学者往往都是从读代码debug开始的,自己写了一段程序,然后编译或执行发现错误,自己根据错误位置和错误条件,反复读一下相关代码慢慢找到问题。这样的步骤在初学的时候很常见,这也是脱离“遇到错误就问人”的第一步,学会自己看自己的代码自己找错误是初学者学习编程需要跨出的第一步。而读代码无论是初学者还是称为顶级的程序员,都是解决问题时必须要做的,所以会读代码是程序员从始至终都在不断进行、不断提高的技能。

  • (2)打印输出

但是当问题变得复杂后,光靠“读”只能找到一些可疑的地方,为了验证对可疑地方的猜测,我们这时候就需要借助一些“交互”手段来进行测试。这时最常见的“交互”手段就是输出(print)我们感兴趣的信息到终端来查看。不管编写什么层的程序,这一招几乎都是方便有效的。以前我们直接面向处理器、控制器编程的时候,往往会写上串口驱动和一些串口调试的程序(函数),方便在需要调试的时候通过串口接收一些信息的输出到电脑屏幕上查看。在使用高级语言在上层编程时,这种方式更加方便,因为高级语言几乎都封装好了print类的方法方便使用。即使在调试内核时我们也常用print的方式来调试,不管是自己在需要地方加printk,还是通过trace point等,无非都是想获得一些信息来了解运行状态。

  • (3)系统信息和状态

获得运行状态信息的方法除了最常见的输出方法以外,还有一些极端条件下的方式。比如在系统crash(windows用户常称为“蓝屏”)或者hang住(俗称死机)的时候,这种状态下我们无法进行交互。这就好比受害者已经死亡,你不可能和受害者进行“交互”的谈话,那你能做的就是尽量“保护现场”以便后续分析。计算机里管这种叫crash dump。就是保存crash的瞬间的内存信息,我们知道程序是在内存里运行的,所以保存内存信息就相当于保存现场,后续程序员可以对这个保存现场的文件进行分析。

  • (4)输入/注入

“交互”除了最常见的输出以外,还有输入。改变输入我们一般通过修改运行参数和运行条件等方式来达到,在用户很难通过“外界”直接干预的时候,比如一些很难达到的临界态等,这时候就需要到代码的内部去搞一下。比如在代码内留下可以注入的点,来影响运行时的一些状态。或者通过一些诸如systemtap的办法,来达到影响运行时输入输出的目的。

  • 所谓的“单步调试”

那么所谓的“单步调试”是什么呢?其实主要就是综合了上面四种调试方式(我们姑且将读代码也算做一种debug的方式)的更高级的调试手段。通过gdb等调试器帮助程序员一边查看每一步前后的源代码,一边可以查看每一步执行前后的程序或系统状态,还可以修改一些变量或参数的数值来影响输入。

虽然单步调试很强大,但是能做到单步调试的条件其实比较苛刻和繁琐。对于很多高级语言所写的应用层程序来说,做单步调试想对来说比较容易,不管是单步执行还是分析coredump,很多时候都很容易做到。但是对于较底层的程序来说,单步调试则很难,很多人可能都知道Linux的kdb,但是这个东西实际用起来比较苛刻和麻烦,我周围几乎没人用它来调试bug。用的更多的反而是上面分开的(1)(2)(3)(4)的方式。

这里我们不要混淆一个概念,调试技术实现上的难易水平,不等于使用调试技术的人的水平。你会不会使用更高级的调试工具,和你的编程水平没有直接关系。再厉害的程序员也几乎都是用print的时候多。他们厉害的地方不在于他们会不会用更厉害的调试工具,而是他们能从纷繁复杂的代码逻辑里理出可能造成问题的可疑之处,然后用当前对于他们手头来说最准确最便捷的方法分析和验证。

所以只能读代码debug是不行的,会单步调试也说明不了什么,只有会读代码并会配合合适的调试手段,能比较精准的锁定问题范围并有效的调试找到问题所在,才是编程高手。


user avatar   yang-bo-75-77 网友的相关建议: 
      

先说答案:可能性是有的,但是对于问这个问题的人来说,可能性不大。

关于可能性,因为机器的运行规则非常确定,只是因为太复杂了,而我们人脑的context太小,记不下那么多规则,所以你很难了解具体每一步怎么运行的。所以,计算机世界喜欢玩封装,封装后,大部分的细节大部分时候你就不需要管了。不需要管也就意味着你脑子里的知识系统不是完备的,没碰到了没事,碰到了还用错了,就是bug。于是你只能debug,因为此时,你脑子关于机器的认知是不够准确的,你无法通过在脑子里复盘就知道错在了哪里。毫无疑问,没什么比单步调试更方便更能确认问题点的手段了。在不能单步调试的环境里,例如production或者多线程之类的场景里,只能拼命加log,log加多了还担心影响性能,惨兮兮的。

所以,存在一种可能性,一个人天赋异禀,或是在太过熟悉的领域,他脑子里的机器模型,真的完美匹配机器的运作。于是他不需要单步调试。唯一的问题是这样的人必然会单步调试。


下面说点题外话。

一般来说,我不想回答这种问题。因为这种问题往往意味着提问者有点贪小便宜的心里,总想着存不存在以小博大的手段。这种心态,往往遇到点小挫折就会打退堂鼓。所以,诚实的回答,很可能就成了劝退~

但其实稍微搅几遍逻辑,就会发现终南捷径、事半功倍这种词都暗示着原有方案的差劲。走在正确的道路上,就没有小道可抄。甚至有些时候,因为涉及到个人条件不同,有些“弯路”是你必须走的,不能看见别人跑得快,就认为自己也能那样跑。

所以,在学习阶段,我个人认可的最有价值的做法,就是不要计算代价的去摸清答案,去实践,去验证自己的理解准不准确。“正确的答案”往往要学会了才能给出~而我认为这“正确的答案”也并不正确,因为我们通常不记得自己不会时的状态。

所以,学习是风险投资,而人这种生物,很喜欢自我实现的预言,过早算计收益,尤其是短期的、确切的收益,容易导致放弃,抹杀人的潜在可能性。把握个整体预期,接下来就砸进去干吧。




  

相关话题

  如果一瞬间让所有编程语言的0.1 + 0.2 == 0.3,会造成多大影响? 
  要学 Python 需要怎样的基础? 
  为什么 C++ 没有 C 语言快? 
  有哪些计算机术语的翻译,让你第一次学的时候感到十分别扭? 
  大部分语言都用尖括号<>表示泛型,为什么golang要标新立异用中括号? 
  这样一个数据库分析软件需难度高吗? 
  在公司下班比其他同事早走好不好? 
  GitHub 上有些什么好玩的项目? 
  golang 为什么没有三元运算符? 
  如何评价 @左耳朵耗子 关于建设团队的一条微博? 

前一个讨论
如果你手机里第33张照片突然开始攻击你,你该如何反击?
下一个讨论
家人有心理疾病,我怎么做才好?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利