團隊的 GIT 分支管理策略 (3) : 持續整合以及相關比較

fin
嗨,世界
Published in
8 min readMay 29, 2020

Patterns for Managing Source Code Branches 系列:

團隊的 GIT 分支管理策略 (1) : 基本概念
團隊的 GIT 分支管理策略 (2) : 主線整合與功能分支
團隊的 GIT 分支管理策略 (3) : 持續整合以及相關比較(本篇)
團隊的 GIT 分支管理策略 (4) : 發佈的分支模式
團隊的 GIT 分支管理策略 (5) : 其他分支模式

持續整合 Continuous Integration / Trunk Based Development

當開發者完成了一個健康的 commit 時,即進行主線整合,頻率通常低於一天

與功能分支的『一個功能一個分支』思路不同,持續整合關注在主線的健康度,只要主線仍然是健康的我們就可以持續的把 commit 整合到主線(無論功能是否完成)。核心原則是 每人每天都做主線整合 ,喜歡的話當然也可以每個小時做一次。

當然這代表著開發者需要注意如何在功能打造到功能一半時就讓這段程式碼上線,其中一個方法是 隱藏 關鍵介面 :直到功能完成之前使用者都沒有介面(這裡的介面指得是可以碰到未完成功能的任何方式)可以操作。或是使用 功能開關 :透過設定而非修改程式碼來決定功能是否開放,後者還能做到開放功能給部分使用者使用,適合用來作初期使用者測試。

持續整合會把未完成的功能直接暴露在正式環境下,因此測試變得很重要,讓我們有信心這個系統的功能都是正常的。就算未完成的功能也應同時提交相關測試,TDD 是個好方法

接下來,我們看看持續整合與功能分支的比較。

註一:持續整合的重點在於頻繁的主線整合,至於開發者要不要在自己本機端開功能分支其實一點都不影響,只要最後能夠以夠高的頻率整合回主線,那麼想開多少分支、想怎麼開都可以。 [關於持續整合可以看這篇更詳細的解說](<https://martinfowler.com/articles/continuousIntegration.html>)。註二:持續整合定義來說是需要大家持續的整合到主線,但因為許多人(包含以前的我)誤以為持續整合就是有個 CI 工具每次 commit 的時候幫你測試建置。所以後來有另一個名詞 Trunk Based Development 用來表示基於主幹的開發模式,其實基本上就是持續整合(原先的定義)。

功能分支與持續整合的比較

從前面的介紹來看,持續整合與功能分支最根本的差異在於整合的頻率。持續整合下開發者穩定的每天產出變更到主線上,而功能分支則要看功能切分的程度。如果團隊有辦法把功能都切分成很小的區塊,那麼就可以每天整合功能分支,這樣持續整合+功能分支一次滿足。但通常我們沒辦法做到這樣,而當功能切分得越大,開發時間越久,其整合間距就會拉得越久,與持續整合的差異就會越大。

無論是功能分支還是持續整合,當整合越頻繁時,整合的痛苦以及恐懼就會越少,開發進度也會更穩定。我們仍然可以把功能切分為數天甚至數週的工作,但只要有持續的想辦法(必備: 關鍵介面功能開關 )整合,持續整合就可以與功能開發脫鉤。

若要說持續整合有什麼缺點,可能就是成就感被分散,不會有功能分支下整合大功能到主線的大滿足感(越痛苦越有成就感,是吧?)。但相反的持續整個透過每日整合,讓我們實際感到進度的推進,雖然成就感降低了,卻也是一種持續的正向回饋。

功能分支另一個隱憂是容易忽略重構這件事,使用功能分支時多半較不熟悉『小而完整的變更』這件事情,而這其實是好的重構的核心,小步小步的替換結構。當不熟悉小而且頻繁的重構時,通常重構也容易變成一個分支單獨處理。而一般開發產品時,『功能』是比較歡迎的(就連『功能分支』的名字都看得出誰比較受歡迎),重構這件事情的優先序比較低,因此造成重構頻率減少、品質的持續下降。

持續整合下因為需要不斷練習小而完整的變更,更有能力把功能拆小,進而達到更快速的上線更快速地獲得回饋的效果,也能讓工程團隊以更貼近 MVP 的概念做開發。

最後來點數據佐證, State Of Dev Ops Report 每年的報告都不斷地顯示出,持續整合團隊具有較高的效能。

功能分支與開源

雖然說持續整合好棒棒,但對於開源專案,像 GitHub PR 這類明顯是為了功能分支所存在的機制還是有其必要。開源專案的變更有可能是由你完全不認識的人提交,你也不可能掌握對方的進度、接下來會處理的事項等。因此一次做完整的 PR ,後面接上負責小組的審查通常會是比較合理的選項。

對於一般產品開發團隊,成員之間無論熟悉程度、投入程度、對產品的責任都要高上許多,此時逐步往持續整合的方向走,才能提升整體開發效率以及整合穩定度。

(以此脈絡去思考,如果你的產品團隊成員彼此之間程度有落差,你會怎麼做呢?)

Reviewed Commit

每一個整合到主線的 commit 都要經過審查

功能分支有個小優勢就是最後審查時比較輕鬆,以 GitHub PR 為例,這機制本身就是為了審查新的功能分支用的,透過檢視 PR 內的變更,確保整體的程式碼健康度,而這也是目前比較主流的做法。由於審查需要來來回回的變動,這可能會讓一個 commit 超過一天完成,因此 Reviewed commit 與功能分支是比較常見的組合。(當然也不是沒有例外,只是需要比較多輔助工具

由於 Reviewed commit 容易拉長主線整合的時間,pair programming 相較之下有比較高的審查效率。

以主線整合來說基本的健康度一定是有的,後續修補主要會針對重構以及臭蟲為主,因此如果團隊對於重構很得心應手,直接主線整合後,發現問題再來修補是個更有效率的做法。這也延伸到下一個主題:整合阻力。

整合阻力

任何拖延 commit 整合至主線的流程都可以視為整合阻力,包含前一節的 reviewed commit,其來來回回審查的過程。這樣的阻力會讓人不想頻繁的整合,比較極端的例子是如果你每次回家都跟過海關一樣要通過安全檢查,你會想要常常經過那道門嗎?也因此,在持續整合的情境下,我們需要努力的移除這些阻力。

多數阻力來自人為的參與,比如說Code Review、QA 機制等,可以盡量透過自動化、部署流程調整、QA in production 等方式來移除。如有興趣,可以在許多 CI/CD 的內容裡找到許多讓整合流程更為順暢的作法。

除了實際上的阻力之外,成員們的技能、信心、態度也是影響阻力的因素。持續整合必需要成員互相信任他們可以做好這件事,且有能力可以做好。

模組化的重要性

稍微有經驗的工程師都應該要知道模組化的重要性,優點之一就是讓我們可以把變動限縮在依定範圍內,不用擔心一個小改動會造成系統大崩潰。無論哪種整合策略,模組化都可以帶來好處,功能開發如果限縮在相對應的模組中,就可以減少互相干擾的狀況,今天 Scarlett 與 Violet 開發不同功能,在沒有模組化的情況下功能被糾纏在一起的機率就會提高,就要處理互相整合上的問題;但如果已經模組化,兩個人就有可能直接修改完全不同的檔案,減少衝突的機率。

好的模組化也讓 關鍵介面Branch by Abstraction 這些事情比較好處理,我們只要專心處理一個一個的模組,或是模組與模組之間的連結,而不用什麼都管。

Feature Branching is a poor man’s modular architecture, instead of building systems with the ability to easy swap in and out features at runtime/deploytime they couple themselves to the source control providing this mechanism through manual merging.

— Dan Bodart

當然模組化講起來簡單,做起來跟持續整合一樣需要較高的技術能力,而其中持續的重構是讓系統架構越加穩固的關鍵,有足夠的重構能力,才有辦法在系統運行的同時讓系統更加模組化、更好維護。這背後牽扯到好的開發準則、熟悉設計模式、持續地學習的文化、程式碼品質的提升等等,這是一整串團隊產能提升的課題

整合模式小結

功能分支與持續整合比較表

上面為功能分支與持續整合比較表,其實沒有一定說哪種方式比較好,不同的團隊組成適合的模式不同,但如果想要讓整個開發更為順暢、效能更加提高,提升成員們的技術並且往持續整合的方向移動是比較符合邏輯的選擇。

--

--

No responses yet