原 名:Brian's Guide to Solving Any Perl Problem
中 文: Brian 的 Perl 问题之万能指南
作 者:brian d foy
原 文:http://www252.pair.com/comdog/brian's_guide.pod
发 表:2004-07-20
翻 译:klaus
审 校:qiang
出 处:中国 Perl协会 FPC - PerlChina.org
阅读这份指南并保持明智的头脑
我的调试哲学
我相信三件事情:
这不是个人问题
别老想着是你的代码。你可能觉得自己是个艺术家,但实际上就算是经验丰富的大师也会写出很多垃圾。每个人的代码都是垃圾,我的也是你的也是。要学着去喜欢它。当你碰到问题的时候,你应该想:“噢,我写的垃圾代码出了点问题。”这说明你不再去责怪 Perl。不应该变成个人性的问题。
忘记你以前怎么做的。如果不是你做事的方法有点问题,你也不会来读这个。这并不是坏事,只是到了该有点长进的时间。我们都经历过的。
个人责任感
如果你的代码出了问题那仅仅是——你的问题。你应该尽最大的力量自己解决。记住,每个人都有自己的代码,每个人都有自己的问题。自己的作业自己做,在麻烦别人之前先尽自己最大的努力。如果你老老实实地按照这个指南做了所有能做的事之后,依然不能解决问题,那么你已经尽力了,应该找别人来看看。
改变你做事的方法
改正之后不要再犯同样的错误。很可能是你写代码的方法错了,而不是你写的代码错了。改变你以前做事的方法,让生活更容易些。不要指望Perl来习惯你,因为这是不可能的。你要习惯 Perl。它只是种语言,而不是种生活方式。
我的方法
你用strictures编译代码吗?
如果你不用 strictures,请把它打开。Perl 高手们之所以是高手,因为他们使用严格模式,使得他们有更多的时间解决其他问题,学新的东西,以及上载模块倒 CPAN。
你可以使用 strict pragma 在代码中打开 strictures
use strict;
也可以用perl的 -M开关在命令行中打开它:
perl -Mstrict script.pl
你可能会被它搞怒,但是坚持用上它几个礼拜之后,你会写出更好的代码,花更少的时间来检查低级错误,而且可能就不再需要读这个指南了。
什么是warning?
Perl 会对一些有问题的结构给你警告提示。把 warning 打开,让 Perl 来帮你。你可以在第一行用 perl的 -w 开关打开它:
#!/usr/bin/perl -w
也可以在命令行打开warning:
perl -w script.pl
你也可以使用词汇警告,它带有许多有趣的特性。更多的信息参看warnings 的帮助文档。
use warnings;
如果你不明白某个警告的意思,你可以使用 warning 的详细模式,或者在你的代码中使用诊断 pragma:
use diagnostics;
解决第一个问题先!
你从 Perl 中得到警告或者错误信息之后,先解决第一个,然后看Perl是否依旧报出其他错误。因为后续的错误很可能是由于第一个错误衍生而来的。
检查错误信息行号之前的代码!
Perl 在错误已经发生的时候才报错,而不是在此之前。因此当 Perl 报出行号时错误已经发生了,而出错的地方是在这之前。看看错误行号之前的代码和表达式是否有问题。
那个变量值是你想的那样吗?
不要乱猜!在表达式中使用某个值的时候先检查它是否正确。世界上最好的调试器就是 print。
print STDERR "The value is [$value]\n";
我用括号括住 $value 的原因是因为这样我可以看见开头和尾巴上是否有空格或者换行。
如果这个值不是标量,那么我使用 Data::Dumper 来打印这些数据结构。
require Data::Dumper;
print STDERR "The hash is ", Data::Dumper::Dumper( %hash ), "\n";
如果打印出来的结果不是你所期望的,那么移到前面几句,再来!找到这个值最后正确的位置。也可以用 perl -d 开关打开内建的 Perl 调试器。更多信息请参考perldebug。
perl -d script.pl
你也可以使用其他调试器或者开发环境,想 ptkdb(一个基于Tk的图形调试器)或者是 Komodo( ActiveStates 基于 Mozilla 的 Perl IDE)
你用的函数是正确的吗?
我写 perl 程序的时间已经不短了,可我还是几乎每天都要查 perlfunc。有些东西我就是吃不准,而有时候我太缺乏睡眠了以至于没了常识,然后总搞不懂为什么 sprintf() 不打印到屏幕上。
你可以用perldoc命令和它的-f开关来查询某个特定的函数。
perldoc -f function_name
如果你在使用一个模块,查询它的文档,看看你是不是在用正确的方式使用它。你可以用 perldoc 查询它的文档。
perldoc Module::Name
你用的特殊变量是正确的吗?
同样,我经常去查 perlvar。不过,当我发现 Perl 快速参考这本书(The Perl Pocket Reference)更加方便之后,我就很少查 perlvar 了。
你用模块版本正确吗?
有些模块在升级版本的时候会有不少改变。你知道你用的模块是什么版本吗?你可以用一个一行的 perl 语句检查你的模块版本:
perl -MModule::Name -le 'print Module::Name->VERSION';
如果你读的文档不是你机器上的本地文档,而是像 http://www.perldoc.com/ 或者 http://search.cpan.org/ 上的,那你就比较有可能碰到文档版本差异的问题。
你用小脚本测试过了吗?
如果你在尝试新的东西,或者觉得某一小段代码很奇怪,你可以写一个最短的程序运行一下这一个片断。这个方法把所有其他的因素都排除在外。如果测试没有问题,那说明问题可能不在这段代码里面。如果测试结果不对,那你大概就找到了你的问题所在。
你检查环境了吗?
有些东西是依赖环境变量的。你确定你的环境变量都是对的吗?程序运行的时候用到的环境变量是你现在看到的环境变量吗?记住有些 CGI 程序或cron 可能用到的环境变量和 shell 里的不一样,尤其是在不同的机器上的时候。
Perl 将环境变量存储在 %ENV 里 。如果你需要某个环境变量,就算是在测试的时候,也记住先提供一个默认值,如果它原来不存在的话。
如果还有问题,查看你的环境。
require Data::Dumper;
print STDERR Data::Dumper::Dumper( \%ENV );
你试过Google了吗?
其他人也许碰到过和你同样的问题。用 Google Groups(http://groups.google.com/)搜索看看是不是有人在 comp.lang.perl.misc 上发过类似帖子, 没准还能发现其他人给出的解决方法。在新闻组里问问题的人和回答问题的人的差别在于,他们使用Google Groups 的能力高底不同。
你对程序做过性能测试吗?
如果你想知道是哪些部分让你的程序变慢,试过性能测试吗?可以让 Devel::SmallProf 帮你做这件事。它可以计算 perl 执行每一行代码的次数和花费的时间,然后打印一份漂亮的报告。
到底是那个测试没通过?
如果你有一套测试,到底是哪个测试失败了呢?你可以很容易的找到错误所在,因为每个小测试只执行一小段代码。
如果你没有,为什么不写一个呢?如果你的代码很短很短,或者只是一个一次性的程序,那我不会建议你专门写一套测试出来。但如果不是这样的情况,那写一些测试代码是很有帮助的。Test::Harness 让这件事变得太容易了,以至于你都找不到理由不做。如果你说你没时间,那大概是因为你不用测试而在脚本除错上浪费了太多时间。
你和小熊说话了吗?
把你的问题大声说出来。把它变成语言。有几年我很愉快地和一个很优秀的程序员一起工作,他几乎能解决任何问题。当我被什么问题堵住的时候,我总去请教他,跟他解释我的问题。几乎每次都是这样的情况:我说不到第三句,就停下来,说:“噢我明白了,没问题了。”他每次也都是这样。
你可能需要做太多次这样的事情,所以我推荐拿一个长毛绒玩具做为你的Perl 临床诊断家,这样你就不会惹怒你的同事了。我的桌子旁边就有一只小熊,我每次都把我的问题解释给他听。每次当我自言自语的时候,我女朋友跟本都不会注意,她习惯了。
这问题在纸上看起来有点不一样了吗?
因为你老是看着电脑屏幕,所以说不定一种新的媒介可以让你从新的角度看这个问题。把程序打印到纸上试试看。
你看 Jon Stewart 的节目吗?
说真的。可能你不太喜欢 Jon Stewart,那换一个其他的。休息一下,停一会,让你的大脑放松放松。当你回来的时候说不定问题忽然就很容易解决了。
你认真检查自己了吗?
如果到了这一步你还没有解决的话,这说不定是个心理问题。可能你对某段代码有特别的感情,所以不想改掉它。说不定你觉得只有你是对的,别人都错了。当你有这种感觉的时候,你该考虑一下问题的来源 -- 你自己。不要过于自负而不愿认清自己的错误。
作者 brian d foy, <bdfoy@cpan.org>
COPYRIGHT Copyright 2002, Perl Documentation Project, All Rights Reserved