在我現在的遊戲項目中,基本上每天都要代碼,各種遊戲資源需要更新。而且每次從SVN伺服器上更新代碼後都要編譯好久。另外資源的更新也是一件很麻煩的事情,因為我們的所有遊戲資源都是統一放在一個FTP上面,每個版本發布之後都會把最新的遊戲資源放在裡面。每次從FTP上把好幾G的資料更新下來很是費時間。於是我在想能不能寫個小程式讓這些都自動執行,即能夠設定一個時間。例如每天的淩晨從FTP上把資源更新下來,然後再從SVN上把最新的代碼更新下來,最後讓程式自動編譯。每一步都有詳細的log記錄,第二天上班後就可以取到最新的版本了。
實際我的上述方法就是Daily Build的雛形。Daily Build又稱“nightly build”,是將一個軟體項目的所有最新代碼取出,從頭開始編譯、連結,用安裝軟體包將連結好的軟體安裝好,運行安裝後的軟體,運行測試軟體包對主要功能進行測試(smoke test),發現錯誤並報告錯誤的完整過程。我的上述想法只是沒有自動安裝和測試的步驟。
其實實現起來也不是很難,最簡單的方法就是寫個批處理,然後把批次程式掛到控制台的“Scheduled Tasks”中。這種土辦法自己要玩玩還行,真要用到項目中去還必須使用專業的軟體工具。我在網上搜了一下,發現一款名叫Visual Build的軟體還不錯,以後有機會要好好介紹一下。
下面還是稍微介紹下每日構建吧:
在微軟軟體開發中,每日構建是最重要的過程之一,被稱為微軟產品開發的“心跳”。簡單來看,每天構建系統將整個產品解決方案完整構建一遍,產生的目標檔案和安裝檔案被放置在一個共用位置。接著,安裝檔案被自動部署到release server上,隨後可以自動運行BVT(build verification test),並將所有結果寄送每個team member的信箱。
微軟有一套完善的內部系統來完成整個自動化流程,以及流程管理、reporting等工作,而如果我們沒有這套系統,也想實現完整的daily build流程,該怎麼做呢?
在VS.NET2003時代,IDE可以控制整個方案的構建,但是所有的構建邏輯被IDE控制,對於開發人員來說,整個構建流程就像一個黑箱,很難修改和管理。當然可以使用PreBuildEvent和PostBuildEvent來控制,但是這些event都寫在csproj/vbproj檔案中,不便於修改,不適於擴充。而且使用IDE來做每日構建的話,要求構建系統本身裝有VS.NET,這會帶來額外的成本。另一種辦法是使用NAnt,通過XML設定檔,來管理構建流程,這會使得整個流程易於修改,可擴充,並且不要求構建系統安裝IDE,只需要有framework即可。問題是使用NAnt必須額外寫一堆複雜的XML設定檔,足以讓很多developer看了頭疼。
VS.NET2005中引入了一套全新的構建系統:MSBuild。簡單來講,MSBuild可以直接讀取csproj檔案,控制csc/vbc等編譯器,產生整個方案。實際上,VS2005的IDE自身就是調用MSBuild來完成編譯的,這與VS2003有很大的不同。並且由於VS2005的csproj檔案服從MSBuild的配置schema,因此我們可以直接使用csproj,稍稍修改一下,就能組織起完整的構建流程了。
雖然這是一個非常簡單的過程,但卻有非常重要的意義:
1、能最小化整合風險
項目組可能遇到的一個很大的風險是,項目群組成員根據不同的系統功能各自開發不同的代碼,但是當這些代碼整合為一個系統的時候,也許系統完成不了預期的功能。這種風險的發生取決於項目中的這種不相容性多久才被發現,由於程式介面已經發生了變化,或者系統的主要部分已經被重新設計和重新實現了,相應的排錯工作將非常困難和耗時。極端情況下,整合的錯誤可能回導致項目被取消掉。每日構造和煙霧測試 (Smoke Test)可以使這種整合錯誤變得非常小,而且便於解決,防止了很多整合問題的產生。
2、能減小產品低品質的風險
這種風險是和整合不成功、整合出錯相關聯的。每天對整合的代碼做一些少量的煙霧測試 (Smoke Test),即可杜絕項目中那些基本的品質問題。通過這種方式,使系統達到一種周知的良好狀態,維護這樣的系統可以防止系統逐步惡化到耗費大量時間排查品質問題的地步。
3、能簡單化錯誤診斷
當系統每天都進行build和測試時,系統任何一天發生的錯誤都能夠變得十分精細,便於排查。比如在17日系統還運行正常,18日就出錯了,那麼只需要檢查這兩次build之間的代碼變化就可以了。
4、能極大鼓舞項目組計程車氣
看到產品的不斷成長,能夠極大的鼓舞項目組計程車氣,有時甚至不管這個產品到底用來做什麼。開發人員可能會為系統顯示了一個矩形而感到激動。通過每日構造,產品每天進步一點點,保證項目士氣的持續高漲。
進行每日構造和煙霧測試 (Smoke Test)
雖然說這是一個簡單枯燥的活,每天進行build,每天進行測試,但也有著一些值得注意的細節:
1、每天堅持
每日構造,最重要的就是“每日”。如Jim McCarthy所說,把每日構造看作是項目的“心跳”,沒有“心跳”的話,項目也就死了(Dynamics of Software Development, Microsoft Press, 1995)。Michael Cusumano and Richard W. Selby描述了另外一種隱含的比喻,把每日構造比作項目的“同步脈衝”(Microsoft Secrets, The Free Press, 1995)。 不同開發人員寫的代碼在他們的“脈衝”之間肯定都會存在“同步”的差異,但是必須有這樣一個“同步脈衝”,使得這些代碼能夠組合為一個整體。當項目組堅持每天把這些不同的“脈衝”組合到一起的時候,開發人員脫離整體的情況就會得到極大程度的杜絕。
有些項目組把這一過程簡化為“每周build一次”。這樣帶來的問題是,某一次build失敗後,可能要回溯好幾周才能找到原因。如果這種情況發生的話,已經得不到經常build帶來的好處了。
2、嚴格檢查每一次build
要保證每一次build的成功,就必須保證build後的結果(也可稱為build)是可以正常啟動並執行,如果build不可運行,那麼本次build被認為是不成功的,同時應該將修複此次build的工作提高到項目組最進階別來處理。
對於如何衡量一個build,每一個項目組都會定義一些自己的標準,這些標準需要設定一個嚴格的品質層級來處理那些特別嚴重的缺陷,同時也需要具有一定的伸縮性來忽略掉那些微不足道的缺陷,一些不適當的關心也許會使整個過程舉步為艱。
一個好的build起碼應該具備以下條件:
●能夠成功編譯所有的檔案、庫,以及其它相關組件;
●能夠成功連結所有的檔案、庫,以及其它相關組件;
●不能存在任何使得系統無法運行或者運行出錯的進階別故障;
●當然,必須通過煙霧測試 (Smoke Test)
3、每天進行煙霧測試 (Smoke Test)
煙霧測試 (Smoke Test)應該是對整個系統流程從輸入到輸出的完整測試。測試不必是面面俱到的,但是應該能夠發現系統中較大的問題。煙霧測試 (Smoke Test)應該是足夠充分的,通過了煙霧測試 (Smoke Test)的build就可以認為是經過充分測試、足夠穩定的。
不進行煙霧測試 (Smoke Test)的build是沒有太大價值的。煙霧測試 (Smoke Test)就像一個哨兵,在阻止著產品品質惡化和整合問題的產生,不進行煙霧測試 (Smoke Test),每日構造可能會變成浪費時間的練習。
煙霧測試 (Smoke Test)必須隨著系統的擴充而擴充。最初,煙霧測試 (Smoke Test)可能是非常簡單的,比如驗證系統是否會列印“Hello World”,隨著系統功能的擴充,煙霧測試 (Smoke Test)需要越來越充分。最初的煙霧測試 (Smoke Test)也許只需要幾秒鐘來執行,逐漸地,測試可能會花費30分鐘,1小時,甚至更長。
4、建立一個專門的build小組
在很多項目組,維護每日構造,並更新煙霧測試 (Smoke Test)用例,會耗費一個人工作的大部分時間。因此在一些大的項目中,這項工作獨立成不止一個人來完成的全職工作。比如在 Windows NT 3.0的研發中,就有一個由四個全職人員組成的專門的build小組(Pascal Zachary, Showstopper!, The Free Press, 1994)。
5、為build增加修訂,如果這樣做有意義的話
一般開發人員不會每天都經常向系統中快速的增加實際的代碼,通常是每隔幾天,他們在開發好完成某個功能的一套代碼以後,然後整合到整個系統中。
6、規定一些導致build失敗的懲罰措施
很多執行每日構造的項目組都會規定一些懲罰措施,來懲罰那些導致build失敗的行為。從最開始,項目群組成員就清楚的知道,build的正常執行是項目組的頭等大事。一個失敗的build是項目組的意外,無法成為項目組工作的準則。必須堅持:導致build失敗的同事,必須停下手中的工作,首先來解決build失敗的問題。如果一個項目組的build經常失敗的話,久而久之的,再來談build的正確性就沒有意義了。
有種輕鬆的懲罰措施,能夠突出解決問題的優先性。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. 有些項目組會懲罰犯錯的同事戴上山羊角,或者向一個項目基金捐獻5塊錢。
有些項目組對此的懲罰就有點殘酷了。微軟的開發人員,在一些知名度很高、很重要的產品如Windows NT,Windows 95,Excel等產品後期研發中,被要求隨時帶著呼叫器,如果你的代碼導致build失敗的話,即使是淩晨3點鐘,也會要求你立即來處理這個問題。
7、即使在壓力下也需堅持每日構造和煙霧測試 (Smoke Test)
當項目進度的壓力越來越大時,維護每日構造的工作看起來有些浪費時間,但是恰恰相反。在壓力之下,開發人員丟掉一些平時的規定,會採用一些設計和實現的捷徑,這在平時壓力較小的環境下一般時不會用的。代碼的review和單元測試也可能會比平時粗心一些,這些代碼的狀態變化也會比平時快很多。
為防止這種情況的出現,每日構造會堅持相關的規定,讓壓力下的項目保持在正軌上。代碼仍然每天在不斷變化,但是構造過程使得這種變化每天都可控。
誰能夠從每日構造這種過程中得到好處呢?一些開發人員會抗議說,由於他們的項目太大,每天進行build是沒有實際意義的。但是為什麼現在最複雜的軟體項目組卻能夠成功的執行每日構造的制度呢?本文首發時,Windows NT包括了560萬行代碼、分布在4萬個來源程式檔案中,項目組仍然可以堅持每日構造。