持續集成之“分支策略”
現代版本控制系統(SCM)的作用已不僅僅是保存歷史版本,它還是各軟件開發組織利用其分支功能實現多人并行開發,提高生產效率的一種工具。對于稍有歷史的軟件產品來說,一般都會有代碼分支的出現,也常常見到一些歷史悠久的產品其錯綜復雜的分支版本樹甚至將產品交付團隊拖入“無盡維護”的泥潭。分支的目的是希望“分而治之”,而持續集成的目的是“頻繁集成”,這二者之間又有哪些聯系呢?
在《測試三角形與分段構建策略原則》一文中,咱們說到:由于自動化測試時間較長,Joe的團隊實施了分階段的持續集成。雖然這么做引入了一些風險(比如因提交階段構建中的測試覆蓋面小而不能盡早發現代碼中問題),但提高了整個團隊的開發效率。而且,Joe會根據實際運行情況,在提交構建和次級構建之間不斷調整自動化測試用例集來緩解分階段構建帶來的風險。
現在,這個軟件游戲平臺的第一個版本已經接近完成,馬上就要進行內測了。團隊面臨的問題是:“如何做分支管理?持續集成該怎么做?”
一、短周期發布分支策略
今天是星期五。下班后,Joe和Alice等主要開發人員并沒有馬上回家,而是在一個小酒吧里聊天呢。
Alice說道:“現在我們一直使用主干開發方式,團隊所有人都工作在Trunk上,與之對應的只有一個持續集成環境。下星期就要做內測了,我們是不是應該拉一個測試分支,用于修復測試中發現的缺陷,在主干繼續開發新功能呢?一旦修復完內測缺陷的話,我們就可以在這個分支上進行發布,再把這個測試分支的代碼變更合并回主干。就像這樣。”她拿了一張紙畫了出來(如圖1所示)。
“好啊,好啊。我們分成兩個團隊,一個在測試分支上工作,修復內測過程中發現的缺陷;另一個在主干上工作,開發新的功能。”Bob回應道。
“對于拉分支做測試這件事,我沒有疑問。但是,我不同意最后再把代碼合并到主干上。”Joe說道。“我們一直在使用持續集成實踐,目的就是盡早集成。為什么要等到發布以后再將測試分支的代碼合并回主干,而不是每次修復一個缺陷就合并回來呢?每次缺陷修復的代碼變更不會太多,所以合并起來很容易。等到最后再合并,首先是容易漏掉一些代碼,其次是一次合并代碼太多,容易出錯。所以,我建議下星期拉分支時,為測試分支也建立一個持續集成環境。每次發現缺陷時,都為它寫一個測試,加到測試套件中。修復代碼提交后,就會觸發測試分支對應的持續集成構建。一旦構建成功,就將其合并回主干。”說完之后,他在Alice畫的那張圖上修改了一下(如圖2所示)。
- 拉分支之后,開發團隊可以繼續開發新的功能。而測試團隊可以單獨對分支進行測試、部署,不受開發團隊的影響。
- 一旦測試中發現問題,開發人員要在該分支上修復。
- 在分支發布之后,一旦發現了嚴重問題,僅在該發布分支上修復后即可發布補丁版本。
- 在分支上做修改后,就要根據實際情況進行分析,是否要合并回主干。如果需要合并,應該立即進行。
“那由誰來負責把發布分支中的Bugfix合并回主干呢?”
“當然是由Bugfix的人來負責了,他是確保合并正確性的關鍵。如果Trunk上的代碼已被修改,無法合并,Bug負責人就要與主干開發人員交流,這個Bug在主干的有效性,然后再決定是否修改,在哪里修改的問題。”
“我們要對發布分支上的Bug定義修復標準,盡量在Trunk上修復Bug,除非這個Bug嚴重影響發布質量。這樣可以避免無休止地在發布分支上做代碼修改。這樣,Bug數才會收斂,發布分支的活躍期才會縮短。”
“嗯,相對于我們一直使用的主干開發方式來說,這種短發布分支策略的成本是:
- 需要多套獨立的持續集成環境。即每個分支在處于活躍期時,要有與之對應的一套持續集成環境,以便不受影響。
- 每次發布分支上修復缺陷后,只要分支對應的持續集成構建成功,就要將其合并回主干。
- 由于主干開發的代碼可能因架構改進使原有缺陷不復存在,所以每次合并時都需要人為判斷一下合并的必要性。”
二、長周期發布分支策略?
“哦,我之前工作的一家公司,就是用這種分支策略。”Bob說道,“但情況變得非常復雜。版本滿天飛,想做合并都不容易。”
Joe說道:“我想,可能是因為他們的客戶不想升級版本,所以必須在已發布的版本上再發小版本吧?”
“的確是這樣的。”Bob回答道,“他們的發布周期大約是半年。由于已發布的版本質量不佳,所以總是有緊急修復的版本上線。另外,客戶比較擔心新版本的穩定性,所以只要滿足自己的當前需求,就會一直使用舊版本。有些大客戶還會要求公司開發針對其自身的特別需求,并快速上線,結果可想而知。”
Alice說道:“其實,這已經是短周期發布分支的變形,即有多個活躍分支的長周期發布分支策略(如圖3所示)。這種分支策略是應該盡量避免的,它的復雜性和維護成本都很高,因為:
- 每次都要把缺陷修復代碼合并到后續的多個發布分支上,尤其是當該缺陷發生在較老的版本,而當前已有多個活躍版本需要維護時。
- 隨著時間的推移,每個分支上的自動化測試用例增多,更多的分支會對持續集成環境中的測試機數量的需求快速增加。
- 發布周期長誘使團隊在已有的發布分支上再做子分支(如圖3中的R1.1),這會讓集成和驗證工作變得更加復雜(如圖3中從R1.1到R2.0的Cherry Picking操作表明:需要向多個分支上合并部分代碼)。
- 由于每個活躍分支都要對應一個持續集成環境,因此,分支越多,對持續集成環境的維護成本也就越高。
Bob問道:“有什么辦法避免這種糟糕的多活躍分支開發策略嗎?”
“辦法當然有,但不能解決所有問題。”Joe回答道,“比方說,首先,要確保每個版本的開發質量,讓客戶放心升級。其次,軟件產品要支持自動升級。在通常情況下,只要滿足需求,用戶就不會輕易升級軟件。所以,要讓軟件具有自動發現新版本并在后臺自動升級的能力。當然,在升級后要通知用戶。這樣,只要將新版本發布到互聯網上的某個服務器上就行了。最后,也是最重要的一點,新版本發布周期要短一些,不斷快速地推出新特性,這樣就可以讓用戶對產品及研發團隊有信心,讓客戶感覺他們的需求很快就會被滿足。”
“對于那些企業用戶來說,這種方法可能不管用。因為,企業內網很少可以連通外網。”Alice說道。
“如果是這種情況的話,除了軟件本身質量好且能自動無縫升級以外,在銷售時可以與客戶簽訂協議,告知所售軟件版本的生命周期(比如18個月)以及升級條款,促使企業升級該軟件,比如免費的大版本升級,或者因缺陷原因可免費升級等等。”Joe回答道。
“嗯,我們開發的是游戲軟件平臺,部署在互聯網上,所以不會遇到這個問題。”Alice說道。
Joe微笑著說道:“我們將會面臨另外一種問題,即多個小團隊開發不同的游戲組件問題。”
“哦,對了!現在我們的游戲平臺中雖然僅有幾個游戲,目前還一起在主干上開發。但在下一版本中,我們會增加大量的游戲組件,那應該如何應對?我們的持續集成環境應該是什么樣的呢?”Alice大聲地問道。
“嗯,是個好問題!”Joe回答道。“我已經有了一些想法。我們內測結束后,再詳細討論吧!時間也不早啦,大家回去休息吧,周末愉快!”