这一篇是Mark Pilgrim在2004/2/18写的Beware of strangers中译心得版,Mark Pilgrim现在在Google公司服务,看起来Google好像很喜欢用Python,所以可以好好读一下这篇文章。
Universal Feed Parser 3.0 beta 18已经过时了,假如可以的话就用libxml2,Libxml2使用libiconv 来做大型的字元编码转换,包括中文,日文跟韩文等的编码,其结果就是Universal Feed Parser会变得更普遍。
用libxml2来写程式就像是异国的陌生人给你的一个扣人心弦的拥抱那样,它似乎有可能满足您的最疯狂的梦想,但事好像在你的脑袋某个地方有个挥之不去的声音警告你,你将糟糕地受骗上当。
Libxml2很快,我的意思是疯狂的快,没有别人可以接近它,它超级的快并且超级的符合它所宣称支援所有的规格,它越来越快的同时,功能也越来越多,所以你只要知道在某个地方,有些人在出卖他们自己的灵魂,而你只会希望那不会是你。
这里有一个真实故事:
对于Universal Feed Parser我有一个庞大而且越来越大的单元测试集,俺在很多种平台和条件下执行:Windows、OS X、Debian GNU/Linux、Python 2.1、Python 2.2、Python 2.3、Python的PyXML、Python的libxml2、Python的XML内建解析器,测试的架构已经很复杂,现在所要做的事情之一就是示范一个本地的HTTP伺服器来测试HTTP层跟XML层的相互影响(像是字元编码),HTTP伺服器检查自己的feed测试来拉出包含回应的自订HTTP表头的列表,它比我想的到的还要可怕。
今晚早些时候,我整合了libxml2支援, 当我用Windows下Python 2.3的libxml2 beta 18版跑了整套的单元测试,一个测试失败了,它是获取透过测试架构的HTTP伺服器的路由的一个测试,这失败使它得很困难并且大大地增加了造成的问题比要测试的程式码更多的事情。
拿掉libxml2,所有的测试就会通过,放回libxml2,相同的测试就会失败,真是奇怪。
开启my _debug旗标再重试那一个测试,它会印出一堆东西到stderr然后就… 通过了,关掉libxml2,第二次再回去试,难以置信的可以通过,关掉侦错,重新执行那个测试,它还是可以通过,在它自己执行的时候这测试一直可以通过。
OK.测试的问题在大概#1100的某些地方,超过了2000个左右的测试,执行测试的前半部粉,他们通过了,就跟之前的一样,执行测试的第二部份,他们全通过了,包括之前失败的那一个,将所有的测试合起来执行∶就失败了,关掉libxml2∶所有的测试都可以过,很诡异吧!
花时间来深入挖掘,它到底是哪里错误?它不只是失败;它实际上是挂了一会儿,然后失败,所有的测试通常会在一秒钟之内通过或失败;在我用了四年多的笔电上,我可以用23秒执行2000个测试,除了这一个,它挂了 10秒钟,然后失败,呣,10秒钟,feed解析器提出了一个10秒钟的网路逾时,增加逾时值,瞧,现在它挂了20秒,然后失败,我自订的HTTP伺服器没有回应,但是,只有在一个测试上,只有当我使用libxml2,增加了这困扰的声音。
记住我的HTTP伺服器没有呼叫libxml2,它只能从磁碟读取档案,或一个或两个正规表示式的比对,然后印出原始资料,libxml2后来要晚一点才放进来。
是再次打开 _debug旗标的时候了,为了避免自己迷失在雪片般的废话中,我增加了程式码假如档案名称跟问题中的测试匹配就设定_debug = 1,重跑所有的测试并关掉libxml2作为控制,所有的测试通过,而且我抓了一个测试的侦错资讯,太棒了,开启libxml2,重跑,然后… 所有的测试通过。
仔细检查程式码;除了print叙述外从来就不会有_debug == 1的情形会发生,这个测试会在正常的情况下失败,但是当你侦错的时候却可以通过,真是诡异,奇怪吧!
我很内疚的决定了移掉问题中的测试以及beta 18版的rm, cvs remove, cvs commit,希望没有人会通知,嘿,这是测试版说,移掉侦错码,重跑整套的测试,所有的测试会通过… 除了测试现在是在我刚移掉那段程式码的相同位置(#1100)。
OK,这一定是潜伏在测试架构中的很难找出的错误,(但是如果是这样,为什么libxml2会这样不同呢?问问这恼人的声音
), HTTP伺服器是设定来服务一定数量的请求跟自我中断,或许我有一个离一误差(off-by-1 error)而且它会在服务最后一个测试前中断,或者可能是没有做好初始化,然后在第一个相关的HTTP测试时失败,刺破了HTTP-相关测试的名单;没有一个假设是对的,这个测试过去在#1101的时候可以通过,现在是在#1100的时候失败,而且它跟先前我删去地方的错误是一样的,(很明确的,我觉得非常非常的内疚),不知何故,也不知哪个地方,在之间几百个请求中libxml2会让我的http伺服器失败那么一次。
再一次开启 _debug = 1 的程式码重跑,注解这个真错得程式码重跑,突然地又全过了,仔细检查;是的,libxml2是启用的,不,这不是我的幻觉,再重跑一次,全过,重开机,全过,我有做什么不同的事吗?我仔细的搜寻翻找,最后我看到了:我留了一个全域的_debug宣告没有注解起来,把它注解起来;就错误,移掉注解,就又通过。
请注意只是想说在函式内的全域的_debug应该一点都不会有影响才对,假如你从没在函式内设定_debug的话,它就像你从来没有实行过的威胁一样,这个程式码就像海中的碎片一样,然而它就是这样:把它注解,失败,宣告,成功,开启libxml2,失败,关掉libxml2,成功。
这个故事告诉我们:libxml2会导致无关的子系统失败,除非你威胁它要进行侦错。
Postscript: 我决定在这个警告下释放它,但是之后我发现在Python 2.1下有一个不相干的错误(而且不难理解,在修正了之后重跑测试,现在我已经不能再重新产生我所提到的错误了,我不断的设定全域的_debug 跟 _debug = 1 以及开关libxml2数次以尝试把这个非常错误的行为带回,都无济于事。
我发誓这曾发生过,这不是我的幻觉,但是我承认我不能证明给你看,你只能听我说的话,在这时候,我的所有测试都可以通过,所以我要今晚停止写程式并且在其他事情发生前释放这个讨厌的东西,使用但请自担风险,并提防陌生人。
这篇看完之后,真是心有戚戚焉,常常碰到这种诡异的事,可是又无解,只好放手不管,把它交给神,过些时日,可能就不会有问题了,但是还是对自己的程式技术没有长进,唉!真是辛苦的工作!
2 則留言
Comments are closed.