自1993年起,我就在賓州西切斯特的一家提供免費網絡服務的小公司CCIL(Chester County InterLink)負責技術工作。我協同建立了公司并編寫了一個專用的多使用者論壇程式——你可以通過telnet連接配接locke.ccil.org一探究竟。如今它在三十條線路上支援着近三千名使用者。這使我可以每天二十四小時的通過CCIL的56K專線上網——其實,這是工作需要。
我已經慣于使用網絡郵件了,但不時地登入locke檢查郵件實在很煩人。我所希望的是有辦法能将郵件轉送到我家的機器(snark)上,并在到達的時候通知我,而且可以用本地工具進行處理。
網際網路預設的郵件傳輸協定SMTP顯然不能滿足我的要求,STMP是為全時線上的機器設計的,而我家的機器不可能全天線上——況且它也沒有一個固定的IP。我需要一個程式,讓我能在撥号之後連結到伺服器上把郵件下載下傳到本地。我知道有這種工具存在,它們大都使用一種稱為POP的簡單協定,現在常用的郵件用戶端軟體都支援這個協定,但那時,我的郵件閱讀軟體并不支援它。
我在網上找到了三四個這樣的POP3用戶端軟體。其中一個我用了一段時間,可是他明顯缺少一個功能:抽取正确的郵件位址。
事情是這樣的,如果locke上一個叫喬的人發給我一封郵件,我将其下載下傳到snark上。可是在回複的時候我的郵件程式會高高興興的把信投寄給一個在snark上并不存在的喬。手工修正位址是件痛苦的事。
顯然這是一件應該由電腦來完成的事情,可是沒有一個現存的POP軟體知道如何解決。這給我們上了第一課:
1.好軟體都源自解決開發者的切身之痛。
Every good work of software starts by scratching a developer's personal itch.
或許這是衆所周知的(不是有句名諺叫做“需要是發明之母”嗎?),可是有那麼多軟體開發者為了薪水把時間都消耗在他們及不喜歡又不需要的程式上了。然而這卻不會發生在Linux世界,或許這就是Linux社群産品平均品質很高的原因吧?
那麼我是否應該瘋狂的投入戰鬥,編寫一套新的POP軟體來和它們一較高下呢?打死都不幹!相反,我仔細地檢視我手中的東西,看看哪個最接近需求。因為:
2.優秀的程式員知道要寫什麼,而偉大的程式員知道要改寫(和重用)什麼。
Good programmers know what to write. Great ones know what to rewrite (and reuse).
我不敢自诩偉大,但是我努力效法那些偉大的程式員。他們都有一個重要的特點——建設性的懶惰,因為我們要的是結果而不是過程。從一個優質的部分接手總比你白手起家要容易的多。
以李納斯為例,他并沒有從零開始編寫Linux。相反他借重了Minix的代碼和理念。(Minix是一個用于個人電腦的小型類Unix作業系統)雖然Minix的全部代碼最終被全部摘除或重寫了,但是它畢竟為Linux充當了學步車。
出于同樣的考慮,我開始尋找一個現存的有最有條理的POP程式來作為開發基礎。
Unix世界共享源代碼的傳統讓我們很容易的對它們并重新加以利用。(這也是為什麼盡管GNU對Unix成見很深,卻依然采用Unix為基礎開發作業系統的原因)而Linux世界更是把這種傳統發揮到了技術的極限。在浩如煙海的Linux開放代碼中花點時間來尋找一個不錯的程式,總比去别處要強的多。
加上我之前用到的,第二次的搜尋讓我有了九個候選對象:fetchpop、PopTart、get-mail、gwpop、pimp、pop-perl、popc、popmail和upop。首先選用的是肖恩[1]的fetchpop,我對其做了一些改動并将改寫郵件位址的功能加了進去。後來他把這些改動加入到了自己的1.9版本中。
幾周之後,我偶然接觸到了卡爾·哈裡斯的popclient代碼時,問題出現了。盡管fetchpop有那麼多優秀的原創功能(比如他的背景程式),但是卻隻能支援POP3協定,而且代碼不夠老練(肖恩很聰明,但是缺少經驗)。卡爾的代碼則更好,專業而穩固。但是卻缺少很多重要的功能——那些fetchpop中的妙作(包括我加入的部分)。
是繼續使用fetchpop還是改用popclinent?如果轉換的話,就意味着我不得不放棄已經完成的代碼來換取一個更好的開發基礎。
一個實際的轉換動機是去支援更多協定。POP3使用最廣,卻不是唯一。Fetchpop和那個競争對手同樣不支援POP2、RPOP和APOP。出于好玩,我那時已經有了在其中加入IMAP(最新設計的,最強大的POP協定)的模糊想法。
其實我還有一個更正式的理由支援我更換軟體,這是我在玩Linux之前就學到的:
3.“為舍棄而計劃,無論如何,你都要這樣做。”(弗雷德裡克·布魯克斯,《人月神話》第十一章,)[2]
“Plan to throw one away; you will, anyhow.” (Fred Brooks, The Mythical Man-Month, Chapter 11)
換言之,當你開始嘗試解決一個問題的之後,你通常并不知道症結所在。再次着手,或許能夠遊刃有餘。是以想把事情做好,你得準備“至少重來一次”。【注】
好吧,(我對自己說)對fetchpop的修改就算是我的第一次吧。于是,放棄了它。
1996年6月25日,我給卡爾寄去了第一批程式更新檔。才發現他對這個程式基本失去了興趣。代碼已經乏人照料很久了,小錯誤流連不去,有很多改動要做。我們一拍即合,由我接手。
不經意間,工作的規模擴大了。我不再隻是真對一個POP用戶端進行修補,而是要負責維護整個程式。一些可能會引發變革的想法在我腦海中浮現。
在鼓勵代碼共享的軟體文化裡,這樣的演進方式是自然而然的。我隻是将這些原理付諸實踐:
4.隻要你态度正确,有趣的問題就會找上門來。
If you have the right attitude, interesting problems will find you.
而卡爾的态度更加重要,他懂得:
5.對一個項目失去興趣的時候,你的最後責任就是找一個稱職的接班人。
When you lose interest in a program, your last duty to it is to hand it off to a competent successor.
為了創造一個最佳的解決方案,我和卡爾不謀而合。唯一的問題是,我是否能證明我的能力。一旦我做到了,卡爾便優雅而迅速的交托給我。希望有一天輪到我這麼做的時候,我能同樣的出色。
注:
著名的計算機學家喬·本特利(Jon Bentley)在其著作《程式設計珠玑》(Programing Pearls)對其做了如下評注:“如果你舍棄了一個,你還會舍棄第二個”。他的話完全正确,布魯克斯和本特利指出:不要期望一蹴而就,以一個好主意重頭來過通常要比梳理一團亂麻要好的多。
譯者按:
1.肖恩,Sean Oh,fetchpop的作者,書中出現的名稱是Seung-Hong Oh。Sean是其英文名。有譯者将其音譯作“歐松宏”,我認為這個譯音有失精當。因為Oh Seung Hong這三個拼寫在韓英互譯時是很常見的。與其對應的韓文大緻是“오승홍”,譯成漢語則大緻是“吳承弘”。在沒有辦法聯系到作者本人的情況下,為了行文不出差錯,我選用了其英文名。
2.The Mythical Man-Month,Frederick P. Brooks。《人月神話》,作者弗雷德裡克·布魯克斯。計算機學家,被稱作“IBM 360之父”,曾獲得圖靈獎和美國國家技術獎——兩個計算機界舉足輕重的獎項。《人月神話》是其随筆集,其在書中對繁複的工程管理做了洞見的觀察。在第十一章《未雨綢缪》(Plan to Throw One Away)中其提出了舍棄型原型的概念。本文引言是強調“為舍棄而計劃”,“one”用來指代一個計劃或者原型,我認為不能直接譯為“一個”是以用了代詞“它”放寬其概念。