從兩周發佈上線到一周發佈上線,如何做到高效穩定?

  • 2020 年 8 月 24 日
  • 筆記

早些年開發軟件,一個版本發佈上線的時間周期是以「月」甚至「年」為單位計的,但是現在隨着敏捷開發的推行和普及,版本上線的周期變成了「周」為單位,甚至更短。周期縮短,並不意味着要犧牲質量,而是一樣會有完善的開發流程來保障質量,比如設計、開發、自動化測試和手工測試。但是當縮短開發周期的時候,可能原本運行好好的開發流程就會出問題,軟件質量下降,需要去重新調整開發流程,以重新做到高效和穩定。

在這裡將向您分享一下我所在團隊的經歷,我們從兩周一個發佈周期,到每周一個發佈周期,都遇到了什麼問題和挑戰,最終如何克服和解決的。希望能對你有所幫助啟發。

在兩周一個版本的迭代中,我們是進行項目開發的?

開發流程

在這裡先簡單介紹一下,我們兩周一個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的周期在執行的時候還算比較順利,上線的版本由於測試較為充分,所以比較穩定。但缺點就是兩周才能發佈一個新的版本,響應需求的速度較慢;兩周一個版本,由於更新的代碼較多,在上線後出現問題也不容易定位。

||另外一個問題就是由於我們主要代碼都在master,一直有代碼合併進去,即使有代碼凍結,有時不是很穩定。||

其實上面的開發流程還有一個問題,只是由於兩周一個迭代,並沒有暴露出來。這個稍後再討論。

在一周一個版本的迭代中,我們是進行項目開發的?

正是基於兩周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

總結

軟件工程中沒有銀彈,不可能有一種開發模式適用於所有的軟件項目。當項目發生變化時,以前一些運行的很好的開發模式可能漸漸的不適合了,這時候就需要先找出問題產生深層次的原因,然後對症下藥,探索出適合於當前項目特點的開發模式。