2.2 邮件必达
“切斯特互联”(Chester County InterLink,CCIL)位于美国宾夕法尼亚州(Pennsylvania)的西切斯特郡(West Chester),是一家小型的免费互联网服务提供商。1993年以来,作为联合创始人,我曾一直负责CCIL的技术部分,并编写了我们独创的多用户论坛程序——你可以通过telnet连到locke.ccil.org来试试看。时至今日,这个程序通过三十多条线路支持近三千名用户访问。这份工作使我能够使用CCIL的56K线路保持每天24小时连在网络上,当然,这是工作需要!
我已经习惯了使用电子邮件,但每过一会儿就telnet到locke上查一下邮件,是一件比较烦人的事。我很希望邮件能够自动地递送到snark(我家里的机器)上,这样,邮件来的时候就会通知我,然后我就能用本地工具来处理它。
互联网原生的邮件转发协议SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)并不适用,因为它最适用于机器一直在线的情况,而我家里的机器并不总是在线,而且也没有一个静态IP地址。我需要这样一个程序,它可以在我时断时续的拨号上网期间,把我的邮件取到本地。我知道有这种软件,它们大多使用了应用层协议POP(Post Office Protocol,邮局协议)。现在绝大多数常见邮件客户端都支持POP,但在那个年代,我所用的邮件阅读器并不支持。
看来我需要一个POP3客户端。于是我便到网上找了一个(事实上我找到了三四个),使用了一段时间后,我发现它有个明显的缺陷:它不能正确地解析取回邮件的邮箱地址,导致我不能正确回复。
问题是这样的:比如locke上有个叫joe的人给我写信,我把信取到snark上并试图回复时,邮件程序会傻乎乎地想把它发给snark上并不存在的joe。所以我不得不每次把回复邮件地址修改为@ccil.org的样子,这实在有点痛苦。
很明显这种事应该由计算机搞定,但没有任何一个现成的POP客户端能做到这点!这给我们上了第一课:
1.好的软件作品,往往源自于开发者的个人需要。
按说这是显而易见的(正如老话说“需要是发明之母”),但太多的软件开发人员并不需要也不热爱他们正在开发的软件,他们把编程当差事,为的只是拿薪酬。Linux世界里可不是这样——也许这可以解释为什么Linux社区里原创软件的平均质量是如此之高。
那么,我是不是应该立即投入到疯狂的编程中,做出一个全新的POP3客户端和其他程序一较高下?千万不要!我把手头的POP程序看来看去,认真思索“哪个最接近我想要的”,因为:
2.优秀的程序员知道写什么,卓越的程序员知道改写(和重用)什么。
我不敢说自己是卓越的程序员,我只是模仿他们。卓越程序员们有个很重要的特征是“建设性懒惰”,他们知道人们要的是结果而不是勤奋,而从一个部分可行的方案开始,明显要比从零开始容易得多。
以Linus Torvalds为例,他并没有尝试从零开始写Linux,而是以重用Minix(一个用于PC机的迷你型UNIX类操作系统)的代码和理念作为开始,虽然Linux中所有Minix代码最终都被移除或重写,但它在Linux成长初期确实起到了类似脚手架的作用。
基于同样的理念,我试图找到一些代码写得还不错的POP程序,作为我开发的基础。
UNIX世界共享源代码的传统使得代码重用变得很便利(这正是GNU选择UNIX作为基础OS的原因,且不论它对UNIX本身的保留意见),Linux世界则把这个传统发挥到了技术上的极限。相比其他地方,从Linux世界多达数T字节的开放源码中,找到一些他人写的“足够好”的代码要可行得多。
不出意外,连同上次找到的,我一共找到九个备选程序:fetchpop、PopTart、get-mail、gwpop、pimp、pop-perl、popc、popmail和upop。我首先选择了Seung-Hong Oh写的fetchpop。我给程序加上了“邮件头重写”功能,并做了一些其他改进,这些改进被作者接受并在1.9版本中发布。
几周以后,我偶然发现了Carl Harris写的popclient代码,同时带来的是一个难题:尽管fetchpop有一些很好的创意(比如使用后台进程模式),但只能处理POP3协议,代码也略显业余(Seung-Hong Oh在那时是个聪明但缺乏经验的程序员,这两点都看得出来)。Carl Harris的代码要好一些,专业而稳健,但缺乏fetchpop中一些重要而精巧的特性(包括我写的那部分)。
继续完善fecthpop还是转换到popclient?如果转换,我写的那些代码就可惜了,但同时能换来一个更好的开发基础。
一个更实际的转换动机是popclient对多协议的支持。POP3是最常用的邮件服务器协议,但并不是唯一的。fetchpop以及其他备选程序并不支持诸如POP2、RPOP或AROP这些协议,而我还有点想加上对IMAP(Internet Message Access Protocol,互联网消息访问协议,这是最新设计的、功能最强大的邮局协议,http://www.imap.org)的支持,仅仅是为了好玩。
另外,还有一个理论上的原因让我决定转换,这可是早在Linux之前我就学到的:
3.“计划好扔掉一个吧,迟早你会这么做的。”(Fred Brooks,《人月神话》第11章)
或者可以这么说:在你第一次把问题解决的时候,你往往并不了解这个问题,第二次你才可能知道怎么把事情做好。所以,如果你想做对事情,至少要再做一次。 1
好吧,我对自己说,改写fetchpop是我的第一次尝试,现在我可以换了。
1996年6月25日,我把自己对popclient所做的第一批补丁发给Carl Harris,发现他基本已经失去了对popclient的兴趣。由于popclient代码有点陈旧,还有些小bug没有解决,很多地方都值得改进,我和Carl Harris很快达成一致:由我来接手这个程序。
项目在不经意间升级了,我不再是对现有POP客户端做一些小打小闹的补丁工作,而是开始维护整个程序。新的想法不时冒出来,我意识到自己也许可以对程序做些大改动了。
在一个鼓励代码共享的软件文化中,这是一种很自然的项目演化方式。我见证了下面这条:
4.如果你有正确的态度,有趣的事情自然会找到你。
当然,Carl Harris的态度更重要,因为他明白:
5.当你对一个程序不再感兴趣时,你最后的责任就是把它交给一个可以胜任的接棒者。
尽管并没有明确提及,但Carl Harris和我都知道,我们的共同目标是做出最好的解决方案。唯一的问题是我能否证明自己是可靠的,一旦我做到这点,Carl Harris就优雅而利落地把程序交接给我。如果有一天轮到我时,希望我也能交接得这么棒。