但是,没有技术含量的事情,不代表做起来就不会出错,比如这次的BUG,最初就是由大猫发现的。大猫是搞UI的,也就是传统意义上说的“美术设计”,他专门负责这款播放器外观的设计工作。
下午的时候,他跑过来跟Barry说:“哎?为什么我做的这款皮肤不能正常显示呢?”Barry很自然地嘟囔了一句:“不会吧”,随后又说:“把皮肤包发给我看看”。
大猫和睿儿不太一样,虽然他们都对技术一窍不通。睿儿更倾向于从自身找问题,对程序的信任程度很高。但是大猫刚好相反,他更喜欢从程序层面上挑毛病。比如,他做了一款皮肤,上面有一个按钮不能正常显示,Barry告诉他:“这个按钮的坐标定位在拉伸区域了,如果用户改变窗口大小的话,程序会把这个部的区域自动伸缩,所以按钮的位置也会不对了。应该避免放在这个位置。”如果是睿儿,一定会说:“这样啊,好,我下次一定改!”但是大猫就会说:“那应该在程序里加一个判断,如果按钮在这个区域里了,就把它特殊处理,不让它随便移动,不就行了?”常常会把Barry搞得痛苦的想自杀。
正是因为大猫不懂技术,所谓“无知者无畏”,他经常会提出很多异想天开的“建设性”方案。每次Barry都要向他解释,为什么这样做不行,必须要那样做。大猫常常似懂非懂地翻翻眼皮,立刻又冒出了另一个“建设性”方案:“哦,那要不然这样吧……”这一回,听起来比上一个方案更加异想天开。
Barry仔细检查了大猫制作的皮肤包,发现皮肤本身确实没有问题,但是在软件上不能够正常显示,有几个元素都加载失败了。他立刻变得认真起来,用VC打开工程,开始一步一步的进行调试。对于程序员来说,如果一个问题在同一条件下总是会出现,那么这就不算是一个问题。最怕某些BUG在别人的电脑上出现,到了程序员自己的电脑上就一切正常了,这种BUG才是真正具有威胁性的。好在,这次遇到的不是,因此,Barry很快找到了问题的所在。
原来这是一个和字符编码相关的问题,大猫皮肤包中的描述文件用了Utf8的编码,Windows在存储这种编码的文件的时候,会自动额外加入几个标志性的不可见字符。程序是按照二进制的方式读取描述文件的,所以就会受到这几个不可见字符的干扰,因此出现了错误。Barry想了想,既然这几个是不可见字符,那么在文件的正文中是不可能出现的,况且这几个字符又总是会出现在文件的开头部分,因此可以尝试判断文件的开头有没有这些特殊字符,如果有,简单的丢弃掉就可以了,不会对文件解读产生影响。
做这样的改动很简单,所以Barry很快改好了程序,重新编译运行,问题解决了!Barry并没有放松警惕,他又找了几个从前使用过的不同类型的皮肤进行测试,果然也都能兼容,没有发现问题。Barry轻轻舒了一口气,总算一个BUG又被搞定了。
如果说,这个问题到这里就此结束了的话,那么就算不上我们在前面提到的“棘手”问题了。事实上,Barry还是高兴得早了一点,事情很快就发展到了他没有预料到的情况。
郑头儿把大猫叫道他身边,问道:“怎么你最新做的皮肤不能正常显示呢?”大猫马上说:“哦,我问过Barry了,他说是字符什么什么的问题。”大猫很巧妙地绕开了“BUG”这个词,虽然,他记不得“字符编码”这个术语,但他还是用这种方式来描述。他知道,在郑头面前说程序有BUG,就像抽Barry嘴巴一样。
记得以前有个笑话,说的是某领导去某工厂视察,厂长带着该领导参观他们的生产线,正参观的时候,一台机床因为传动装置过热突然罢工了,还没等领导发问,机灵的厂长马上说道:“哦,这是传动热效应的表现!”领导一愣,紧接着微笑着点了点头。厂长的聪明之处在于,他既没有承认机床出了故障,也没有遮遮掩掩欺骗领导,而是很坦然地说这是一个什么什么样的“表现”。领导听不懂什么传动热效应这样的专业名词,但是作为领导,不能在下属面前显露出无知,既然这是一种“表现”,那也许就是正常现象吧。他当然不知道,厂长的意思是说:“这是一种故障的表现!”
但问题是,郑头儿并不是什么“无知的厂长”,他是这款软件的第一作者,就好比是那台机床的设计师,能不知道什么叫“传动热效应”?所以,郑头儿听了大猫的描述,就一皱眉,紧接着问道:“是软件的问题?”大猫只好不置可否。
郑头儿站起身来,踱步走到Barry身边,看到他还在屏幕上打开的VC窗口里调试着什么,便问道:“那款新皮肤不能正常显示,是什么问题?”他期待着从Barry这里获得更专业的解释。
Barry听见郑头儿的声音从身边传来,不由得有些紧张,连忙停下手中的调试工作,抬起头来。“哦,是字符编码的问题,皮肤里面的配置文件用UTF8保存的,所以文件开头处有BOM,导致解析文件出错。我已经改好了,在解析文件之前将BOM去掉。”Barry尽力想解释得专业一些,他不用担心郑头儿会听不懂“BOM”这个词,相反的,他如果不这么说,可能还会被郑头儿鄙视,这是Barry最不能容忍的。
“为什么会这样呢?我记得,配置文件解析的函数,应该是可以处理不同字符编码的。”郑头儿一边说着,一边看着Barry,语气中带着些许不满意和质疑的成分。这让Barry略微感到有些压抑,他这次并没有马上说话,而是立刻扭向屏幕,在程序中寻找文件解析函数的部分。
郑头儿有些不耐烦地看着他在一堆繁杂的文件中间点来点去,不轻不重地说了一句:“做这么久了,连哪个模块在什么位置还要一个文件挨一个文件地找吗?”
Barry的两颊立刻火烧一般,鼻尖上立刻渗出了汗珠。他感觉到郑头儿的眼睛在盯着他,他不敢抬头,想说点什么回应,又不知道该说什么好,只是加快了鼠标的点击,在大脑中飞快地分析那个函数可能的位置。好在,没过多久,他终于找到了。
他的眼珠迅速地扫描着函数的代码,试图找出和字符编码相关的部分,但这时候,郑头儿已经指着屏幕上的一行代码说:“你看,这里,这个参数,只要传递AUTO进来就行了,函数会自动判断编码然后进行相应处理。”Barry顺着他指的代码看过去,果然看到函数有一个带默认值的参数,从参数声明的名字就能看出来,那是一个指定字符编码的输入参数。
Barry无话可说,郑头儿说的完全正确,不管是从代码的修改代价上来讲,还是从风险程度来讲,郑头儿的方案都绝对是首选,当然这一切都建立在要对源代码非常熟悉的基础上。郑头儿离开之前说了一句:“以后改代码之前先好好看看源代码,别轻易就动手。”这句话让Barry抑郁了很久。
在回家的路上,Barry的脑子里一直盘旋着下午发生的事情。从内心深处讲,他还有点不服气。郑头儿的解决方案虽然好,但那是因为那部分代码是他自己写的,对于Barry来说,他本不知道那个函数本身能够处理不同字符编码的情况。从修改BUG的角度来讲,尽量保持源代码的接口调用方式一直,这个是减少修改副作用的基本原则,Barry认为自己并没有做错。但是,不服气归不服气,毕竟这个问题解决的不是太好,如果在修改代码前仔细的阅读程序的上下文,如果再把那个文件解析的模块好好研究一下,肯定就会发现那个函数有编码识别的功能了。有人说,成功者与失败者之间的区别,并不在于他们处理问题的能力,而是在于他们处理问题的态度。他这么想,又觉得很懊恼,恨自己处理问题太草率了。
再说郑头儿,也真不简单,一个简单的函数就设计的如此到位,居然连字符编码的扩展性支持都想到了。Barry扪心自问,如果是自己来写这个函数,肯定达不到这样的水准。一般来说,程序员与程序员之间,往往都有一点“文人相轻”的意味,在技术上很难从心里真正地佩服另一个人。但是,单老常讲:“钱压奴婢手,艺压当行人”,在公司里,也总会存在让所有人都心服口服的“大牛”。在Barry的公司里,郑头儿就是这样一个“大牛”。据说,他从前是搞个人软件的,在业界也小有名气,后来他的软件被一家大公司看中,以不菲的价格收购,并且把他也招入公司专门负责那个软件的升级和运作。后来,听说他和那个公司的上层有了一些意见上的分歧,最终离开了。后来辗转来到了现在的公司。在公司里,要说技术,Barry认为无人能出其右。这也就是为什么,Barry在郑头儿面前总是会有一种“敬畏”的感觉。他在心里也把郑头儿当作一个目标,希望有一天能够达到甚至超越郑头儿的水平,用他自己的话来说,那时候就可以“纵剑江湖”了。
Barry到家的时候已经是晚上七点半了,骑车出了一身臭汗,他进了家门扔下包,直接就扒了衣服冲进卫生间洗澡去了。晚饭还是没有着落,虹在家的时候,他洗完澡出来就可以直接奔饭桌了,一荤一素一个汤,热腾腾的米饭,那是何等的幸福啊。只是,虹在家的时候,他并没有意识到这幸福的可贵。人都是到失去的时候,才懂得珍惜。
Barry并不是不会做饭,在虹临走之前的一个星期,硬逼着他学了几样简单的小炒。做饭这种技术比起编程来要容易得多,而且Barry发现自己在烹饪方面似乎有与生俱来的悟性,能够触类旁通。在虹走的第三天,他就开始尝试着做了一道连虹也没有做过的肉菜——京酱肉丝,而且大获成功。为这,Barry在电话里向虹好好的吹嘘了一通,但是那道京酱肉丝也基本上成了他绝笔。
做饭和编程序一样,不怕难也不怕苦,就怕没有成就感。辛辛苦苦做了一道京酱肉丝,味道好坏只有自己知道。Barry在电话里向虹描绘得就像自己做了一套满汉全席,虹也给了他高度的赞扬,但是这种赞扬远远比不上她能亲口尝一尝之后露出的一丝微笑。因此,没有坚持几天,Barry就再也没有做饭的动力了。
晚上吃了包方便面,虽然Barry昨天就在心里发誓“明天一定不吃方便面!”吃完,他边收拾残局,一边又再次发誓:“明天一定不吃方便面!”