Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2.2 使命必达a

1993 年起,我在宾夕法尼亚州西切斯特运营免费接入互联网服务商切斯特县互联(CCIL),全权负责平台技术板块。我是 CCIL 的联合创始人,并编写了我们自研的多用户 BBS 系统软件——你可以通过 telnet 登录 locke.ccil.org 来查看它。如今,它在30条线路上支持着近 3000 名用户。这份工作让我能够通过 CCIL 的 56K 线路全天候接入互联网——实际上,这份工作几乎要求我这么做!

我早已习惯即时互联网邮件带来的便利了。我得频繁用 Telnet 登录 locke 服务器查邮件,实在十分麻烦。我想要的是我的邮件被投递到 snark(我的家用系统)上,这样我就能在邮件到达时收到通知,能用我本地的所有工具来着手处理。

互联网原生的邮件转发协议 SMTP(简单邮件传输协议)并不适用,因为它在机器全时在线时工作得最好,而我的个人电脑并不总是连着互联网,也没有静态 IP 地址。我需要的是一种程序,它能在我的间歇性拨号连接中主动抓取,把邮件拉取过来并在本地投递。我知道这样的东西是存在的,而且大多数使用一种叫做 POP(邮局协议)的简单应用协议。POP 如今已被大多数常见邮件客户端广泛支持,但当时,我正在使用的邮件阅读器并没有内置这个功能。

我需要一个 POP3 客户端。于是我上网找了一个——实际上,我找到了三四个。我用了其中一个一段时间,但它缺少一个在我看来很明显的功能——能够修改拉取邮件的地址头,以便回复功能正常工作。

问题是这样的:假设 locke 上一个叫 joe 的人给我发了邮件。如果我把邮件拉到 snark 然后试图回复,我的邮件程序会兴高采烈地将邮件发送给 snark 上一个不存在的 joe。每次回信都要手动给地址补上@ccil.org后缀,没过多久就让我不胜其烦。

这显然应该是计算机替我做的事情,但现有的 POP 客户端没有一个知道该怎么做!这就引出了第一课:

  1. 所有出色的软件,最初都是为了解决开发者自己遇到的麻烦。

或许这本来就显而易见(“需求是发明之母”早已是格言),但太多软件开发者日复一日地为薪酬而打磨他们既没有需求也没有热爱的程序。但在 Linux 世界里并非如此——这或许可以解释,为什么 Linux 社区出产的软件平均质量如此之高。

那么,我会不会三下五除二,一头扎进新项目开发,去写一个新 POP3 客户端竞品呢?想都别想!我仔细分析了手头的 POP 工具,问自己:“哪个最接近我的需求?”因为:

  1. 普通的程序员清楚要从零开发什么,优秀的程序员懂得该改造、复用什么。

虽然我不敢自称顶尖,但是我会努力效仿顶尖程序员的方法论。顶尖人物的一个重要特质就是会偷懒——只在有建设性的地方投入精力。他们知道,得到 A 的评级不是因为有多努力,而是因为成果;更何况从一个能解决部分问题的原型方案出发,基本上总比从零开始要容易得多。

举个例子,林纳斯・托瓦兹(Linus Torvalds)(http://www.tuxedo.org/˜esr/faqs/linus) 实际上并没有从头开始编写 Linux。相反,他先复用了 Minix(一个面向 IBM PC 兼容机的小型类 Unix 操作系统)的代码和思想。最终所有 Minix 代码要么消失、要么完全重写,但趁它还在,它便仍然是幼年 Linux 的脚手架。

本着同样的精神,我开始寻找现有且代码质量尚可的 POP 工具,作为开发的基础原型。

Unix 社区的源代码共享传统,向来十分拥抱代码复用(这正是 GNU 项目选择 Unix 作为基础操作系统的原因,尽管对该系统本身颇有保留)。Linux 世界几乎将这一传统发挥到了技术极限,它有按 TB 计的开源代码可供获取。因此,花时间寻找改一点就能用的他人成果,在 Linux 社区里更可能有所收获。

对我而言确实如此。加上之前找到的那些,我第二次搜索总共找到了 9 个候选项目:fetchpop、PopTart、get-mail、gwpop、pimp、pop-perl、popc、popmail 和 upop。我最初选定的是 Seung-Hong Oh(音译:吴承洪,后文采用此译)编写的 fetchpop。我把我的邮件头重写功能加入其中,并做了其他一些改进,作者接受了这些改进,并将其合并到了他的 1.9 版本中。

然而,仅仅几周后,我偶然发现了卡尔·哈里斯(Carl Harris)的 popclient 代码,很快发现自己面临一个两难:尽管 fetchpop 有一些不错的原创想法(比如后台守护进程模式),但它只能处理 POP3,而且代码写得相当业余(承洪当时是一位有天赋但经验不足的程序员,这两点都暴露无遗)。卡尔的代码更好,相当专业扎实,但他的程序缺少 fetchpop 几个重要且实现起来相当棘手的功能(包括我自己编写的那几个)。

是继续用 fetchpop,还是换到 popclient?如果换,那我就舍弃已经完成的代码,换取一个更好的开发基础。

一个让我想换项目的实际原因是 popclient 支持多协议。POP3 是最常用的邮局协议(POP,Post Office Protocol),但不是唯一的一种。Fetchpop 和其他竞品都不支持 POP2、RPOP 和 APOP,而我已经有了模糊的设想:也许可以为了好玩增加对 IMAP(互联网消息访问协议,最新设计、功能最强大的邮局协议,http://www.imap.org)的支持。

但我还有一个更理论性的理由,这是我早在 Linux 之前就学到的:

  1. “做好舍弃第一版的准备,无论如何,你最后总会推倒重来。”(弗雷德里克·布鲁克斯(Fred Brooks),《人月神话》第 11 章)

换句话说,你往往在第一次实现某个解决方案之后,才真正理解问题所在。到了第二次,也许你才足够了解,也能把它做对。所以如果你想做对,就要准备好至少重来一次。1

好吧(我对自己说),对 fetchpop 的修改已经是我的第一次尝试了。于是我就换了。

1996 年 6 月 25 日,我把第一组 popclient 补丁发给卡尔·哈里斯后,我发现他基本上在那之前一阵子就已经对 popclient 没什么兴趣了。代码长期无人维护,还积累了一些遗留的小 bug。我还有很多改动要做,于是我俩很快就达成一致:由我来接手这个程序是顺理成章的事。

在我几乎还没察觉的情况下,这个项目就已经升级了:我不再只琢磨给现有的 POP 客户端打些小补丁,而是接手了整个项目的维护,而且我的脑海中正涌现出一些想法——我知道那些想法很可能会带来大改。

在一个鼓励代码共享的软件文化中,这是项目演化的一种自然的方式。我正是在践行这条原则:

  1. 如果你态度端正,有趣的问题自然会找上门来。

但卡尔·哈里斯的态度更为重要。他明白:

  1. 当你不再愿意维护一款程序,你最后的责任就是把它交给一个称职的继任者。

这不需要任何多余的讨论,卡尔和我都知道,我们有一个共同的目标:拿出最好的解决方案。对我们俩来说,唯一的问题就是我能不能证明自己是可靠的接手人选。一旦证明了这一点,他便爽快得体地完成了项目移交。我希望轮到我的时候,我也能做得一样好。

作者注

  1. 在《编程珠玑》(Programing Pearls)中,著名计算机科学随笔作家乔恩·本特利(Jon Bentley)对布鲁克斯的经典论断评论道:“如果你心里打算直接废掉第一版,最后大概率两个版本都得丢掉重做。”这话基本说到点子上了。不管是布鲁克斯还是本特利,他们想表达的重点不只是“你一开始就应该知道初版的方案会走偏”,而是说想清楚正确的思路再从头做,通常比收拾一个烂摊子更有效。

译者注

a. 原文为 The Mail Must Get Through,在美国文化中有深厚渊源,代表“忠诚、勇气和克服万难”。美国著名的英语阅读教材Basic Readers(以及《美国小学英语教材》)中就有一篇题为The Mail Must Go Through的课文,详细讲述了驿马快信(Pony Express)第一个骑手出发的故事,从一个历史故事升华为美国文化中“使命必达、忠于职守”的象征。在本文中 ESR 将常见的‘Go Through’化用为‘Get Through’,更强调穿越技术障碍的过程,呼应正文中作者通过拨号连接收取邮件的技术挑战。