早些年開發軟體,一個版本釋出上線的時間週期是以“月”甚至“年”為單位計的,但是現在隨著敏捷開發的推行和普及,版本上線的週期變成了“周”為單位,甚至更短。週期縮短,並不意味著要犧牲質量,而是一樣會有完善的開發流程來保障質量,比如設計、開發、自動化測試和手工測試。但是當縮短開發週期的時候,可能原本執行好好的開發流程就會出問題,軟體質量下降,需要去重新調整開發流程,以重新做到高效和穩定。
在這裡將向您分享一下我所在團隊的經歷,我們從兩週一個釋出週期,到每週一個釋出週期,都遇到了什麼問題和挑戰,最終如何克服和解決的。希望能對您有所幫助啟發。
在兩週一個版本的迭代中,我們是進行專案開發的?
開發流程
在這裡先簡單介紹一下,我們兩週一個Sprint的開發流程是什麼樣的。整個開發流程如圖所示:
Sprint計劃和部署上一版本到生產環境
每個Sprint開始前,會先有一個計劃會議,規劃好當前Sprint 要完成的新功能和要修復的Bug,這些任務都在Jira上用一條條Ticket記錄和跟蹤。
編碼和分支管理
在計劃好了後,緊接著是一整週的開發編碼,這期間會對計劃好的Tickets進行編碼。我們是基於分支開發的,在開發一個Ticket之前會建立一個新的分支,開發完成後將分支程式碼提交PR,程式碼稽核通過以及自動化測試完成後合併到git的master分支。
測試
在一週的開發編碼完成後,就會基於master的最新程式碼建立tag,併發布到測試環境。QA人員會對釋出的功能進行自動化測試和手工測試,發現的bug會提交ticket進行跟蹤。開發人員會對報的bug進行修復,修復bug的程式碼會繼續合併到master。
程式碼凍結
由於我們要部署的程式碼都在master上,如果master持續的合併程式碼會不太穩定,所以在Sprint最後兩天會對master的程式碼凍結,除非重要的bug修復,否則新的PR不合並,等到下一個Sprint開始再統一合併。
部署生產環境
在測試結束後,我們會根據版本建立release tag,這樣根據tag就可以部署對應的版本到生產環境。
兩週Sprint的優缺點
這樣兩週一個Sprint的週期在執行的時候還算比較順利,上線的版本由於測試較為充分,所以比較穩定。但缺點就是兩週才能釋出一個新的版本,響應需求的速度較慢;兩週一個版本,由於更新的程式碼較多,在上線後出現問題也不容易定位。
其實上面的開發流程還有一個問題,只是由於兩週一個迭代,並沒有暴露出來。這個稍後再討論。
在一週一個版本的迭代中,我們是進行專案開發的?
正是基於兩週Sprint的一些問題,我們決定改成一週一個Sprint,這樣就可以更高頻率的釋出新版本;釋出的版本變更較小,有問題也能及時定位和發現。
在最開始的時候,一週一個Sprint的開發流程和之前兩週一個Sprint的開發模式類似,只是把相應的開發和測試時間縮短了。如圖所示:
改成一週一個Sprint後遇到的問題和挑戰
但在變成一個週一個Sprint後,我們很快發現版本質量下降了,經常在上線後發現嚴重的問題而需要回滾或者打補丁。
於是在一次Retro會議(專案回顧會議)上,我們的QA提出了一個建議:“Avoid last minute change”。背景是我們的服務剛剛有過一次生產環境故障,故障的原因是因為開發在上線前有過一些改動,原以為改動很小,不會有問題,Code Review沒發現問題,部署到測試環境簡單測試後,也沒發現問題。結果部署上生產環境後,出現嚴重的問題。
這是個很好的建議,然而我們能避免上線前臨時修改嗎?避免了上線前的臨時修改服務就會穩定嗎?
在接下來的時間裡,我們努力避免上線前的臨時修改,上線前的修改需要更嚴格的程式碼審查流程,然而想完全避免上線前的臨時修改是幾乎不可能的,總有一些上線前才發現的問題需要修復。
那麼在減少了上線前的臨時修改後,我們的服務更穩定了嗎?
有一點改善,但並沒有完全解決,服務還是不太穩定,而且很多伺服器故障並不是由於上線前的臨時修改導致的!
這就說明上線前的臨時修改並不是導致服務不穩定的根本原因,那麼到底是什麼原因導致的服務不穩定?
於是我們又嘗試了一些探索和改進,比如說增加更多的自動化測試、上線後對主要功能做一些手動的檢查。這些方法都有一點效果,但都屬於治標不治本的措施,服務還是不算穩定。
是什麼原因讓服務不穩定
對於這個問題我一直沒有答案,直到幾個月後,又一年的“Holiday Readiness”,也就是美國的購物季,從萬聖節開始一直持續到新年,商家有各種促銷打折活動,民眾也是各種買買買。這期間對於我們這種線上消費類網站來說,穩定性要求特別高,當機一點點時間都可能造成巨大損失。
如何保證服務的穩定呢?根據我們過去幾年的血淚教訓中總結出來的經驗,保證服務穩定的最簡單有效的措施就是:節日期間不更新,除非必要的小更新和補丁!
所以在消費季,我們會實行“Soft/Hard Moratorium”,也就是“Holiday Readiness”期間,我們不上線新功能,只做必要的補丁更新以修復一些嚴重的線上故障。並且上線需要有嚴格的審批流程。
為了應對公司的“Soft/Hard Moratorium”策略,我們組也做了一些調整:
-
首先我們建立了一個holiday的branch分支,這個分支只修復生產環境的Bug或者必須的新功能更新。其他常規的開發依然放在master主分支。
-
然後每次holiday分支的修改在部署生產環境前,都預先在測試環境測試一週左右時間,測試沒問題後再部署生產環境。
這樣實施下來,在“Holiday Readiness”結束的時候,我發現我們的服務異常的穩定,雖然有過數次更新,但是一次故障都沒有發生。這給我很多啟示,讓我意識到之前服務之所以一直不穩定,有兩個主要原因:
原因一:沒有一個穩定的可隨時釋出的分支
首先,我們的版本釋出是基於master分支釋出的,新功能和Bug修復的PR都會合併到master,這就意味著master分支一直是不穩定的。
在以前每兩週一個Sprint的時候,這個問題就存在,只是當時因為測試時間更長,所以沒有暴露出來。當改成每週一個Sprint後,這個問題就很嚴重了,導致了很多上線前的臨時修改。
在“Holiday Readiness”期間,我們有一個穩定的holiday分支,這個分支只有bug修復,幾乎沒有新功能的程式碼,所以相對要穩定很多。
原因二:測試時間不夠充分
在以前每兩週一個Sprint的時候,我們有3-5天的時間測試,有大的問題問題基本上能在測試環境發現,當改成每週一個Sprint後,留給測試的時間只有1-2天,這點時間是很難充分測試的,所以很多問題要在上線後才暴露出來。
在“Holiday Readiness”期間,在每次程式碼修改後釋出前,在測試環境都會有一週左右的測試時間,這樣Bug就能得到充分的暴露,而不至於到生產環境才發現,而導致回滾或者補丁。
怎麼改善釋出流程?
既然已經發現了問題所在,怎麼去改進就相對容易了。所以我針對當前流程提出了一些改進的建議。
每個Sprint對應一個穩定的分支
對於沒有穩定分支的問題,很好解決,那就是在每次Sprint完成,我們都建立一個對應的Release分支,Release分支建立好後,類似於我們之前在holiday分支做的那樣,只做Bug修復,不增加新功能程式碼。
對於前面說到的上線前臨時修改,如果是緊急Bug更新,那麼放到Release分支,如果是其他的,則只合併到master分支,不會影響到release分支。
給測試留足時間
對於測試時間不夠的問題,一個簡單可行的方案就是回到兩週一個Sprint的開發方式。但是大家已經習慣了一週一個Sprint的節奏,尤其是產品經理,希望新功能能儘早上線,更喜歡保持一週一個Sprint。
那麼怎樣在一週一個Sprint的情況下,保證有充足的時間測試呢?
於是我提出了一個簡單可行的方案:在“Holiday Readiness”結束後,推遲第一個Sprint的上線時間一週。
具體做法是:我們的第一個Sprint完成後,不上線生產環境,在測試環境保留一週,同時開始第二個Sprint的開發,等到第二個Sprint開發完成後,上線第一個Sprint的版本,第二個Sprint的版本釋出到測試環境測試一週,同時開始第三個Sprint的開發。
如圖所示
這就意味著我們每一個Sprint開發完成,有完整的一週時間進行測試和Bug修復,但我們還是可以每週一個版本部署生產環境。
經過這樣的調整後,我們的服務馬上就穩定下來了,基本上不用擔心釋出後會有嚴重的質量問題,也極少需要上線後回滾或補丁。
當然這樣調整後,也帶來一些小的問題:
問題一:有兩個Sprint在並行
在當前Sprint開發的同時,還要對上一個Sprint的Bug進行修復。但一般Bug的修復都比較簡單,這樣並行並沒有帶來太多的問題,我們的開發人員對這種模式適應的很好。
問題二:多分支管理
由於每個Sprint都會建立一個分支,那麼意味著修復一個Bug,有可能要將修改同時合併到多個分支。
舉例來說,在生產環境發現一個問題需要打補丁,那麼這個PR要合併到生產環境版本對應的分支,還要合併到測試環境版本對應的分支,最後還要合併到master;如果在測試環境發現的Bug,需要同時合併到測試環境版本對應的分支和master。
不過相對於穩定性帶來的提升,這一點不便還是完全可以接受的。
問題三:開發過程不易理解
這個開發模式在我們組內部執行的很好,但是對於組外的人來說,不是很容易理解,對於他們來說,最關心的是:我的需求或者PR什麼時候能部署到測試環境,什麼時候能部署到生產環境。
於是我們開發了幾個工具,可以直觀的知道當前開發中的是在哪個版本,測試環境是哪個版本,生產環境是哪個版本。
(電視投影)
配合這樣的小工具,無論是組內還是組外,都可以很直觀的瞭解當前的開發狀態了。
總的來說,新的開發流程實行後,雖然存在一些小的麻煩,但是執行的很不錯,服務的穩定性大幅提升。release分支讓我們有一個隨時可以釋出的穩定版本;一週的測試時間可以很好的保證質量;同時每週一個版本的釋出頻率也可以讓我們及時響應需求,有問題能及時發現。
Chrome的開發流程
無獨有偶,後來我發現Chrome的開發流程,和我們現在的這套開發流程很類似,它是6周的開發流程,其中上一個版本的測試和當前版本的開發也是重疊的。
Chrome Release Cycle
總結
軟體工程中沒有銀彈,不可能有一種開發模式適用於所有的軟體專案。當專案發生變化時,以前一些執行的很好的開發模式可能漸漸的不適合了,這時候就需要先找出問題產生深層次的原因,然後對症下藥,探索出適合於當前專案特點的開發模式。