重寫Reddit

發表於2014-10-29

2012 年注:本文首發於2005年。釋出之後,Django上線了一個RemovingTheMagic專案,提出了我的一些質疑(儘管我本人發現它仍然不可用),web.py促進了FriendFeed的tornado.web和Google的gae.webapp以及其它專案(儘管如此我仍然喜歡web.py),本文引起了Reddit流量的永久井噴,仍然沒有真正地停止增長。

reddit.com過去的一週裡,我們用Python代替Lisp重寫了網站。這周我們做了很多工作(透露:我們使用了我開發的web.py類庫)。其他人熟悉Lisp(整個站點用它編寫),他們喜歡Python(他們用它重寫了整個站點),然而他們決定,在這個專案中喜歡Python多一些。Python版本的網站需要更少的程式碼,執行更快、程式碼更容易閱讀和維護。

根據在reddit部落格上的評論,比Lisp更好的東東的想法,表面上對一些人是不可思議的。Lisp愛好者們很快著手儘量找到變換語言背後的真正原因。

有人認為這裡面一定有不同尋常的干預,由於“貌似沒有切換到低等語言的其它原因。”又有人覺得其它事情必須在發生著:“這會是……一個謊言?扔掉競爭力?貌似Paul Graham沒有在他的文章裡暗示這個策略呀……”還有人附和道:“我認為這是惡作劇。”也有人提出,作者只是想更多地“走捷徑、hack和偽裝手法。”

當然,它們都是極端的情況。其它人猜測一定有來自外部的壓力。“我猜,要麼是類庫,要麼是僱傭新員工。”有人總結到:“一些投資商想要任何程式設計師都能維護的產品。我希望他給你支付了好多錢。”

Lisp新聞組comp.lang.lisp對於這次切換感到失望,他們為了表明自己是多麼地正確,最近正計劃把reddit寫成Lisp的一個競爭者

這些說法當中,稍微中肯的提到Lisp的價值在於能夠建立新的語言結構,這對於簡單的web應用程式而言,是不必要的,因為結構已經被建好了。不過,這也不是真實的。web.py完全從零起步,用到了各種“新的語言結構”(linguistic constructs)——甚至更好——這些結構具有語法,讓它們具有合理的可讀性。當然,Python不是Perl 6,因此你不能增加任意語法,不過你經常能夠找到把事情搞定的聰明方法。

另一方面,Python有它自己的問題。最大的問題在於它有很多web應用程式框架,但是都不太好。Python愛好者只是注意到了第一句,而明顯忽視了第二句,因為當我告訴他們我正在用自己的類庫時,通常的反應是“我認為Python不需要另一個web應用程式框架”。是的,Python需要更少的web應用程式框架,但是它也需要不是太糟糕的框架。

貌似最有前途的框架就是Django了,我們最初的確想用它重寫reddit。做為有經驗的Python程式設計師,我儘量幫助其他人解脫出來。

從外面看Django貌似優秀:良好外觀的網站、極具才能和天賦的開發者,表面過剩的、優秀功能。開發者和社群是非常有幫助的,也對補丁和建議作出響應。所有正確的目標都在他們的哲學文件和FAQ得以支援。然而不幸的是,它們好像完全沒有達到自己的期望。

Django聲稱它是“鬆耦合”的,卻要求你的程式碼符合Django的風格。Django堅持你的程式碼執行本身,或是通過命令列工具,或是藉助正確的環境變數和Python路徑做特定的伺服器處理程式呼叫。當你開始專案時,Django預設為程式碼生成了巢狀四層的資料夾,而你能夠移動一些檔案,我在搞清楚移動哪一個以及如何移動上遇到了麻煩。

Django的哲學是“明確優於隱式”,但是它卻有各種魔法。你在一個檔案建立的資料庫模型,神奇地出現在有著不同名字的Django模組內部的某個地方。當模型功能被呼叫時,新東東被添到了它的變數裡,舊的資料被移除了。(我被告知,他們目前正在修復這兩個問題。)

Django的另一個目標是“較少的程式碼”,至少對你而言。但是Django卻充滿了程式碼。在Django裡有10個不同的資料夾、而每個資料夾內部又有一些資料夾。當你根據Django教程開始實際地建立網站時,你已經匯入了django.core.meta, django.models.polls,django.conf.urls.defaults.*,django.utils.httpwrappers.HttpResponse和django.core.extensions.render_to_response。任何人應當記住它們,不是明確的,尤其是好像沒有原理或如何命名的指導原則。上面的三個模組被開始的指令碼自動插入了,但是你仍然需要為你想使用的每個函式記住這些名字。

不過,Django最重要的問題在於,它的開發者貌似未能設計出得體的API。他們肯定是有能力的Python程式設計師——他們的程式碼用到了各種奇怪的手法。他們肯定能寫出可執行的程式碼——它們有各種有趣的功能。但是,他們好像不能把程式碼構造成其他人可用的方式。

他們的API是醜陋的,定期地丟失重要功能:資料庫API通過計算下劃線來構造查詢,但是沒有專門的語法來處理JOIN,模板系統需要4個大括號包圍每個變數,卻不能做任意種類的計算,表單API需要15行來處理表單,卻不能自動生成模板。

我盡力修復這些問題了——Django社群相當支援——但是任務讓我退縮了。我只是精神上做不到,更不要說 不得不為我自己的創業去實際開發自己的應用程式的、時間限制。

因此,Lisp和Django是不足的,我們帶著web.py離開了。我想說,web.py認識到了這些錯誤,在設計的時候就避免了它們,不過真相是,web.py在出現這些問題之前已經被編寫了,並設法避免了它們。

我寫web.py的方式是簡單的:我想象著事情應該如何執行,然後我讓它們成為現實。有時候讓它執行需要很多程式碼。有時候它只需要一點兒程式碼。但是不管怎樣,這些事實對於使用者是不可見的——它們只需要完美的API。

那麼應該如何執行呢?第一個原則是,程式碼應該清晰簡單。如果你想輸出文字,你就呼叫web.output。如果你想得到表單輸入,你就呼叫web.input。沒有特別難記的東東。

第二個原則,web.py應該適合你的程式碼,而不是其它方式。web.py裡的每個函式都是完全獨立的,你想用哪個就用哪個。你可以把檔案隨意放在任何地方,web.py樂於定位到它。如果你想把一塊程式碼做為web應用程式執行,你可以呼叫web.run,你不要把程式碼放在不可思議的地方,讓web.py執行。

第三個原則是,web.py預設應該做web所認為的正確的事情。這意味著正確地區分GET和POST。它代表了簡單、同一性會跳轉到標準連結。它代表了含有正確HTTP頭的、可讀的HTML。

我所擔心的是,有太多你需要的原則。它們對我來說,好像非常簡單和明顯,甚至我樂意篡改它們,但是其它Python的web應用程式框架卻沒有和它比肩的。(如果你知道有,請告訴我,我樂於收回上面的話。我想不是這樣的。)在此之前,貌似我被迫做了一件本不願意做的、可怕的事情:向世界又提交了一個Python web應用程式框架。

相關文章