天天看點

阿裡在使用一種更靈活的軟體內建釋出模式相同點不同點及其主要價值另一方面的價值弱點和風險落地及工具支援相關閱讀:

阿裡在使用一種更靈活的軟體內建釋出模式相同點不同點及其主要價值另一方面的價值弱點和風險落地及工具支援相關閱讀:
掃描上述二維碼或點我直達 免費領!
作者:董越(花名荷鋤),阿裡巴巴研發效能部進階産品專家

當今典型的軟體內建釋出模式是,通過類似GitHub的Pull Request或GitLab的MergeRequest的方式管理特性分支(Feature Branch):在通過代碼評審等方法确認一條特性分支上的改動沒問題後,将其合入內建用的分支。随後,代碼改動進入在內建分支上運作的持續傳遞流水線,直到釋出上線。

在阿裡巴巴内部,盡管這種工作方式也得到了研發協同工具平台(Aone,對外叫雲效)的支援,但廣大研發同學選擇的主流工作方式卻不是它,而是用一種被稱之為變更(全稱變更請求,英文Change Request)的對象來管理特性分支,直到釋出。

初看起來,變更與Pull/MergeRequest有不少相同點,但實際它們在理念上的差别很大。

本文詳細介紹它們的相同點和不同點,并探讨使用者喜歡變更這種方式的原因,當然也會介紹相應的風險和弱點。或許閱讀本文,能給你帶來一些思考。

相同點

  • 變更與Pull/MergeRequest的相同點主要在于對特性分支本身的品質和流程的控制:
  • 一個變更,就像一個Pull/MergeRequest一樣,大體上對應一條特性分支。
  • 在Pull/Merge Request中,可以看到這條特性分支上代碼改動内容,進而進行代碼評審(Code Review)。類似的,也可以以變更為粒度進行代碼評審。
  • 在特性分支上的代碼送出,可以自動觸發持續內建工具做建構以及各種自動檢測,其結果可以在Pull/Merge Request中展現。類似的,在變更中也可以展現。
  • 可以把Pull/MergeRequest上的最新代碼建構部署到它專屬的測試環境并運作,以進行測試和調試。在變更中也可以這樣做。
  • 在Pull/Merge Request中可以設定通過的條件,比如至少兩名評審者同意,且所有的代碼評審中發現的問題都已修複或澄清,且特性分支上的持續內建流水線運作成功。在變更中也支援類似設定。

不同點及其主要價值

變更與Pull/MergeRequest的不同之處關鍵在于,這個特性分支與其他特性分支一起內建和傳遞的方式。

對于Pull/MergeRequest,随後把特性分支合并到內建用的分支,然後就沒有然後了。哦不,是然後就不再以特性分支為粒度去管理了。這條特性分支已經合入內建用的分支,其上的代碼改動已經融入內建釋出的洪流之中,被裹挾着和其他特性分支上的代碼改動一起前進,去闖關通過內建-釋出的各個階段(Stage)。

而變更不同。即便是已與其他變更內建,它仍然具有一定的獨立性和靈活性,在确有必要時,可針對單獨變更進行操作。下面我們通過兩個例子來詳細介紹。

第一個例子:簡化起見,假定內建傳遞過程有三個階段:日常內建測試、在預釋出環境測試、正式釋出。某應用的變更A到變更E共五個變更,在通過了日常內建測試這個階段後,進入了在預釋出環境測試這個階段。測試時,發現變更C有一個缺陷。這個缺陷因為受日常測試環境所限,在日常內建測試階段沒有暴露出來。經分析,變更C與其他四個變更間沒有依賴關系,不會互相影響。是以,為了讓其他四個變更的釋出盡量少受影響,決定把變更C從在預釋出環境測試這一階段中摘除出來。其他四個變更在一起再次測試驗證,此時該缺陷不再出現,這四個變更在一起通過了在預釋出環境測試階段,進而進入正式釋出階段,釋出上線。

阿裡在使用一種更靈活的軟體內建釋出模式相同點不同點及其主要價值另一方面的價值弱點和風險落地及工具支援相關閱讀:

在這個例子中,在摘除了變更C後,沒有将其他四個變更在一起再次經過日常內建測試階段,是出于兩方面考慮:一是,此時的日常內建測試環境,已經被若幹新添的變更所占用。它們的測試需要時間,而且可能也會反複調整。把新添的變更趕出去,或者把這四個變更和新添的變更混在一起,或者讓着四個變更等着,都分别有明顯的不利之處。另一方面,A、B、D、E四個變更,它們與變更C在一起,已經通過了日常內建測試。而變更C又與它們無關,是以對它們再次進行日常內建測試,發現問題的可能性很低。測試是要講究成本效益的,而不是一味追求保證産品零缺陷。出于以上原因,在具體實戰中,開發團隊就有可能根據當時實際情況,在評估後決定,在摘除了變更C後,不再将其他四個變更在一起送回日常內建環境,而是直接在預釋出環境再次測試。

第二個例子:仍假定內建傳遞過程有日常內建測試、在預釋出環境測試、正式釋出三個階段。某應用的變更A到變更E共五個變更,在通過了日常內建測試這個階段後,進入了在預釋出環境測試這個階段。此時,根據市場情況變化,需要對變更C所承載的新功能做出少量調整,比如頁面說明文案上改幾個字。考慮到新的修改與變更C原有内容要麼都釋出,要麼都不釋出,是以為便于管理,新的修改就在變更C所在的特性分支上完成。這樣形成的變更C的最新内容,與其他四個變更在一起,在預釋出環境進行測試,通過後正式釋出。

阿裡在使用一種更靈活的軟體內建釋出模式相同點不同點及其主要價值另一方面的價值弱點和風險落地及工具支援相關閱讀:

以上兩個例子,是在傳統的內建-釋出方式基礎上,加入了一些靈活性:內建-釋出過程中,必要時可以中途撤下變更,可以中途修改完善變更。而有些團隊在使用變更時,采用了更進一步的方式:不再設內建工程師之類的角色,不再規劃統一的內建、釋出的計劃和時間點。而是每個開發同學負責自己的變更,不僅跟蹤它直到把變更的品質提升到可內建的程度,而且由開發同學自己把他負責的變更依次适時推入(也可能是自動進入)內建-釋出的各個階段,跟蹤它直到釋出上線。也就是說,盡管進入了內建-釋出階段,各個變更仍是被各自的開發者分别跟蹤和推進的:它們可能有各自的推進速率和節奏,而不會互相拖累。彼此無關的變更,隻是碰巧一同使用某個測試環境,一同批量測試以提高測試效率、一同上線以避免排隊而已。據此,盡可能縮短了一個需求從開發到釋出上線的時間,并表現為相當頻繁的釋出上線。同時也契合了DevOps的理念:“誰開發誰運作”(You build it, you run it)。

這一變化趨勢其實和軟體研發的管理實踐中發生的事情類似:瀑布模型時代就不提了。随後疊代方法取代了瀑布模型。典型的,Scrum方法中的Sprint。而更進一步,在精益方法的看闆牆上,疊代被弱化,關注的焦點從每個疊代做什麼,每個疊代進入到什麼階段,演化為關注每個在制品流動到了哪個階段,以及每個階段包含的在制品總量。

類似的,在上述變更管理方法中,從關注某個內建版本進入到內建-釋出的哪個階段,演化為關注每個變更進入到內建-釋出的哪個階段,以及每個階段包含了哪些變更。

另一方面的價值

以上,介紹的是使用變更管理方式帶來的靈活性,以及因為靈活務實而帶來的效率提升。變更管理方式,在資訊記錄和跟蹤方面還有一些的好處:

要想友善地知道,本次測試、本次釋出,到底包含了哪些特性,隻要看看包含了哪些變更就好了。變更本身有說明文字,變更還可以關聯需求、任務、缺陷等工作項,更詳細地說明變更的目的。而在變更之外,也沒有别的代碼修改可以通過直接送出到內建分支等途徑溜進來。

而從變更的視角,這個變更相關的所有改動,都在該特性分支上,而不會因為多次回報修改而散亂到各處。是以這些修改總是可以友善地一同檢視,一同操作。同時,總是能夠清晰地知道這個變更的狀态,它到了哪個階段:開發完畢了嗎?進入日常內建測試階段了嗎?已經正式釋出了嗎?等等。

變更可以關聯需求、任務、缺陷等工作項,同時變更的狀态是可以自動擷取的。是以,看闆牆上跟蹤的工作項,從原理上就可能被自動移動,以反映其實際狀态。協作和進展,在看闆牆上一覽無餘。

弱點和風險

以上談的都是這樣的變更管理方式能帶來的好處。那麼,它有沒有弱點和風險呢?

是的,它有。從大爆炸式內建到持續部署流水線,業界幾十年來幾乎一直在采用一個基本模式:總是一個內建版本,去順序經曆內建-釋出的各個階段。這樣可以保證,下一階段收到的内容,總是精确的經過了上一個階段的檢驗。而本文介紹的變更管理方式所引入的靈活性,意味着颠覆了這一基本模式。靈活性從來都是雙刃劍。靈活性意味着風險增加,意味着可能被濫用。

靈活宣言認為“個體和互動高于流程和工具”,上述變更管理方式暗合了這樣的思想。但在實際使用該方式時,需要注意到它對團隊成員提出了更高的要求:要求他們在具體場景具體案例中,能夠對變更間的相關性及相應風險做出評估,并了解不同選擇對效率的影響,最終綜合做出特定場景特定案例中的決策。具體來說:

  • 變更對應的代碼改動越少,中途撤下變更帶來的風險越小。
  • 中途修改完善變更所對應的代碼改動越少,帶來的風險越小。
  • 軟體架構越好,變更中途撤下或修改完善帶來的風險越小。
  • 本次變更與其他變更的相關性越小,中途撤下或修改完善帶來的風險越小。
  • 越緊急,越考慮靈活處理。
  • 業務角度,對軟體品質的要求越高,就越不要考慮靈活處理。

延伸一下,事實上,在微服務甚至函數服務時代,即便不使用上述變更管理方式,也有類似上文的風險,也相應需要團隊成員具備類似上文的自主判斷能力。為什麼這麼說呢?

之是以把單體應用拆分為微服務甚至函數服務,一個重要原因就是為了每個服務能單獨測試和釋出上線。然而,在使用微服務甚至函數服務方式時,被測對象嚴格地講并不是一個服務,而是該服務以及測試環境中與其直接或間接打交道的所有其他服務。而當把每個服務單獨測試和釋出時,就經常會導緻本階段測試時某個其他服務的版本,與下個階段測試時的版本不同,或者與将來正式釋出運作時的版本不同。于是就意味着類似上述變更管理方式中的風險。

相應的,這裡面就需要人來判斷(當然可以有智能算法的輔助),本次哪些服務上的改動務必要一起測試和上線,而另外幾個服務上的改動可以單獨運作。而下次可能又是不同情況,要根據下次的具體情況判斷。

由此看來,“總是由一個內建版本,去順序經曆內建-釋出的各個階段”這個基本模式,其實已經被悄然突破了。上述變更管理方式,隻是使這個突破更加明顯了而已。

落地及工具支援

以上是介紹了一種獨特的變更管理方式,介紹了優點,也介紹了相應的風險。下面我們來看看它在阿裡是如何落地的。

首先需要一套分支方案來支援它。大體上是這樣:

  • master分支總是代表最新已釋出版本。
  • 代碼改動總是在特性分支上完成。特性分支總是從master分支上拉出的,并在必要時從master再次同步。
  • 沒有一條長期存在的內建釋出用的分支。而是內建釋出過程的各個階段,各對應一條短期的,被自動管理的內建釋出分支。從master分支自動拉出該分支,再把各特性分支自動合并到該分支(出現沖突時人工介入),于是它上面就有了使用者想要的各特性。
  • 如果發現某個特性需要進一步修改完善,在特性分支上完成,并再次合并到相應的內建釋出分支。

在阿裡,我們如何管理代碼分支?

》這篇文章對上述分支方案有更多介紹。

雲效 > 使用指南 > 持續傳遞 > 開發模式 > 分支模式

》這篇文檔是該分支方案的詳細說明。

可以看出,這套方案,對工具平台的要求是比較高的:從界面角度,使用者隻需要管理各個內建釋出階段分别要有哪些變更。而工具平台要将它映射為對內建釋出分支的管理,包括建立新分支或複用已有分支、從各特性分支到內建釋出分支的合并等等。這裡面也包括了不少算法,以盡可能減少相同的合并沖突重複出現。

對工具平台的高要求,或許是這套方法多年來一直隻是在阿裡巴巴内部被廣為使用的原因。

不少曾在阿裡巴巴工作過的同學,出去後都念叨着沒有這樣的工具支援了。不過現在好了,就像Google基于内部的Borg對外提供了Kubernetes,阿裡巴巴也基于内部研發協同工具平台Aone對外提供了

雲效

的公有雲版和專有雲版,都提供了上述方法的完整支援。不論是你對上述方法抱有興趣還是懷有疑慮,都可以嘗試研究一下。

相關閱讀:

在阿裡,我們如何管理代碼分支 在阿裡,我們如何管理測試環境

繼續閱讀