Oo緣來(lái)是你oO


          posts - 120,comments - 125,trackbacks - 0
          作者: 周思博 (Joel Spolsky)
          譯: Chen Bin
          2001年1月27日

          1982年,我家定購(gòu)了IBM的PC機(jī)(IBM生產(chǎn)的最早的個(gè)人計(jì)算機(jī),是現(xiàn)代流行的標(biāo)準(zhǔn)化的個(gè)人計(jì)算機(jī)的祖宗)。我們家可能是以色列最早擁有這種PC機(jī)的幾個(gè)家庭之一。當(dāng)時(shí)我們跑到了倉(cāng)庫(kù)等著電腦從港口運(yùn)過(guò)來(lái)。事實(shí)上,我說(shuō)服我爸購(gòu)買(mǎi)的是帶有全套附屬設(shè)備的個(gè)人計(jì)算機(jī)(譯者按:有些現(xiàn)在很便宜的附屬設(shè)備,那時(shí)候都是非常昂貴的),這些附屬設(shè)備包括兩個(gè)軟盤(pán)驅(qū)動(dòng)器,128K內(nèi)存,一個(gè)針式點(diǎn)陣打印機(jī)(用來(lái)快速打印草稿)和一個(gè)運(yùn)轉(zhuǎn)起來(lái)發(fā)出機(jī)關(guān)槍掃射聲音的兄弟牌的雛菊輪式打印機(jī)(譯者按:原文為Daisy Wheel printer,是一種已經(jīng)淘汰的打印機(jī),原理類似于老式的機(jī)械打字機(jī),可以產(chǎn)生清晰的英文字符)。附屬的軟件也很齊全,PC-DOS 1.0(最早的PC操作系統(tǒng)),75美元的參考書(shū)冊(cè),包括BIOS的完整源代碼。 一個(gè)匯編語(yǔ)言編譯器(Macro Assembler),非常棒的IBM單色顯示器,可以顯示80列寬的字符,而且支持小寫(xiě)字母顯示。整套配置大概花了10000美元。這些錢(qián)包括以色列的荒謬的進(jìn)口稅。呵呵,那時(shí)候我家可真舍得花錢(qián)啊!

          因?yàn)楫?dāng)時(shí)“每個(gè)人”都知道BASIC是給小孩玩的語(yǔ)言,用這種語(yǔ)言只能使你寫(xiě)出非結(jié)構(gòu)化的垃圾代碼,然后你的的腦子也會(huì)被這種語(yǔ)言變成Camembert產(chǎn)的奶酪(Camembert cheese,法國(guó)的一種奶酪,實(shí)心,圓餅狀,灰色,有一個(gè)拳頭大小)。所以我們又花了600美元買(mǎi)了一個(gè)IBM公司PASCAL語(yǔ)言開(kāi)發(fā)包,需要3張軟盤(pán)才裝的下。PASCAL編譯器運(yùn)行分別需要第一號(hào)軟盤(pán),和第二號(hào)軟盤(pán),PASCAL鏈接器需要第三號(hào)軟盤(pán)。我寫(xiě)了一個(gè)簡(jiǎn)單的輸出文字“你好,世界”程序然后編譯鏈接這個(gè)程序,總共花了8分鐘。

          嗯,8分鐘好像太長(zhǎng)了。我寫(xiě)了一個(gè)腳本程序來(lái)自動(dòng)化整個(gè)過(guò)程,把時(shí)間縮減為7.5分鐘。這樣好一點(diǎn)了。但是我想設(shè)計(jì)一個(gè)可以玩奧賽羅的程序。(譯者按:奧賽羅原文為Othello,一種棋類游戲,規(guī)則見(jiàn)http://www.ugateways.com/bof4.html)這個(gè)游戲總是能打動(dòng)我。我不得不花很多時(shí)間等待編譯器編譯我的程序。“就是這樣的,”一個(gè)專業(yè)程序員告訴我,“我們通常在辦公室里房放上sit-up board(譯者按:一種健身器材,可以在上面做仰臥起坐或者有氧操什么的) ,當(dāng)PASCAL編譯器開(kāi)始運(yùn)行時(shí),我們就開(kāi)始鍛煉。我這樣編程了幾個(gè)月后,我的身材不要太棒喔!”

          后來(lái)有一天,丹麥程序員寫(xiě)了一個(gè)很靈的叫做Compas Pascal的程序。Philippe Kahn(Borland公司的創(chuàng)始人)買(mǎi)下了它,更名為Borland Turbo Pascal。Turbo Pascal好得簡(jiǎn)直難以想象,因?yàn)樗茏鯥BM Pascal能做的所有事情,但是只要33K內(nèi)存。而且還額外提供一個(gè)編輯器。 這還不是最棒的。最棒的是編譯一個(gè)小程序只需要不到一秒。這就好比一個(gè)你從來(lái)沒(méi)有聽(tīng)說(shuō)過(guò)的公司生產(chǎn)了通用公司別克轎車(chē)的克隆版,這種克隆車(chē)可以每小時(shí)行駛一百萬(wàn)英里,但是只消耗了一滴汽油。一只小小的螞蟻喝下這點(diǎn)汽油也不會(huì)撐死。

          突然,我的編程效率變得高的

          那時(shí)我開(kāi)始明白了“REP循環(huán)”(Rep loop)這個(gè)概念. REP是“讀入,求值,打印(Read, Eval, Print)”的縮寫(xiě)。這個(gè)概念解釋了Lisp(一種編程語(yǔ)言,用于人工智能)解釋器的基本原理:它“讀入”你的輸入,計(jì)算你的輸入得到結(jié)果,打印結(jié)果。下面給一個(gè)例子:我輸入一些東西,Lisp解釋器計(jì)算,然后輸出結(jié)果。

          REP Loop

          在一個(gè)稍微大點(diǎn)的規(guī)模上,當(dāng)你寫(xiě)代碼時(shí),你也處于一個(gè)REP循環(huán)的宏版本中,這個(gè)循環(huán)就是“編碼-編譯-測(cè)試”。你編寫(xiě)代碼,把代碼編譯成可執(zhí)行的文件,然后測(cè)試它,看一下運(yùn)行起來(lái)怎么樣。

          關(guān)鍵一點(diǎn)是當(dāng)你寫(xiě)一個(gè)程序時(shí),你的工作過(guò)程是循環(huán)的。一個(gè)循環(huán)所花時(shí)間越短,你的生產(chǎn)力就越高,當(dāng)然最短時(shí)間不會(huì)小于編譯器運(yùn)行的時(shí)間。 這就是一個(gè)程序員為什么總是要一個(gè)真正夠快的硬件而編譯器開(kāi)發(fā)者們總是不斷使他們的編譯器運(yùn)行更快的正式的純計(jì)算機(jī)科學(xué)角度的原因。Visual Basic的辦法是當(dāng)你輸入代碼時(shí),它就開(kāi)始進(jìn)行代碼的語(yǔ)法解析,這樣程序解釋運(yùn)行時(shí)速度很快。Visual C++的辦法是增量編譯(incremental compiles),預(yù)編譯頭文件(precompiled headers)和增量鏈接(incremental linking)。

          但是一個(gè)大型的團(tuán)隊(duì)有多個(gè)開(kāi)發(fā)人員和測(cè)試人員,你碰到了同樣的循環(huán),可能不同點(diǎn)就是有更多的文檔要寫(xiě)(可是這還只是草稿,天哪!)。一個(gè)測(cè)試人員發(fā)現(xiàn)了bug并報(bào)告,然后開(kāi)發(fā)人員修復(fù)了這個(gè)bug。那么測(cè)試人員得到修正后的代碼需要多少時(shí)間?在一些軟件開(kāi)發(fā)機(jī)構(gòu),這樣的報(bào)告-修正-再測(cè)試循環(huán)(Report-Fix-Retest loop)可能需要幾個(gè)禮拜。如果一個(gè)循環(huán)需要這么長(zhǎng)的時(shí)間,通常意味著該機(jī)構(gòu)生產(chǎn)力很低。想讓整個(gè)開(kāi)發(fā)過(guò)程運(yùn)轉(zhuǎn)得更平滑一點(diǎn),你必須想方設(shè)法使得報(bào)告-修正-再測(cè)試循環(huán)(Report-Fix-Retest loop)花的時(shí)間更少。

          一個(gè)好的辦法是每日構(gòu)建(daily builds)。 每日構(gòu)建意味著自動(dòng)地,每天,完整地構(gòu)建整個(gè)代碼樹(shù)、(譯者按:“代碼樹(shù)”,原文為source tree,意思是將整個(gè)項(xiàng)目源代碼的目錄,子目錄,文件的位置盡可能事先固定下來(lái),這樣在開(kāi)發(fā)過(guò)程中各個(gè)模塊間,各個(gè)文件間的相對(duì)位置都不會(huì)混亂。源代碼樹(shù)指的就是一個(gè)項(xiàng)目所有的已經(jīng)組織好的代碼文件。通常代碼樹(shù)應(yīng)該用版本控制軟件管理起來(lái)。雖然這個(gè)概念很基本,但是據(jù)我的觀察,國(guó)內(nèi)還是有軟件公司在這方面做的不夠好的,所以有必要解釋一下。)

          自動(dòng)地 因?yàn)槟阍O(shè)定代碼每天在固定的時(shí)間構(gòu)建。在Unix環(huán)境下使用cron,在windows下使用“任務(wù)計(jì)劃”。

          每天 - 或者更頻繁. 當(dāng)然每天構(gòu)建的次數(shù)越多越好啦。但是有時(shí)候構(gòu)建次數(shù)還是有上限的,原因和版本控制有關(guān)系,等會(huì)兒我會(huì)談到的。

          完整地 -很可能你的代碼有多個(gè)版本。多語(yǔ)言版本,多操作系統(tǒng)版本,或者高端低端版本。每日構(gòu)建(daily build)需要構(gòu)建所有這些版本。并且每個(gè)文件都需要從頭編譯,而不是使用編譯器的不完美的增量編譯功能。

          以下是每日構(gòu)建(daily build)能帶來(lái)的好處:

          1. 當(dāng)一個(gè)bug被修正了,測(cè)試者可以很快得到最新的修正后的版本開(kāi)始重新測(cè)試,以驗(yàn)證bug是否真正地被修復(fù)了。
          2. 開(kāi)發(fā)人員可以更加確定他們對(duì)代碼做的修改不會(huì)破壞1024個(gè)操作系統(tǒng)上的任何一個(gè)版本。驗(yàn)證這一點(diǎn)不需要在他們的機(jī)器上安裝OS/2(IBM公司生產(chǎn)的PC機(jī)操作系統(tǒng))。
          3. 那些每天將修改過(guò)的代碼導(dǎo)入(check in)版本控制服務(wù)器的開(kāi)發(fā)人員知道,他們對(duì)一個(gè)模塊導(dǎo)入的修改不會(huì)拖別的開(kāi)發(fā)人員的后腿。拖后腿的意思是,那些開(kāi)發(fā)別的模塊的程序員使用這個(gè)修改過(guò)的模塊,出了問(wèn)題,于是他們自己的模塊也沒(méi)有辦法開(kāi)發(fā)下去了。每日構(gòu)建則不會(huì)有人拖后腿。如果把一個(gè)開(kāi)發(fā)團(tuán)隊(duì)比作一臺(tái)PC機(jī),那么團(tuán)隊(duì)中的一個(gè)程序員對(duì)某個(gè)模塊的修改導(dǎo)致其他人無(wú)法開(kāi)發(fā)別的模塊,相當(dāng)于PC機(jī)發(fā)生了藍(lán)屏。當(dāng)一個(gè)程序員忘記把他(她)新建立的文件導(dǎo)入到repository(指版本控制服務(wù)器上的代碼樹(shù))時(shí),這種開(kāi)發(fā)過(guò)程中的“藍(lán)屏”會(huì)經(jīng)常發(fā)生。因?yàn)樵谶@個(gè)程序員自己的計(jì)算機(jī)上有這個(gè)文件,所以他(她)構(gòu)建 這個(gè)程序沒(méi)有問(wèn)題。但是其他程序員是從版本控制服務(wù)器上導(dǎo)出(check out)代碼的,由于服務(wù)器上沒(méi)有這個(gè)文件,他們遇到了鏈接錯(cuò)誤(link error),無(wú)法繼續(xù)工作了。
          4. 外部團(tuán)隊(duì)(例如市場(chǎng)銷(xiāo)售部門(mén),進(jìn)行beta測(cè)試的一些客戶)可以獲得一個(gè)比較穩(wěn)定的版本,這樣對(duì)他們開(kāi)展自己的工作比較有利。
          5. 假如你將每日構(gòu)建出的二進(jìn)制文件(例如一個(gè)可執(zhí)行程序,一個(gè)dll等等)存檔管理,那么當(dāng)你發(fā)現(xiàn)一個(gè)非常奇怪的,無(wú)法解決的bug時(shí),你可以通過(guò)對(duì)這些文件進(jìn)行二進(jìn)制搜索(binary search)來(lái)確定什么時(shí)候這個(gè)bug第一次出現(xiàn)。如果有對(duì)代碼進(jìn)行了完善的版本控制,你也可以找出是誰(shuí)在何時(shí)對(duì)代碼進(jìn)行的導(dǎo)入(check in)導(dǎo)致了這個(gè)bug。
          6. 當(dāng)開(kāi)發(fā)者修正了測(cè)試者報(bào)告的一個(gè)錯(cuò)誤時(shí),如果測(cè)試者同時(shí)報(bào)告了發(fā)現(xiàn)錯(cuò)誤時(shí)的構(gòu)建的版本,開(kāi)發(fā)人員可以直接在那個(gè)版本中測(cè)試是否bug真正被修復(fù)了。(譯者按:測(cè)試者報(bào)告出現(xiàn)了一個(gè)bug,只是報(bào)告了一個(gè)錯(cuò)誤癥狀,而錯(cuò)誤的原因可能有多個(gè),每個(gè)原因可能在不同的模塊中。前文中的方法是為了避免只修正了一個(gè)模塊中一個(gè)原因,別的模塊由于在變動(dòng),于是掩蓋了而不是修復(fù)了bug)

          以下是如何進(jìn)行每日構(gòu)建(daily build)的具體步驟。你需要用最快的電腦建立一個(gè)每日構(gòu)建服務(wù)器。寫(xiě)一個(gè)腳本,可以自動(dòng)從版本控制服務(wù)器中導(dǎo)出(check out)完整的代碼,(你當(dāng)然使用版本控制,不是嗎?),然后對(duì)代碼從頭開(kāi)始進(jìn)行構(gòu)建(build),要構(gòu)建所有的版本。如果你有一個(gè)安裝打包程序,也要在腳本中自動(dòng)運(yùn)行。所有會(huì)賣(mài)給最終用戶的東西都要包括在構(gòu)建過(guò)程中。把構(gòu)建出來(lái)的版本放在各自的的目錄里,不同時(shí)間構(gòu)建的相同版本也應(yīng)該按日期整理好,不要相互覆蓋。每天固定的時(shí)間運(yùn)行這樣的腳本。

          • 最關(guān)鍵的是所有這些步驟都應(yīng)該由腳本自動(dòng)化完成,從導(dǎo)出(check out)代碼到將最終產(chǎn)品放在網(wǎng)上供用戶下載(當(dāng)然在開(kāi)發(fā)階段,產(chǎn)品是放在一臺(tái)測(cè)試服務(wù)器上的)。要保證開(kāi)發(fā)過(guò)程中的任何東西的任何記錄是由文檔記錄的而不是由某個(gè)人的腦子來(lái)記錄的,這是唯一的辦法。否則你會(huì)碰到這樣的情況,產(chǎn)品需要發(fā)布了,可是只有Shaniqua知道如何將產(chǎn)品打包的,可是他剛剛被巴士撞了。在Juno公司(本文作者工作過(guò)的公司之一),要進(jìn)行每日構(gòu)建,你唯一需要學(xué)會(huì)的東西就是雙擊每日構(gòu)建服務(wù)器桌面上的一個(gè)快捷方式。
          • 如果你在發(fā)行程序的當(dāng)天發(fā)現(xiàn)了一個(gè)小bug,沒(méi)有問(wèn)題。修正它,然后重新運(yùn)行每日構(gòu)建腳本,現(xiàn)在你可以安安心心的發(fā)行程序了。當(dāng)然,黃金定律是每日構(gòu)建腳本應(yīng)該是把所有的事情從頭做一遍,遵循這個(gè)定律就不會(huì)有什么問(wèn)題。
          • 將你的編譯器的警告參數(shù)設(shè)到最大(在微軟的VC中是-W4 ; 在GCC中是-Wall),當(dāng)遇到任何一個(gè)最微小的警告時(shí)就應(yīng)該停下來(lái)。
          • 如果每日構(gòu)建失敗了,可能整個(gè)開(kāi)發(fā)團(tuán)隊(duì)的工作會(huì)因此進(jìn)行不下去。當(dāng)務(wù)之急是立刻找出原因,使得每日構(gòu)建能成功進(jìn)行下去。某天也許你會(huì)一天運(yùn)行好幾次每日構(gòu)建腳本的。
          • 每日構(gòu)建一旦失敗,應(yīng)該自動(dòng)地將失敗用email通知整個(gè)團(tuán)隊(duì)。提取錯(cuò)誤日志中的恰當(dāng)部分并包括在email正文中也不是很難。每日構(gòu)建腳本也可以將當(dāng)前的狀態(tài)報(bào)告整理成一個(gè)html文件,自動(dòng)發(fā)布到一個(gè)所有人都可以訪問(wèn)的web服務(wù)器上,這樣測(cè)試者可以很快知道那個(gè)版本的構(gòu)建是成功的。
          • 當(dāng)我在微軟的excel團(tuán)隊(duì)中工作時(shí),我們的一個(gè)有效辦法是,誰(shuí)導(dǎo)致每日構(gòu)建(daily build)失敗,他(她)就得負(fù)責(zé)照看當(dāng)日的每日構(gòu)建(譯者按:微軟通常每日構(gòu)建都在半夜),直到有另一個(gè)人導(dǎo)致構(gòu)建失敗而接替他(她)。這樣做當(dāng)然可以使每個(gè)開(kāi)發(fā)者都小心不要因?yàn)樽约捍a的錯(cuò)誤破壞了構(gòu)建,更重要的是團(tuán)隊(duì)中的每個(gè)人都可以學(xué)會(huì)每日構(gòu)建(daily build)的原理。
          • 如果你的團(tuán)隊(duì)在同一個(gè)時(shí)區(qū)工作,在午飯時(shí)間進(jìn)行每日構(gòu)建(daily build)是個(gè)不錯(cuò)的主意。午飯前每個(gè)程序員導(dǎo)入(check in)代碼,這樣當(dāng)程序員在吃飯時(shí),構(gòu)建系統(tǒng)在工作。當(dāng)程序員吃完飯回來(lái)時(shí),如果每日構(gòu)建失敗了,所有的人也都在,可以盡快找出失敗的原因。當(dāng)構(gòu)建系統(tǒng)運(yùn)作起來(lái)時(shí),沒(méi)有人再會(huì)擔(dān)心別人導(dǎo)入(check in)代碼會(huì)妨礙自己的工作了。.
          • 如果你的團(tuán)隊(duì)同時(shí)在兩個(gè)時(shí)區(qū)工作,計(jì)劃好每日構(gòu)建(daily build)的時(shí)間使得一個(gè)時(shí)區(qū)的工作不會(huì)影響另一個(gè)時(shí)區(qū)的工作。在Juno公司,紐約程序員在晚上7:00導(dǎo)入(check in)到版本控制服務(wù)器。如果他們的導(dǎo)入導(dǎo)致構(gòu)建失敗,印度Hyderabad市(譯者按:印度科技重鎮(zhèn))的程序員在紐約時(shí)間晚上8:00以后的工作幾乎無(wú)法進(jìn)行下去。我們每天進(jìn)行兩次每日構(gòu)建(daily build),每次構(gòu)建的時(shí)間都在兩地的程序員回家之前,這下就沒(méi)有問(wèn)題了。

          更進(jìn)一步的閱讀:



          馬嘉楠
          jianan.ma@gmail.com

          posted on 2006-08-22 11:45 馬嘉楠 閱讀(502) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 湟源县| 邢台市| 渝中区| 安新县| 巴南区| 邢台县| 洮南市| 灵石县| 井研县| 崇左市| 娄底市| 建宁县| 瑞金市| 穆棱市| 高青县| 新平| 镇平县| 宁乡县| 滨州市| 正蓝旗| 佛坪县| 巢湖市| 陆良县| 德化县| 射洪县| 新晃| 延庆县| 凉城县| 蕲春县| 三亚市| 张掖市| 元朗区| 洪洞县| 辽源市| 靖宇县| 邮箱| 文水县| 新乐市| 皋兰县| 谢通门县| 河北区|