大教堂和市集

大教堂和市集
 
Eric Raymond
HansB翻譯

--------------------------------------------------------------------------------

一. 大教堂和市集


  Linux的影響是非常巨大的。甚至在5年以前,有誰能夠想象一個世界級的操作系統能夠僅僅用細細的Internet連接起來的散佈在全球的幾千個開發人員有以業餘時間來創造呢?

  我當然不會這麼想。在1993年早期我開始注意Linux時,我已經參與Unix和自由軟件開發達十年之久了。我是八十年代中期GNU最早的幾個參與者之一。我已經在網上發佈了大量的自由軟件,開發和協助開發了幾個至今仍在廣泛使用的程序(Nethack,Emacs VC和GND模式,xlife等等)。我想我知道該怎樣做。


  Linux推翻了許多我認爲自己明白的事情。我已經宣揚小工具、快速原型和演進式開發的Unix福音多年了。但是我也相信某些重要的複雜的事情需要更集中化的,嚴密的方法。我相信多數重要的軟件(操作系統和象Emacs一樣的真正大型的工具)需要向建造大教堂一樣來開發,需要一羣於世隔絕的奇才的細心工作,在成功之前沒有beta版的發佈。
Linus Torvalds的開發風格(儘早盡多的發佈,委託所有可以委託的事,對所有的改動和融合開放)令人驚奇的降臨了。這裏沒有安靜的、虔誠的大教堂的建造工作——相反,Linux團體看起來像一個巨大的有各種不同議程和方法的亂哄哄的集市(Linux歸檔站點接受任何人的建議和作品,並聰明的加以管理),一個一致而穩定的系統就象奇蹟一般從這個集市中產生了。


  這種設計風格確實能工作,並且工作得很好,這個事實確實是一個衝擊。在我的研究過程中,我不僅在單個工程中努力工作,而且試圖理解爲什麼Linux世界不僅沒有在一片混亂中分崩離析,反而以大教堂建造者們不可想象的速度變得越來越強大。


  到了1996年中,我想我開始理解了。我有一個極好的測試我的理論的機會,以一個自由軟件計劃的形式,我有意識的是用了市集風格。我這樣做了,並取得了很大的成功。


  在本文的餘下部分,我將講述這個計劃的故事,我用它來明確一些自由軟件高效開發的格言。並不是所有這些都是從Linux世界中學到的,但我們將看到Linux世界給予了它們一個什麼樣的位置。如果我是正確的,它們將使你理解是什麼使Linux團體成爲好軟件的源泉,幫助你變得更加高效。


二. 郵件必須得通過


  1993年以前我在一個小的免費訪問的名爲Chester County InterLink的ISP的做技術工作,它位於Pennsylvania的West Chester。(我協助建立了CCIL,並寫了我們獨特的多用戶BBS系統——你可以telnet到locke.ccil.org來檢測一下。今天它在十九條線上支持三千的用戶)。這個工作使我可以一天二十四小時通過CCIL的56K專線連在網上,實際上,它要求我怎麼做!


  所以,我對Internet email很熟悉。因爲複雜的原因,很難在我家裏的機器(snark.thyrsus.com)和CCIL之間用SLIP工作。最後我終於成功了,但我發現不得不時常telnet到locke來檢查我的郵件,這真是太煩了。我所需要的是我的郵件發送到snark,這樣biff(1)會在它到達時通知我。


  簡單地sendmail的轉送功能是不夠的,因爲snark並不是總在網上而且沒有一個靜態地址。我需要一個程序通過我的SLIP連接把我的本地發送的郵件拉過來。我知道這種東西是存在的,它們大多使用一個簡單的協議POP(Post Office Protocol)。而且,locke的BSD/OS操作系統已經自帶了一個POP3服務器。


  我需要一個POP3客戶。所以我到網上去找到了一個。實際上,我發現了三、四個。我用了一會pop-perl,但它卻少一個明顯的特徵:抽取收到的郵件的地址以便正確回覆。


  問題是這樣的:假設locke上一個叫“joe”的人向我發了一封郵件。如果我把它取到snark上準備回覆時,我的郵件程序會很高興地把它發送給一個不存在的snark上的“joe”。手工的在地址上加上“@ccil.org”變成了一個嚴酷的痛苦。


  這顯然應是計算機替我做的事。(實際上,依據RFC1123的5.2.18節,sendmail應該做這件事)。但是沒有一個現存的POP客戶知道怎樣做!於是這就給我們上了第一課:

  1.每個好的軟件工作都開始於搔到了開發者本人的癢處。

  也許這應該是顯而易見的(“需要是發明之母”長久以來就被證明是正確的),但是軟件開發人員常常把他們的精力放在它們既不需要也不喜歡的程序,但在Linux世界中卻不是這樣——這解釋了爲什麼從Linux團體中產生的軟件質量都如此之高。


  那麼,我是否立即投入瘋狂的工作中,要編出一個新的POP3客戶與現存的那些競爭呢?纔不是哪!我仔細考察了手頭上的POP工具,問自己“那一個最接近我的需要?”因爲:
  2.好程序員知道該寫什麼,偉大的程序員知道該重寫(和重用)什麼。


  我並沒有聲稱自己是一個偉大的程序員,可是我試着效仿他們。偉大程序員的一個重要特點是建設性的懶惰。他們知道你是因爲成績而不是努力得到獎賞,而且從一個好的實際的解決方案開始總是要比從頭幹起容易。


  例如,Linux並不是從頭開始寫Linux的。相反的它從重用Minix(一個386機型上的類似Unix的微型操作系統)的代碼和思想入手。最後所有的Minix代碼都消失或被徹底的重寫了,但是當它們在的時候它爲最終成爲Linux的雛形做了鋪墊。


  秉承同樣的精神,我去尋找良好編碼的現成的POP工具,用來作爲基礎。


  Unix世界中的代碼共享傳統一直對代碼重用很友好(這正是爲什麼GNU計劃不管Unix本身有多麼保守而選取它作爲基礎操作系統的原因)。Linux世界把這個傳統推向技術極限:它有幾個T字節的源代碼可以用。所以在Linux世界中花時間尋找其他幾乎足夠好的東西,會比在別處帶來更好的結果。


  這也適合我。加上我先前發現的,第二次尋找找到了9個候選者——fetchPOP,PopTart,get-mail,gwpop,pimp,pop-perl,popc,popmail 和 upop)。我首先選定的是“fetchpop”。我加入了頭標重寫功能,並且做了一些被作者加入他的1.9版中的改進。


  但是幾個星期之後,我偶然發現了Carl Harris寫的“popclient”的代碼,然後發現有個問題,雖然fetchpop有一些好的原始思想(比如它的守護進程模式),它只能處理pop3,而且編碼的水平相當業餘(Seung-Hong是個很聰明但是經驗不足的程序員),Carl的代碼更好一些,相當專業和穩固,但他的程序缺少幾個重要的相當容易實現的fetchpop的特徵(包括我自己寫的那些)。


  繼續呢還是換一個? 如果換一個的話,作爲得到一個更好開發基礎的代價,我就要扔掉我已經有的那些代碼。


  換一個的一個實際的動機是支持多協議,pop3是用的最廣的郵局協議,但並非唯一一個,Fetchpop和其餘幾個沒有實現POP2.RPOP,或者APOP,而且我還有一個爲了興趣加入IMAP(Internet Message Access Protocol,最近設計的最強大的郵局協議)的模糊想法。


  但是我有一個更加理論化的原因認爲換一下會是一個好主意,這是我在Linux很久以前學到的:

  3.“計劃好拋棄,無論如何,你會的”(Fred Brooks,《神祕的人月》第11章)


  或者換句話說,你常常在第一次實現一個解決方案之後才能理解問題所在,第二次你也許才足夠清楚怎樣做好它,因此如果你想做好,準備好推翻重來至少一次。


  好吧(我告訴自己),對fetchpop的嘗試是我第一次的嘗試,因此我換了一下。


  當我在1996年6月25日把我第一套popclient的補丁程序寄給Carl Harris之後,我發現一段時間以前他已經對popclient基本上失去了興趣,這些代碼有些陳舊,有一些次要的錯誤,我有許多修改要做,我們很快達成一致,我來接手這個程序。不知不覺的,這個計劃擴大了,再也不是我原先打算的在已有的pop客戶上加幾個次要的補丁而已了,我得維護整個的工程,而且我腦袋裏涌動着一些念頭要引起一個大的變化。


  在一個鼓勵代碼共享的軟件文化裏,這是一個工程進化的自然道路,我要指出:

  4. 如果你有正確的態度,有趣的問題會找上你的,但是Carl Harris的態度甚至更加重要,他理解:

  5.當你對一個程序失去興趣時,你最後的責任就是把它傳給一個能幹的後繼者。


  甚至沒有商量,Carl和我知道我們有一個共同目標就是找到最好的解決方案,對我們來說唯一的問題是我能否證明我有一雙堅強的手,他優雅而快速的寫出了程序,我希望輪到我時我也能做到。

三. 擁有用戶的重要性


  於是我繼承了popclient,同樣重要的是,我繼承了popclient的用戶基礎,用戶是你所擁有的極好的東西,不僅僅是因爲他們顯示了你正在滿足需要,你做了正確的事情,如果加以適當的培養,他們可以成爲合作開發者。


  Unix傳統另一有力之處是許多用戶都是黑客,因爲源優碼是公開的,他們可以成爲高效的黑客,這一點在Linux世界中也被推向了令人高興的極致,這對縮短調試時間是極端重要的,在一點鼓勵之下,你的用戶會診斷問題,提出修訂建議,幫你以遠比你期望快得多的速度的改進代碼。


  6. 把用戶當做協作開發者是快速改進代碼和高效調試的無可爭辯的方式。


  這種效果的力量很容易被低估,實際上,幾乎所有我們自由軟件世界中的人都強烈低估了用戶可以多麼有效地對付系統複雜性,直到Linus讓我們看到了這一點。


  實際上,我認爲Linus最聰明最了不起的工作不是創建了Linux內核本身,而是發明了Linux開發模式,當我有一次當着他的面表達這種觀點時,他微笑了一下,重複了一句他經常說的話:“我基本上是一個懶惰的人,依靠他人的工作來獲取成績。”象狐狸一樣懶惰,或者如Robert Heinlein所說,太懶了而不會失敗。


  回顧起來,在GNU Emacs Lisp庫和Lisp代碼集中可以看到Linux方法的成功,與Emacs的C內核和許多其他FSF的工具相比,Lisp代碼庫的演化是流動性的和用戶驅動的,思想和原型在達到最終的穩定形式之前往往要重寫三或四次,而且經常利用Internet的鬆散合作。


  實際上,我自己在fetchmail之前最成功的作品要算Emacs VC模式,它是三個其他的人通過電子郵件進行的類似Linux的合作,至今我只見過其中一個人(Richard Stallman),它是SCCS、RCS和後來的CVS的前端,爲Emacs提供“one-touch”版本控制操作,它是從一個微型的、粗糙的別人寫好的sccs.el模式開始演化的,VC開發的成功不像Emacs本身,而是因爲Emacs Lisp代碼可以很快的通過發佈/測試/改進的過程。


  (FSF的試圖把代碼放入GPL之下的策略有一個未曾預料到的副作用,它讓FSF難以採取市集模式,因爲他們認爲每個想貢獻二十行以上代碼的人都必須得到一個授權,以使受到GPL的代碼免受版權法的侵擾,具有BSD和MITX協會的授權的用戶不會有這個問題,因爲他們並不試圖保留那些會使人可能受到質詢的權力)。


四. 早發佈、常發佈


  儘量早儘量頻繁的發佈是Linux開發模式的一個重要部分,多數開發人員(包括我)過去都相信這對大型工程來說是個不好的策略,因爲早期版本都是些充滿錯誤的版本,而你不想耗光用戶的耐心。

  這種信仰強化了建造大教堂開發方式的必要性,如果目標是讓用戶儘可能少的見到錯誤,那你怎能不會僅僅每六個月發佈一次(或更不經常),而且在發佈之間象一隻狗一樣辛勤“捉蟲”呢? Emacs C內核就是以這種方式開發的,Lisp庫,實際上卻相反,因爲有一些有FSF控制之外的Lisp庫,在那裏你可以獨立於Emacs發佈週期地找尋新的和開發代碼版本。


  這其中最重要的是Ohio州的elisp庫,預示了今天的巨大的Linux庫的許多特徵的精神,但是我們很少真正仔細考慮我們在做什麼,或者這個庫的存在指出了FSF建造教堂式開發模式的什麼問題,1992年我曾經做了一次嚴肅的嘗試,想把Ohio的大量代碼正式合併到Emacs的官方Lisp庫中,結果我陷入了政治鬥爭中,徹底失敗了。


  但是一年之後,在Linux廣泛應用之後,很清楚,一些不同的更加健康的東西誕生了,Linus的開發模式正好與建造教堂方式相反,Sunsite和tsx-11的庫開始成長,推動了許多發佈。所有這些都是聞所未聞的頻繁的內核系統的發佈所推動的。


  Linus以所有實際可能的方式把它的用戶作爲協作開發人員。


  7. 早發佈、常發佈、聽取客戶的建議

  Linus的創新並不是這個(這在Unix世界中是一個長期傳統),而是把它擴展到和他所開發的東西的複雜程度相匹配的地步,在早期一天一次發佈對他來說都不是罕見的!而且因爲他培育了他的協作開發者基礎,比其他任何人更努力地充分利用了Internet進行合作,所以這確實能行。


  但是它是怎樣進行的呢?它是我能模仿的嗎?還是這依賴於Linus的獨特天才?


  我不這樣想,我承認Linus是一個極好的黑客(我們有多少人能夠做出一個完整的高質量的操作系統內核?),但是Linux並不是一個令人敬畏的概念上的飛躍,Linus不是(至少還不曾是)象Richard stallman或James Gosling一樣的創新天才,在我看來,Linus更象一個工程天才,具有避免錯誤和開發失敗的第六感覺,掌握了發現從A點到B點代價最小的路徑的決竅,確實,Linux的整個設計受益於這個特質,並反映出Linus的本質上保守和簡化設計的方法。


  如果快速的發佈和充分利用Internet不是偶然而是Linus的對代價最小的路徑的洞察力的工程天才的內在部分,那麼他極大增強了什麼?他創建了什麼樣的方法?


  問題回答了它自己,Linus保持他的黑客用戶經常受到激勵和獎賞:被行動的自我滿足的希望所激勵,而獎賞則是經常(甚至每天)都看到工作在進步。


  Linus直接瞄準了爭取最多的投入調試和開發的人時,甚至冒代碼不穩定和一旦有非常棘手的錯誤而失去用戶基礎的險,Linus似乎相信下面這個:

  8. 如果有一個足夠大的beta測試人員和協作開發人員的基礎,幾乎所有的問題都可以被快速的找出並被一些人糾正。


  或者更不正式的講:“如果有足夠多的眼睛,所有的錯誤都是淺顯的”(羣衆的眼睛是雪亮的),我把這稱爲“Linus定律”。


  我最初的表述是每個問題“對某些人是透明的”,Linus反對說,理解和修訂問題的那個人不一定非是甚至往往不是首先發現它的人,“某個人發現了問題”,他說,“另一個理解它,我認爲發現它是個更大的挑戰”,但是要點是所有事都趨向於迅速發生。


  我認爲這是建造教堂和集市模式的核心區別,在建造教堂模式的編程模式看來,錯誤和編程問題是狡猾的、陰險的、隱藏很深的現象,花費幾個月的仔細檢查,也不能給你多大確保把它們都挑出來的信心,因此很長的發佈週期,和在長期等待之後並沒有得到完美的版本發佈所引起的失望都是不可避免的。


  以市集模式觀點來看,在另一方面,我們認爲錯誤是淺顯的現象,或者至少當暴露給上千個熱切的協作開發人員,讓他們來對每個新發布進行測試的時候,它們很快變得淺顯了,所以我們經常發佈來獲得更多的更正,作爲一個有益的副作用,如果你偶爾做了一個笨拙的修改,也不會損失太多。也許我們本不應該這樣的驚奇,社會學家在幾年前已經發現一羣相同專業的(或相同無知的)觀察者的平均觀點比在其中隨機挑選一個來得更加可靠,他們稱此爲“Delhpi效應”,Linus所顯示的證明在調試一個操作系統時它也適用——Delphi效應甚至可以戰勝操作系統內核一級的複雜度。


  我受Jeff Dutky (dutky @ wam.umd.edu)的啓發指出Linus定律可以重新表述爲“調試可以並行”,Jeff觀察到雖然調試工作需要調試人員和對應的開發人員相交流,但它不需要在調試人員之間進行大量的協調,於是它就沒有陷入開發時遇到的平方複雜度和管理開銷。

  在實際中,由於重複勞動而導致的理論上的喪失效率的現象在Linux世界中並不是一個大問題,“早發佈、常發佈策略”的一個效果就是利用快速的傳播反饋修訂來使重複勞動達到最小。


  Brooks甚至做了一個與Jeff相關的更精確的觀察:“維護一個廣泛使用的程序的成本一般是其開發成本的40%,奇怪的是這個成本受到用戶個數的強烈影響,更多的用戶發現更多的錯誤”(我的強調)。

  更多的用戶發現更多的錯誤是因爲更多的用戶提供了更多測試程序的方法,當用戶是協作開發人員時這個效果被放大了,每個找尋錯誤的人都有自己稍微不同的感覺和分析工具,從不同角度來看待問題。“Delphi效應”似乎因爲這個變體工作變得更加精確,在調試的情況下,這個變體同時減小了重複勞動。


  所以加入更多的beta測試人員雖不能從開發人員的P.O.V中減小“最深”的錯誤的複雜度,但是它增加了這樣一種可能性,即某個人的工具和問題正好匹配,而這個錯誤對這個人來說是淺顯的。


  Linus也做了一些改進,如果有一些嚴重的錯誤,Linux內核的版本在編號上做了些處理,讓用戶可以自己選擇是運行上一個“穩定”的版本,還是冒遇到錯誤的險而得到新特徵,這個戰略還沒被大多數Linux黑客所仿效,但它應該被仿效,存在兩個選擇的事實讓二者都很吸引 人。

  
五. 什麼時候玫瑰不是玫瑰?


  在研究了Linus的行爲和形成了爲什麼它成功的理論之後,我決定在我的工程(顯然沒有那麼複雜和雄心勃勃)裏有意識的測試這個理論。
但我首先做的事是熟悉和簡化Popclient。 Carl Harris的實現非常好,但是有一種對許多C程序來說沒有必要的複雜性。他把代碼當作核心而把數據結構當作對代碼的支持,結果是代碼非常漂亮但是數據結構設計得很特別,相當醜陋(至少對以這個老LISP黑客的標準來看),然而除了提高代碼和數據結構設計之外,重寫它還有一個目的,就是要把它演化爲我徹底理解的東西,對修改你不理解的程序中的錯誤負責可不是一件有趣的事。


  第一個月我只是在領會Carl's的基本設計的含義,我所做的第一個重大修改是加入了IMAP支持,我把協議機重新組織爲一個通用驅動程序和三個方法表(對應POP2、POP3和IMAP),這個前面的修改指出一個需要程序員(特別是象C這種沒有自然的動態類型支持的語言)記在腦中的一般原理:


  9. 聰明的數據結構和笨拙的代碼要比相反的搭配工作的更好


  Fred Brooks也在他第11章中講道:“讓我看你的[代碼],把你的[數據結構]隱藏起來,我還是會迷惑;讓我看看你的[數據結構],那我就不需要你的[代碼]了,它是顯而易見的”。


  實際上,他說的是“流程圖”和“表”,但是在三十年的術語/文化演進之後,事情還是一樣的。


  此時(1996年9月初,在從零開始六個月後),我開始想接下來修改名字——畢竟,它已不僅僅是一個POP客戶,但我猶豫了,因爲還沒有什麼新的漂亮設計呢,我的popclient版本需要有自己的特色。


  當fetehmail學會怎樣把取到的郵件轉送到SMTP端口時,事情就完全改變了,但是首先:上面我說過我決定使用這個工程來測試我關於Linus Torualds所做的行爲的理論,(你可能會問)我怎樣做到這點呢? 以下面的方式:
    1. 我儘早儘量頻繁的發佈(幾乎從未少於每十天發佈一次;在密集開發的時候是每天一次)。
    2. 我把每一個和我討論fetchmail的人加入一個beta表中。
    3. 每當我發佈我都向beta表中的人發出通告,鼓勵人們參與。
    4. 我聽取beta測試員的意見,向他們詢問設計決策,對他們寄來的補丁和反饋表示感謝。


  這些簡單的手段立即收到的回報,在工程的開始,我收到了一些錯誤報告,其質量足以使開發者因此被殺掉,而且經常還附有補丁、我得到了理智的批評,有趣的郵件,和聰明的特徵建議,這導致了:


  10. 如果你象對待最寶貴的資源一樣對待你的beta測試員,他們就會成爲你最寶貴的資源。


六. popclient變成了Fetchmail


  這個工程的真正轉折點是Harry Hochleiser寄給我他寫的代碼草稿,他把郵件轉發到客戶端機器的SMTP端口,我立即意識到這個特徵的可靠實現將淘汰所有其他的遞送模式。


  幾個星期以來我一直在修改而不是改進fetchmail,因爲我覺得界面設計雖然有用但是太笨拙瑣碎了,到處充滿了太多的粗陋的細小選項。


  當我思考SMTP轉發時我發現popclient試圖做的事太多了,它被設計成既是一個郵件傳輸代理(MTA)也是一個本地遞送代理(MDA)。使用SMTP轉發,它就可以從MDA的事務中解脫出來而成爲一個純MTA,而象sendmail一樣把郵件交給本地遞送程序來處理。


  既然端口25在所有支撐TCP/IP的平臺上早已被預留,爲什麼還要爲一個郵件傳輸代理的配置或爲一個郵箱設置加鎖的附加功能而操心呢?尤其是當這意味着抽取的郵件就象一個正常的發送者發出的SMTP郵件一樣,而這就是我們需要的。


  這裏有幾個教益:第一,SMTP轉發的想法是我有意識地模擬Linus的方法以來的最大的單個回報,一個用戶告訴我這個非同尋常的想法——我所需做的只是理解它的含義。


  11. 想出好主意是好事,從你的用戶那裏發現好主意也是好事,有時候後者更好。


  很有趣的是,你很快將發現,如果你完全承認你從其他人那裏得到多少教益的話,整個世界將會認爲所有的發明都是你做出的,而你會對你的天才變得謙虛。我們可以看到這在Linus身上體現得多明顯!(當我在1997年8月的Perl會議上發表這個論文時,Larry Wall坐在前排,當我講到上面的觀點時,他激動的叫了出來:“對了!說對了!哥們!”所有的聽衆都鬨堂大笑起來,因爲他們知道同樣的事情也發生在Perl的發明者身上)。


  於是在同樣精神指導下工程進行了幾個星期,我開始不光從我的用戶那兒也從聽說我的系統的人那兒得到類似的讚揚,我把一些這種郵件收藏起來,我將在我開始懷疑自己的生命是否有價值時重新讀讀這些信。:)


  但是有兩個更基本的,非政治性的對所有設計都有普遍意義的教益。


  12. 最重要和最有創新的解決方案常常來自於你認識到你對問題的概念是錯誤的。

  一個衡量fetchmail成功的有趣方式是工程的beta測試人員表(fegtchmail的朋友們)的長度,在創立它的時候已經有249個成員了,而且每個星期增加兩到三個。


  實際上,當我在1997年5月校訂它時,這張表開始因爲一個有趣的原因而縮短了,有幾個人請求我把他們從表中去掉,因爲fetchmail已經工作的如此之好,他們不需要看到這些郵件了!也許這是一個成熟的市集風格工程的生命週期的一部分。

  我以前一直在解決錯誤的問題,把popclient當作MTA和具有許多本地遞送模式的MDA的結合物,Fetchmail的設計需要從頭考慮爲一個純的MTA,做爲一個普通Internet郵件路徑的一部分。


  當你在開發中碰了壁時(當你發現自己很難想通下一步時),那通常不是要問自己是否找到正確答案,而是要問是否問了正確問題,也許需要重新構造問題。


  於是,我重新構造了我的問題,很清楚,要做的正確的事是(1)把SMTP轉發支持放在通用驅動程序中,(2)把它做爲缺省模式,(3)最終分離所有其他的遞送模式,尤其是遞送到文件和標準輸出的選項。


  我在第三步上猶豫了一下,擔心會讓popdiant的長期用戶對新的遞送方法感到煩心,在理論上,他們可以立即轉而轉發文件或者他們的非sendmail等價物來得到同樣的效果,在實際中這種轉換可能會很麻煩。
但是當我這麼做之後,證明好處是巨大的,驅動程序代碼的冗餘的部分消失了,配置完全變得簡單了——不用屈從於系統MDA和用戶的郵箱,也不用爲下層OS是否支持文件鎖定而擔心了。


  而且,丟失郵件的唯一漏洞也被堵死了,如果你選擇了遞送到一個文件而磁盤已滿,你的郵件就會丟失,這在SMTP轉發中不會發生,因爲SMTP偵聽器不會返回OK的,除非郵件可以遞送成功或至少被緩衝留待以後遞送。


  還有,性能也改善了(雖然在單次執行中你不會注意到),這個修改的另一個不可忽視的好處是手冊變得大大簡單了。


  後來,爲了允許處理一些罕見的情況,包括動態SLIP,我必須回到讓用戶定義本地MDA遞送上來,但是我發現了一個更加簡單的方法。


  所有這些給了我們什麼啓發呢?如果可以不損失效率,就要毫不猶豫拋棄陳舊的特性,Antonine de Saint-Exupery(在他成爲經典兒童書籍作家之前是一個飛行員和飛機設計師)曾說過:


  13. “最好的設計不是再也沒有什麼東西可以添加了,而是再也沒有什麼東西可以去掉。”


  當你的代碼變得更好和更簡單時,這就是你知道它是正確的時候了,而且在這個過程中,fetehmail的設計具有了自己的特點,而區別於其前身popclient。


  現在是改名的時候了,這個新的設計看起來比老popclient更象一個sendmail的複製品,它們都是MTA,但是Senmail是推然後遞送,而新的popclient是拉然後遞送。於是,在兩個月之後,我把它重新命名爲fetehmail。


七. Fetchmail成長起來


  現在我有了一個簡潔和富有創意的設計,工作得很好的代碼,因爲我每天都用它,和一直在增長的beta表,它讓我漸漸明白我已經不是在從事只能對少數其他人有用的工作中,我寫了一個所有有一個Unix郵箱和SLIP/PPP郵件連接的人都真正需要的程序。


  通過SMTP轉發功能,它成爲一個潛在的“目錄殺手”,遠遠領先於它的競爭者,這個程序如此能幹以至於其他的程序不但被放棄簡直被忘記了。


  我知道你不可以真得瞄準或計劃出這樣的結果,你只能努力去設計這些強大的思想,以後這些結果就好象是不可避免的、自然的、註定了的,得到這種思想的唯一辦法是獲取許多思想,或者用工程化的思考其他人的好主意而超過原來想到它的人的設想。


  Andrew Tanenbanm原來設想建造一個適合386的簡單的Unix用做教學,Linus Torvalels把Andrew的可能想到的Minix可以做什麼的概念推進了一步,成長爲一個極好的東西,同樣的(雖然規模較小),我接受了Card Harris和Harry Hochheiser的想法,把它們變得更強大,我們都不是人們所浪漫幻想的天才的創始人,但是大多數科學和工程和軟件開發不是被天才的創始人完成的,這和流傳的神話恰恰相反。


  結果總是執着的原因——實際上,它是每個黑客爲之生存的成功!而且它們意味着我必須把自己的標準定高一點,爲了把fetchmail變得和我所能設想的那樣好,我必須不僅爲我自己的需要寫代碼,而且也要包括對在我生活圍主頁外的人們的需求的支持,而且同時也要保證程序的簡單和健壯。


  在實現它之後我首先寫的最重要的特徵是支持多投——從集中一組用戶的郵件的郵箱中取出郵件,然後把它路由到每個人手中。


  我之所以加上多投功能部分是因爲有些用戶一直在鬧着要它,更是因爲我想它可以從單投的代碼中揭露出錯誤來,讓我完全一般地處理尋址,而且這被證明了。正確解釋RFC822花了我相當長的時間,不僅因爲它的每個單獨部分都很難,而且因爲它有一大堆相互依賴的苛刻的細節。


  但是多投尋址也成爲一個極好的設計決策,由此我知道:


  14. 任何工具都應該能以預想的方式使用,但是一個偉大的工具提供你沒料到的功能。


  Fetchmant多投功能的一個沒有料到的用途是在SLIP/PPP的客戶端提供郵件列表、別名擴展。這意味着一個使用個人機器的人不必持續訪問ISP的別名文件就能通過一個ISP帳戶管理一個郵件列表。我的beta測試員提出的另一個重要的改變是支持8位MIME操作,這很容易做,因爲我已經仔細的保證了8位代碼的清晰,不僅因爲我預見到了這個特性的需求,而且因爲我忠實於另一準則:


  15. 當寫任何種類的網關型程序時,多費點力,儘量少干擾數據流,永遠不要拋棄信息,除非接收方強迫這麼作!


  如果我不遵從這個準則,那麼8位MIME支持將會變得困難和笨拙,現在我所需要做的,是隻讀一下RFC 1652,在產生信頭的邏輯加上一點而已。


  一些歐洲用戶要求我加上一個選項來限制每次會話取得消息數(這樣他們就可以從昂貴的電話網中控制花費了),我很長一段時間拒絕這樣做,而且我仍然對它不很高興,但是如果你是爲了世界而寫代碼,你必須聽取顧客的意見——這並不隨他們不付給你錢而改變。


八. 從Fetchmail得來的另一些教益


  在他們回到一般的軟件工程問題以前,還有幾個從fetchmail得到的教益需要思考。


  rc文件語法包括可選的“noise”關鍵字,它被掃描器完全忽略了,當你把它們全抽取出的時候,關鍵字/值對更具可讀性。


  當我注意到rc文件的聲明在多大程度上開始象一個微型命令語言時,這是一個Late-night的體驗(這也是我爲什麼把popclient原來的“server”關鍵字改成了“poll”)。


  對我來說似乎把這個微型命令語言變得更象英語可能會使它更容易使用。現在,雖然我對經過Emacs和HTML及許多數據庫引擎所證實的“把它做成一個語言”的設計方式確信不疑,但是我並不是一個通常的“類英語”語法的狂熱擁護者。


  傳統程序員容易控制語法使它儘量精確和緊湊,完全沒有冗餘,這是計算機資源還很昂貴時遺留下的一種文化傳統,所以掃描策略需要儘可能的廉價和簡單,而具有50%冗餘度的英語,看來好象是一個非常不合適的模型。


  這並不是我不用類英語語法的原因,我提到這一點是爲了推翻它,在更廉價的時鐘週期與核心的時代,簡潔並沒有走到盡頭,今天對一個語言來說,對人更方便比對機器更廉價來的更加重要。


  然而,有幾個原因提醒我們小心一點,一個是掃描策略的複雜度開銷——你並不想把它變成一個巨大的錯誤來源和讓用戶困惑,另一個是試圖使語言表面上的類似可以和傳統語言一樣令人困惑(你可以在許多4GL和商業數據庫查詢語言上看到這一點)。
發佈了26 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章