4種常見分支模式解析及優劣對比
簡介:團隊研發的本質並不是團隊規模越大,研發的效率就越高。我們以為團隊規模越大,研發效率就會越高,可以做越多的東西,但是我們發現團隊規模大到一定程度,整個研發效率是會下降的,甚至降得非常快。為什麼團隊的規模越來越大,我們的釋出反而越來越慢了?
策劃&編輯|雅純
團隊研發的本質
這個時候悖論就來了:我們以為團隊規模越大,研發效率就會越高,可以做越多的東西,但是我們發現團隊規模大到一定程度,整個研發效率是會下降的,甚至降得非常快。
以下是兩個具體的場景。
第二種情況,多個分支往同一個分支合併,FeatureA先合進主幹,FeatureB晚了一點結果發現無法合併,因為基線不一樣了,這時候必須先解決掉程式碼衝突才能合進去。
我們發現,程式設計師和程式設計師,測試人員和開發人員之間,在整個的開發協作中其實是非同步的、延遲協作的過程。每個人並不是收到一個請求就馬上回復,馬上協作,往往都是有自己的步調和自己的動作,可能會產生延遲。所以當產品更復雜,協作更多,團隊更復雜,團隊的人多了以後,協作成本就會快速上升。
在這樣一個非同步的、延遲協作的過程中,程式設計師面對日常開發的工作,需要有一套相應的研發模式,來保證在協作過程中能夠持續地把資訊同步掉,並快速地響應掉。
軟體交付過程,本質是開發者圍繞程式碼庫的協作過程。無論是產品程式碼、配置、環境和釋出流程,都可以通過程式碼來描述,並儲存到程式碼庫裡。
因此,研發模式的目的就是約束我們在圍繞程式碼庫工作時的行為,本質是一種圍繞程式碼庫的行為約束。
研發模式我們狹義地理解為分支模式,包含一系列的行為約束,比如分支型別及其標識、分支的生命週期、Commit在分支間的流轉方式,以及流轉的約束條件,還有分支和程式碼之間的對應關係等。接下來我們會一一探討。
研發模式是一系列研發行為的約束,目標是避免衝突、減少等待。在協作的過程中,人多了之後帶來的最大的問題就是衝突變多、等待變多,所以好的研發模式應該儘可能的避免衝突,儘可能的減少等待。
首先看一下研發模式和研發行為之間的對應關係。
同樣地,整合完進入待發布也是在做Merge,而完成釋出意味著打一個Tag。程式碼庫裡的操作記錄了我們的研發行為,所以研發行為和程式碼庫的操作可以做到一一對映。
要減少等待,而等待是資訊不同步造成的,儘可能地做到資訊同步,就不用等待。在程式碼裡面的等待,是程式碼之間基線的同步,比如說頻繁地提交。所以其實分支是用來避免衝突和做工作隔離,而頻繁地提交合並是為了做資訊同步,減少等待。
Q:如果是一個人做軟體開發,用什麼樣的分支模式?一個人會不會有衝突?
一個人做軟體開發的時候是不會有衝突的,一個人工作的時候不需要很多分支,一個分支就足夠。一個人做開發,也不用等待資訊,因此可以一條主幹走到底。但是如果人數擴張到10人、100人,彼此之間就會有工作的隔離,彼此之間也會存在著衝突,也存在著等待。所以在這個過程中,隨著協作的人數越來越多,分支的模式會不斷地發生變化。
4種常見分支模式解析
主幹開發
主幹開發方式一條主幹分支走到底,開發的過程中不會有太多的衝突,要求程式碼持續整合到主幹上去,所以在開發過程中不需要做相應工作的隔離。開發的過程中,所有的開發者在主幹上面頻繁地提交,頻繁地整合。這種分支模式下,唯一的分叉出現在釋出的時候,為了能夠把釋出版本隔離出來,有了釋出分支。
這種模式下,不需要做分支隔離,資訊同步通過持續頻繁地提交來保證。在人數比較少,並且整個工程能力比較強的時候,這是我們推薦的研發模式。
但是當參與開發的人數越來越多時,主幹開發的衝突機率就大大增加了,對工程能力的要求也越來越高。
所以說主幹開發不是萬能藥,主幹上的人越多,程式碼提交的衝突機率就越大,而且解決衝突的風險也越大。如果兩個人的時候,即便有衝突我知道只是和另外一個人有衝突,如果是10個人,這中間就會產生很多的問題。
另外在主幹開發裡面,要保持資訊地同步,需要做頻繁持續地提交,而且每次提交的力度要很小,這針對有一些特性來說,可能只做了一半,這時需要將它提交上去,需要通過特性開關等方式來進行隔離。比如說這個是還未完成的特性,提前把它的開關製成Off,再做相應的提交,但是特性開關本質上也是一個分支。
特性開關只是用程式碼的形式拉了一個分支,但是這個分支只有開啟的時候才能跑到,本質上還是一個分支。如果特性開關比較多,它在一定程度上會把程式碼變得很脆弱,維護起來比較麻煩。
主幹開發當很多人同時參與時,程式碼衝突的機率很大,而且特性開發的時候也有很多的風險,大家彼此之間需要隔離。
Git-Flow
比如說feature分支,是很多個feature並行開發的時候用來去做工作隔離,避免彼此之間有衝突。而release分支是用來做釋出的隔離,使得釋出之間不會有衝突。
我們發現這種模式很好地做了隔離,但是在資訊同步的過程中,它需要基於develop頻繁地整合去做同步,並且在各個分支中間做相應的cherry-pick或者是rebase這樣的方式來做的。
這個時候,我們就會發現分支太多,而且一個commit從feature開發到最終釋出要經歷好幾個分支,其中分支的流轉和merge規則非常麻煩。
所以Git—Flow也不是仙丹,過多的分支增加了分支管理的複雜度。還有如果Feature分支的生命週期特別長,它的合併耗時也會變得很長。而且Develop分支和Master分支同時存在,好像Develop分支的意義不是特別大。另外區分Feature分支和hotfix好像意義也不是特別大。
所以Git—Flow雖然增加了很多的分支,讓各種工作儘可能地隔離開來,但是它資訊同步是很麻煩的,而且它管理這些分支的難度也特別大。
GitHub-Flow
這個過程中,它的隔離只發生在開發過程中,它的資訊同步通過持續地往Master去做整合,和頻繁從Master裡面Pull程式碼來實現。它的釋出過程是基於主幹Master分支做的,因此沒有在釋出的過程中做相應地隔離。
這時候又會帶來一個問題,就是Master分支需要做持續整合,這個分支既是整合的地方也是釋出的地方。一旦整合後出現問題,它會把所有的工作堵塞掉,無法釋出也無法合併。
所以GitHub—Flow很簡單,可以做相應地隔離,但是如果說本身基礎設施或工程能力比較弱,它會限制你整合和釋出的頻率。
GitLab-Flow
完成整合以後是在Master分支上,下面一步將會切換到預發分支上。對應Commit的版本已經達到了預發的條件,在預發上做完驗證以後再將其同步到Production分支,說明它已經達到了釋出的條件,所以它是逐級Promotion(晉級)的過程。逐步從整合的環境Promotion到預發環境,再Promotion到生產環境。
我們簡單地介紹了一些常見的分支模式,下面我們再來比較一下他們之間的優劣。
常見分支模式優劣對比
Git—Flow特性之間可以並行開發,規則很完善,每個分支的職責特別明確,再大的團隊協作基本上也不會有太多的問題,但是它分支太多,規則太複雜,而且分支生命週期長,合併衝突會比較頻繁。尤其是Develop,Master是長期存在的。
對於GitHub—Flow,Git—Flow能支援的基本上它也能支援,但是這裡面有一個問題,它的整合只有在Master分支去做,因此對整合紀律有很高的要求,而且整合和釋出在一個分支上,一旦整合分支中斷,無論是整合還是釋出都會被中斷。
Gitlab—Flow也是並行開發,但是開發分支還是會有生命週期長的問題,有合併衝突的風險。另外,釋出分支之間是有耦合的,比如說Prodution和Pre—Prodution之間,是基於Promotion來耦合,所以彼此之間也是一種中斷阻塞的方式,而且很多的開發分支,Prodution和Pre—Prodution,也增加了分支管理的複雜性。
因此,我們發現沒有哪個分支模式是絕對好的,也沒有哪個是絕對差的。
對於分支有一個簡單的原則,即控制分支數目,小批量頻繁整合。控制分支的數目也就是做到工作隔離,但是又增加太多管理成本。而小批量頻繁整合可以加速資訊同步。
所以一個簡單的原則就是,從最大化生產力和最小化風險的角度,儘可能地控制分支的數目和小批量頻繁整合。
最大化生產力:所有人工作在公共區域內。除了一條長期的,不被中斷的開發主幹外,沒有任何分支。也並無其他規則,程式碼的提交過程相當簡單。但是,每一次的程式碼提交,都有可能破壞整個專案的整合,進而導致專案進度的中斷。
最小化風險:所有人都工作自己的分支上。每個人的工作是相互獨立的,沒人可以打斷其他人的工作,這樣,減少了開發被打斷的風險。但是,這種做法卻增加了額外的流程負擔,同時,協作變得非常困難,所有人都不得不謹小慎微地合併自己的程式碼,即便是整個系統中非常小的一部分,也是如此。
那麼怎麼設計或選擇適合自己的分支模式?下一篇文章,我們將繼續分享,不同的團隊如何選擇適合自己的研發模式。
本文為阿里雲原創內容,未經允許不得轉載。