如何高效地增强编程(特别是debug)能力?
近几年工作中,带过很多刚毕业的新人上岗,这个我总结一下无非是:多看,多写,多想。多看,看别人写的代码,好坏代码都看,在看了一段时间以后,你自己知道什么代码叫做好代码,什么样的代码会让你不断吐槽。多写,代码如文章。从来没有一个文豪是看文章看出来的,写是必须的一个过程,也是很漫长的一个过程,在有清晰的概念来定义代码的好坏的时候,你需要通过不断的练习让自己的语言表达能力过关。多想,综合上面两点,多动动脑子,不要别人说什么就信什么。
我总结的16字诀:明辨职责,厘清结构;规范注释,善用断言。明辨职责:不管是用什么程序设计方式,都存在代码块。每个代码块的职责必须是清晰不变的、可以明确定义的,并且在逻辑上是完整的、完备的。如果职责不清晰,那么程序的结构一定是混乱的。这对程序的开发及调试是极大的困扰。厘清结构:程序设计时,思路一定要清晰,首先就是层次结构要明确,这样才能弄清楚代码块之间的关系,使得代码块组成的结构也更趋于合理。做一件事,通常会分解为多个大步骤,每个大步骤又可以分解为多个小步骤,小步骤还可以继续分解,这样的结构就是层次结构。最终代码块所属的步骤在什么层上一定是清晰的,如果这个层次被打乱了,那么程序出现bug的概率极大。规范注释:很多时候,程序bug的产生是因为内部某些隐式条件的不满足,这更多的体现为调用者并不清楚被调用者对他的要求。因此,不要吝啬注释,通过规范的注释把这些要求表达清楚,会使得bug显著减少。善用断言:注释是防“君子”不防“小人”,对于不遵守规则的调用者,需要有防备,因此,通过断言(或者检查判断)来保证所要求的前提已被满足也很重要。另外,自己的代码块执行完毕后是否达到预期的目的,也可以通过断言或检查逻辑来判断。这方面,契约式编程的一些思想和做法可以借鉴。
单元测试很重要最迟在进行系统联调前,准备好单元测试用例(最好是一边写代码一边写单元测试用例),然后根据系统联调和生产环境的反馈不断的完善单元测试用例集。几个迭代下来以后,被单元测试覆盖的模块就能保持相当好的表现,并且你能很放心的去重构那些模块文档很重要在开始写代码前,先写文档,特别是如果项目中不止你一个人写代码的话,文档就更加重要。它能帮助你厘清思路,提前发现一些逻辑坑测试很重要系统上线前,多和测试人员聊聊,也许能救你一命日志很重要次要日志写日志文件里,用好流行的日志类,而不要用简陋的printf重要日志最好写数据表里,这样可以使用SQL和数据库软件的功能去管理分析\使用这些日志数据
debug的话,思路基本上就是不断地问自己两个问题:出了什么问题?在哪儿出的问题?前一个问题要求你能精确地说出期望的行为或结果以及实际的行为和结果,后一个问题则要求精确到某一行某一个语句。这样不断追根溯源,直到问题解决。某些并发问题可能要更倚重经验一些。但从来另一方面讲,debug虽然重要,但仅仅debug强不算是好的程序员。应该一次写完就能运行。要减少debug上浪费的时间,个人经验:设计阶段就要想好各个模块、对象间的关系和交互,控制、数据如何流动等重要细节。如果有模式或者最佳实践可用,就用上。测试先行。起码把最重要的单元或模块的测试写出来。从一开始就要考虑各种出错的情况,如I/O错误,外部模块错误,用户误操作等等。我带的本科生中很多新手不喜欢考虑出错的情况,结果导致程序脆弱,极易崩溃。注重代码质量,不要写看着就乱糟糟的代码,不要用asdf这样的命名。对某些语言,比如C++之类,要知道常见的陷阱,遵循一定的规范,比如使用裸指针时要搞清楚所有者,所有者负责分配空间和回收等等。学会一个简单的日志库,或者直接自己手写一个。print大法不错,但我发现很多情况下日志里的其他信息,比如时间、文件名、行号、线程ID等还是很有用的。这时即使是手工定义的一个LOG宏也比printf要方便。
Debug这个问题显然是相当的开放。我相信对于每个程序员都会有自己Debug的具体方法。但是由于Bug这个东西的出现一般相当的诡异,有很多不确定的因素。在找出来之前也不知道具体是什么原因造成的,所以说可能还是没有通用的一套方法来找出Bug。那么我抛个砖,来说说平时我Debug过程中的一些奇技淫巧吧。首先,从Bug产生的可能情况来看,越是复杂的工程,产生Bug的数量就会越多,而且实际情况是,这两个之间的关联是非线性的。所以一定要畏惧代码的复杂度。对于短小的代码而言Bug显然会更容易调通一些。一个非常重要的工作就是进行单元测试。一个非常重要的工作就是进行单元测试。(因为真的很重要,所以我要说两遍)对于每个单一的函数、模块、程序等,依次进行测试。去生成一组范围内的数据(尤其是一些极限情况的数据),保证每个函数、模块、程序都能够在任何情况下返回正确的结果。单元测试的另外一个重要意义是为了防止一种我个人认为Bug中最最恶心的东西。那就是重合Bug。我的意思是,一个程序有多个Bug,他们一起存在在你程序中时,互相发生了奇怪的作用,导致只有某些特定的数据下才会出错。而当你调通其中一个的时候,你所有数据都出错了。你下意识就会以为自己之前的修补出了问题。虽然这种情况听起来非常扯,但是实际上,我经常遇到这样的问题。除了单元测试,一个非常重要的技巧是封装封装再封装。把所有可能需要重复调用的东西都封装成接口、抽象类、方法或者函数。这样所带来的好处是不言而喻的。一旦出了问题,可以一次性修改掉所有的代码。而且调试程序的时候代码非常短,可以很容易确定出出问题的究竟是哪个部分。对于具体代码的调试,我想上面一些答主已经说的很不错了。最常用的还是打印log的方法。当然,一个擅长去使用一个IDE在开发工程的时候也是必要的。它可以更好帮你跟踪每个变量在运行过程中是怎么变化的,当然这些个也是没有固定的方法的。不用去比较哪个IDE好用,哪个IDE不好用。我觉得对于大多数情况而言,并不需要IDE一些奇奇怪怪的特性支持,能断点能显示变量就基本够用了。至于很多同学提到可以进一步采用TestDrivenDevelopment的方法规避Bug。个人认为这在大工程下是很有效的,但是也相当地反人类。我觉得还是要依据工程的规模和自身团队的情况进行选择,或者进行变化。毕竟一个人的命运啊,当然要靠自我奋斗,但也要考虑历史的进程。
首先,debug一定要靠自己呀!原因有四:1.如果是别人给你指出你的程序哪儿错了,你自己不会有任何收获,你下一次依旧会犯同样的错误。2.经过长时间努力Debug获得的错误,印象更深刻。3.Debug能力是面试的考察范围。4.锻炼Debug能力能够提高自己的BugFree的能力。其次,我想介绍一下debug的基本步骤:1.重新读一遍程序。按照自己当初想的思路,走一遍程序,看看程序是不是按照自己的思路在走。(因为很多时候,你写着写着就忘了很多事儿)这种方式是最有效最快速的Debug方式。2.找到一个非常小非常小的可以让你的程序出错的数据。比如空数组,空串,1-5个数的数组,一个字符的字符串。3.在程序的若干位置输出一些中间结果。比如排序之后输出一下,看看是不是真的按照你所想的顺序排序的。这样可以定位到程序出错的部分。4.定位了出错的部分之后,查看自己的程序该部分的逻辑是否有错。在第4步中,如果无法通过肉眼看出错误的部分,就一步步“模拟执行”程序,找出错误。最后,要是debug还是不行怎么办?如果已经Debug了一整天,还是不行,那么兄弟,你可以考虑向他人求助了~能力提高是一个循序渐进的过程,这就给自己定个小目标:做一个debug的小能手~
回答请先登录