Next Previous Contents

2. 信一定要寄到 (The Mail Must Get Through)

自 1993 年起, 我一直擔任一家提供免費上線的小型 ISP 的技術人員,這家 ISP 叫做 County InterLink (CCIL), 位於賓夕凡尼亞州的 West Chester. (我本身參與捐款設立 CCIL, 並寫了我們獨一無二的多人佈告欄軟體 -- 你 可以用 telnet 連線至 locke.ccil.org 一探究竟. 目前它共有三十條線, 可提供近三千位的使用者上網.) 這個工作讓我可以一天二十四小時透過 CCIL 56K 的線路上網. -- 事實上, 我的確非常需要它!

因此我必須常常利用便捷的網際網路電子郵件, 但由於一些複雜的原因, 使得 我家裡的機器 (snark.thyrsus.com) 要以 SLIP 協定連上 CCIL 有所困難. 最後我還是做到了, 但我馬上發覺我必須週期性地以 telnet 連上 lokcke 來檢查我是否有新信件, 這實在是一件煩人的事. 我想要的是: 我的郵件可以 被送到 snark, 而且送達時會通知我, 然後我可以用 snark 上的工具程式來 處理這些郵件.

簡單的 sendmail 轉信功能在這裡幫不上忙, 因為我個人的機器並不是時時 都和網路連結著而且它也沒有固定的網址. 我所需要的程式是這樣的: 它可 以透過 SLIP 連線把我的電子郵件都抓回來並放在我的機器. 我知道有這樣 的程式, 它們大部份都使用一個簡單的網路應用協定叫 POP (Post Office Protocol), 而 locke 的 BSD 作業系統上確定已包含有 POP3 的伺服程式.

我需要一支 POP3 客戶端的程式. 所以我到網路上搜尋之後找到一個. 其實 我找到了三或四支這樣的程式. 我使用了一陣子的 pop-perl, 但是它少了一 個滿重要的特性 -- 就是精巧地處理抓回來信件檔頭附的來源處, 以使收件人 能回覆信件至正確的網址.

這個問題是這樣的: 假設 locke 上有一個叫做 joe 的使用者寄信給我, 而 pop-perl 把信抓回到我的 snark 上, 當我要回給信給 joe 時, 我的送信程式 會傻呼呼地試著把這封回信送給根本就不存在 snark 上的使用者 joe. 所以 我必須動手編輯回信的網址即加上 ``@ccil.org'', 很快地這變成了一件頗痛苦 的事情.

很明顯的這是電腦應該幫我做的, 可是現有的 POP 客戶端程式卻沒有任何一 支知道要這麼做. 這使我們學會了第一課:

[格言 1] 好軟體都是起源於程式發展者要解決切身之痛.

1. Every good work of software starts by scratching a developer's personal itch.

也許這已是眾所皆知 (不是有句著名的諺語叫: ``需要為發明之母'' 嗎?), 但 有多少軟體發展者為了薪水, 把時間都耗在寫他們既不需要也不喜愛的程式上 呢? 然而這樣的事不會發生在 Linux 的世界 -- 這也許可以解釋為什麼由 Linux 社群們發展出來的軟體的平均水準都這麼高.

所以, 我是否該立即如抓狂般地投入寫作一支新的 POP 客戶端的程式來和既有 的一較高下? 並不如你所想的, 我仔細地檢視我手上已握有的 POP 客戶端程式, 看看那一支最符合我的需要, 因為

[格言 2] 優秀的程式師知道要寫程式, 偉大的程式師知道要改寫 (和重覆利用) 程式.

2. Good programmers know what to write. Great ones know what to rewrite (and reuse).

我並非在宣稱我是一個偉大的程式師, 但我願去效法. 偉大的程式師還有一項重 要的特色是老製造著偷懶的辦法, 他們認為人們爭取最好的成績並不是為了努 力的過程, 而是為了最後的結果. 更何況由一個部份可行的解決方法開始總比 什麼都沒有容易得多.

舉例來說, Linus Torvalds http://www.earthspace.net/~esr/faqs/linus 當初寫 Linux 的核心程式時也不是從零開始, 他是由借重 Minix 的 程式和構想開始的 (Minix 是一個像 UNIX 的小型作業系統, 它在 386 機器 上執行), 然而到最後原來屬於 Minix 的碼不是被移出就是被改寫 -- 儘管 如此, Minix 的碼畢竟曾存在於 Linux 中, 並且曾為尚未茁壯的 Linux 提供 一個骨架, 最後終於誕生了 Linux.

為仿效這樣的精神, 我開始找尋一個現有而且寫得有條理的 POP 工具程式, 來 作為我發展新程式的基礎.

在 UNIX 的世界中, 原始程式碼共享的傳統讓我們可以很容易地重覆利用程式碼 , 這也是為什麼 GNU 專案要選擇 UNIX 作為它發展的平台, UNIX 作業系統本身 幾乎沒做什麼保留, Linux 的世界也遵行著這個傳統, 到接近它技術極限的地 步, 它供人運用旳開放性原始碼程式, 有天文數字般地多, 所以在 Linux 已有 的資源中找到一個足夠好的程式要比其他的作業系統容易.

而我也的確找到了, 連我先前的搜尋再加上這一次總共有九個程式候選 -- fetchpop, PopTart, get-mail, gwpop, pimp, pop-perl, popc, popmail 及 upop. 我首先選擇 Seung-Hong Oh 寫的 ``fetchpop'' 作為出發點, 我加入了我 要的 ``重寫郵件檔頭'' 功能, 並且作了多處的改善. 原作者同意將這些納入 fetchpop 的 1.9 版.

幾個星期之後, 我緩緩地讀著 Carl Harris 寫的 ``popclient'' 的原始碼, 並且 發現了一個問題: 雖然 fetchpop 有一些好的初始想法 (如它的伺服程式模式), 但它只能處理 POP3 的協定, 而且它的原始程式只有業餘的水準 (Seung-Hong 是個聰明的程式設計師, 但經驗不夠老道). 而 Carl 寫的程式碼就比較好, 具 相當的職業水準和穩固性, 但他的程式缺乏了許多重要的特色, 如 fetchpop 中 巧妙的實作 (包括我加入的部份).

要換還是不換呢? 假如我選擇換的話, 那麼換到一個較好的發展基礎所要付出的 代價就是要丟掉我已經寫好的程式碼.

事實上我選擇換的動機是為了能支援多種 post-office 的協定, 雖然 POP3 最廣 為人採用, 但它卻不是唯一可用的協定. Fetchpop 和其他同類的程式並不支援 POP2, RPOP, 或 APOP, 而我早先有一個概略的想法 (只是為了有趣): 加入 IMAP http://www.imap.org (Internet Message Access Protocol 最新最強的 post-office 協定) 協定的 支援.

一個更正式的理論讓我覺得換到新的發展基礎是個好主意, 這個理論是早在 Linux 出現前, 我就已經學會了:

[格言 3] ``計畫好如何捨棄一條路吧, 你遲早會想盡辦法這麼做的.'' (引自 Fred Brooks << 人-月 的迷思 >> 一書的第十一章)

3. ``Plan to throw one away; you will, anyhow.'' (Fred Brooks, ``The Mythical Man-Month'', Chapter 11)

否則, 計畫走另一條路吧. 針對一個問題, 在尚未實作出第一個解法前, 你通常並 不真正瞭解這個問題. 也許第二次的時候你才能充分瞭解怎麼做才對, 所以即使 你想做對一件事, 但起碼你要準備從第一次做起.

我告訴我自己: 修改 fetchpop 是第一次. 所以我換到 Carl Harris 的 popclient 繼續發展 (是第二次).

當 1996 年 6 月 25 日我送給 Carl Harris 我第一次對 popclient 所做的修正 後 , 我才曉得他已經對這支程式沒興趣了. 原來的程式碼乏人照料已有一段時間, 還包括一些次要的錯誤. 有許多修正要做, 很快的我們兩人都同意由我接手整個程 式是合理的一件事.

在我不經意間, 這個專案的規模擴大了, 我不再只注意現在的 popclient 要修補 那些次要的部分, 而是要接下維護整個整程式, 在我腦海曾浮現許多主意, 我想這 可以引導我改變 popclient 的主要部分.

在鼓勵分享程式碼的軟體文化下, 一個專案以這樣自然的方式演進. 我表現出:

[格言 4] 抱持正確的態度, 就會發現有趣的問題.

4. If you have the right attitude, interesting problems will find you.

但 Carl Harris 的態度更為重要, 他懂得:

[格言 5] 當你對一個問題不再感興趣時, 你最後的責任就是找位能勝任的接棒人.

5. When you lose interest in a program, your last duty to it is to hand it off to a competent successor.

雖然 Carl 和我沒討論這些, 但我們卻有一個共同的目標就是對這個問題寫出最好 的解法. 現在唯一的問題只剩: 證明我是個可信賴的人, 而我已經做到, 所以他便 欣然地把這支程式交給了我. 我希望這個專案在我手中能變得更好.


Next Previous Contents