如果你想創(chuàng)建一個(gè)只包含一個(gè)源程序文件的簡(jiǎn)單程序,那么你只需要編譯、連接那一個(gè)文件就可以了。如果是一個(gè)團(tuán)隊(duì)項(xiàng)目組,有著許多甚至上千個(gè)源程序文件,那么要?jiǎng)?chuàng)建一個(gè)可執(zhí)行程序的過(guò)程就變得更復(fù)雜、更耗時(shí)。你必須用各種各樣的組件將程序逐步建立起來(lái)。
在微軟或其它一些軟件公司中慣例是:每日構(gòu)造并做“冒煙測(cè)試”。每天都對(duì)已完成的源程序進(jìn)行編譯,然后連接組合成可執(zhí)行的程序,并做“冒煙測(cè)試”,以簡(jiǎn)單的檢查該執(zhí)行程序在運(yùn)行時(shí)是否會(huì)“冒煙”。
帶來(lái)的好處
雖然這是一個(gè)非常簡(jiǎn)單的過(guò)程,但卻有非常重要的意義:
1、能最小化集成風(fēng)險(xiǎn)
項(xiàng)目組可能遇到的一個(gè)很大的風(fēng)險(xiǎn)是,項(xiàng)目組成員根據(jù)不同的系統(tǒng)功能各自開(kāi)發(fā)不同的代碼,但是當(dāng)這些代碼集成為一個(gè)系統(tǒng)的時(shí)候,也許系統(tǒng)完成不了預(yù)期的功能。這種風(fēng)險(xiǎn)的發(fā)生取決于項(xiàng)目中的這種不兼容性多久才被發(fā)現(xiàn),由于程序界面已經(jīng)發(fā)生了變化,或者系統(tǒng)的主要部分已經(jīng)被重新設(shè)計(jì)和重新實(shí)現(xiàn)了,相應(yīng)的排錯(cuò)工作將非常困難和耗時(shí)。極端情況下,集成的錯(cuò)誤可能回導(dǎo)致項(xiàng)目被取消掉。每日構(gòu)造和冒煙測(cè)試可以使這種集成錯(cuò)誤變得非常小,而且便于解決,防止了很多集成問(wèn)題的產(chǎn)生。
2、能減小產(chǎn)品低質(zhì)量的風(fēng)險(xiǎn)
這種風(fēng)險(xiǎn)是和集成不成功、集成出錯(cuò)相關(guān)聯(lián)的。每天對(duì)集成的代碼做一些少量的冒煙測(cè)試,即可杜絕項(xiàng)目中那些基本的質(zhì)量問(wèn)題。通過(guò)這種方式,使系統(tǒng)達(dá)到一種周知的良好狀態(tài),維護(hù)這樣的系統(tǒng)可以防止系統(tǒng)逐步惡化到耗費(fèi)大量時(shí)間排查質(zhì)量問(wèn)題的地步。
3、能簡(jiǎn)單化錯(cuò)誤診斷
當(dāng)系統(tǒng)每天都進(jìn)行build和測(cè)試時(shí),系統(tǒng)任何一天發(fā)生的錯(cuò)誤都能夠變得十分精細(xì),便于排查。比如在17日系統(tǒng)還運(yùn)行正常,18日就出錯(cuò)了,那么只需要檢查這兩次build之間的代碼變化就可以了。
4、能極大鼓舞項(xiàng)目組的士氣
看到產(chǎn)品的不斷成長(zhǎng),能夠極大的鼓舞項(xiàng)目組的士氣,有時(shí)甚至不管這個(gè)產(chǎn)品到底用來(lái)做什么。開(kāi)發(fā)人員可能會(huì)為系統(tǒng)顯示了一個(gè)矩形而感到激動(dòng)。通過(guò)每日構(gòu)造,產(chǎn)品每天進(jìn)步一點(diǎn)點(diǎn),保證項(xiàng)目士氣的持續(xù)高漲。
進(jìn)行每日構(gòu)造和冒煙測(cè)試
雖然說(shuō)這是一個(gè)簡(jiǎn)單枯燥的活,每天進(jìn)行build,每天進(jìn)行測(cè)試,但也有著一些值得注意的細(xì)節(jié):
1、每天堅(jiān)持
每日構(gòu)造,最重要的就是“每日”。如Jim McCarthy所說(shuō),把每日構(gòu)造看作是項(xiàng)目的“心跳”,沒(méi)有“心跳”的話,項(xiàng)目也就死了(Dynamics of Software Development, Microsoft Press, 1995)。Michael Cusumano and Richard W. Selby描述了另外一種隱含的比喻,把每日構(gòu)造比作項(xiàng)目的“同步脈沖”(Microsoft Secrets, The Free Press, 1995)。 不同開(kāi)發(fā)人員寫(xiě)的代碼在他們的“脈沖”之間肯定都會(huì)存在“同步”的差異,但是必須有這樣一個(gè)“同步脈沖”,使得這些代碼能夠組合為一個(gè)整體。當(dāng)項(xiàng)目組堅(jiān)持每天把這些不同的“脈沖”組合到一起的時(shí)候,開(kāi)發(fā)人員脫離整體的情況就會(huì)得到極大程度的杜絕。
有些項(xiàng)目組把這一過(guò)程簡(jiǎn)化為“每周build一次”。這樣帶來(lái)的問(wèn)題是,某一次build失敗后,可能要回溯好幾周才能找到原因。如果這種情況發(fā)生的話,已經(jīng)得不到經(jīng)常build帶來(lái)的好處了。
2、嚴(yán)格檢查每一次build
要保證每一次build的成功,就必須保證build后的結(jié)果(也可稱為build)是可以正常運(yùn)行的,如果build不可運(yùn)行,那么本次build被認(rèn)為是不成功的,同時(shí)應(yīng)該將修復(fù)此次build的工作提高到項(xiàng)目組最高級(jí)別來(lái)處理。
對(duì)于如何衡量一個(gè)build,每一個(gè)項(xiàng)目組都會(huì)定義一些自己的標(biāo)準(zhǔn),這些標(biāo)準(zhǔn)需要設(shè)定一個(gè)嚴(yán)格的質(zhì)量級(jí)別來(lái)處理那些特別嚴(yán)重的缺陷,同時(shí)也需要具有一定的伸縮性來(lái)忽略掉那些微不足道的缺陷,一些不適當(dāng)?shù)年P(guān)心也許會(huì)使整個(gè)過(guò)程舉步為艱。
一個(gè)好的build起碼應(yīng)該具備以下條件:
●能夠成功編譯所有的文件、庫(kù),以及其它相關(guān)組件;
●能夠成功鏈接所有的文件、庫(kù),以及其它相關(guān)組件;
●不能存在任何使得系統(tǒng)無(wú)法運(yùn)行或者運(yùn)行出錯(cuò)的高級(jí)別故障;
●當(dāng)然,必須通過(guò)冒煙測(cè)試
3、每天進(jìn)行冒煙測(cè)試
冒煙測(cè)試應(yīng)該是對(duì)整個(gè)系統(tǒng)流程從輸入到輸出的完整測(cè)試。測(cè)試不必是面面俱到的,但是應(yīng)該能夠發(fā)現(xiàn)系統(tǒng)中較大的問(wèn)題。冒煙測(cè)試應(yīng)該是足夠充分的,通過(guò)了冒煙測(cè)試的build就可以認(rèn)為是經(jīng)過(guò)充分測(cè)試、足夠穩(wěn)定的。
不進(jìn)行冒煙測(cè)試的build是沒(méi)有太大價(jià)值的。冒煙測(cè)試就像一個(gè)哨兵,在阻止著產(chǎn)品質(zhì)量惡化和集成問(wèn)題的產(chǎn)生,不進(jìn)行冒煙測(cè)試,每日構(gòu)造可能會(huì)變成浪費(fèi)時(shí)間的練習(xí)。
冒煙測(cè)試必須隨著系統(tǒng)的擴(kuò)充而擴(kuò)充。最初,冒煙測(cè)試可能是非常簡(jiǎn)單的,比如驗(yàn)證系統(tǒng)是否會(huì)打印“Hello World”,隨著系統(tǒng)功能的擴(kuò)充,冒煙測(cè)試需要越來(lái)越充分。最初的冒煙測(cè)試也許只需要幾秒鐘來(lái)執(zhí)行,逐漸地,測(cè)試可能會(huì)花費(fèi)30分鐘,1小時(shí),甚至更長(zhǎng)。
4、建立一個(gè)專門的build小組
在很多項(xiàng)目組,維護(hù)每日構(gòu)造,并更新冒煙測(cè)試用例,會(huì)耗費(fèi)一個(gè)人工作的大部分時(shí)間。因此在一些大的項(xiàng)目中,這項(xiàng)工作獨(dú)立成不止一個(gè)人來(lái)完成的全職工作。比如在 Windows NT 3.0的研發(fā)中,就有一個(gè)由四個(gè)全職人員組成的專門的build小組(Pascal Zachary, Showstopper!, The Free Press, 1994)。
5、為build增加修訂,如果這樣做有意義的話
一般開(kāi)發(fā)人員不會(huì)每天都經(jīng)常向系統(tǒng)中快速的增加實(shí)際的代碼,通常是每隔幾天,他們?cè)陂_(kāi)發(fā)好完成某個(gè)功能的一套代碼以后,然后集成到整個(gè)系統(tǒng)中。
6、規(guī)定一些導(dǎo)致build失敗的懲罰措施
很多執(zhí)行每日構(gòu)造的項(xiàng)目組都會(huì)規(guī)定一些懲罰措施,來(lái)懲罰那些導(dǎo)致build失敗的行為。從最開(kāi)始,項(xiàng)目組成員就清楚的知道,build的正常執(zhí)行是項(xiàng)目組的頭等大事。一個(gè)失敗的build是項(xiàng)目組的意外,無(wú)法成為項(xiàng)目組工作的準(zhǔn)則。必須堅(jiān)持:導(dǎo)致build失敗的同事,必須停下手中的工作,首先來(lái)解決build失敗的問(wèn)題。如果一個(gè)項(xiàng)目組的build經(jīng)常失敗的話,久而久之的,再來(lái)談build的正確性就沒(méi)有意義了。
有種輕松的懲罰措施,能夠突出解決問(wèn)題的優(yōu)先性。Some groups give out lollipops to each "sucker" who breaks the build. This developer then has to tape the sucker to his office door until he fixes the problem. 有些項(xiàng)目組會(huì)懲罰犯錯(cuò)的同事戴上山羊角,或者向一個(gè)項(xiàng)目基金捐獻(xiàn)5塊錢。
有些項(xiàng)目組對(duì)此的懲罰就有點(diǎn)殘酷了。微軟的開(kāi)發(fā)人員,在一些知名度很高、很重要的產(chǎn)品如Windows NT,Windows 95,Excel等產(chǎn)品后期研發(fā)中,被要求隨時(shí)帶著尋呼機(jī),如果你的代碼導(dǎo)致build失敗的話,即使是凌晨3點(diǎn)鐘,也會(huì)要求你立即來(lái)處理這個(gè)問(wèn)題。
7、即使在壓力下也需堅(jiān)持每日構(gòu)造和冒煙測(cè)試
當(dāng)項(xiàng)目進(jìn)度的壓力越來(lái)越大時(shí),維護(hù)每日構(gòu)造的工作看起來(lái)有些浪費(fèi)時(shí)間,但是恰恰相反。在壓力之下,開(kāi)發(fā)人員丟掉一些平時(shí)的規(guī)定,會(huì)采用一些設(shè)計(jì)和實(shí)現(xiàn)的捷徑,這在平時(shí)壓力較小的環(huán)境下一般時(shí)不會(huì)用的。代碼的review和單元測(cè)試也可能會(huì)比平時(shí)粗心一些,這些代碼的狀態(tài)變化也會(huì)比平時(shí)快很多。
為防止這種情況的出現(xiàn),每日構(gòu)造會(huì)堅(jiān)持相關(guān)的規(guī)定,讓壓力下的項(xiàng)目保持在正軌上。代碼仍然每天在不斷變化,但是構(gòu)造過(guò)程使得這種變化每天都可控。
誰(shuí)能夠從每日構(gòu)造這種過(guò)程中得到好處呢?一些開(kāi)發(fā)人員會(huì)抗議說(shuō),由于他們的項(xiàng)目太大,每天進(jìn)行build是沒(méi)有實(shí)際意義的。但是為什么現(xiàn)在最復(fù)雜的軟件項(xiàng)目組卻能夠成功的執(zhí)行每日構(gòu)造的制度呢?本文首發(fā)時(shí),Windows NT包括了560萬(wàn)行代碼、分布在4萬(wàn)個(gè)源程序文件中,項(xiàng)目組仍然可以堅(jiān)持每日構(gòu)造。