關於DVCS、持續整合和特性分支

發表於2012-09-10

來源:喬樑,本文來自於持續整合英文站的文章《On DVCS, continuous integration, and feature branches》。

為了吸引大家的注意力,我想說:“特性分支是邪惡的化身”。

自2008年起,Mercurial (最近是Git)就成了我日常工作的工具,而且我喜歡使用分散式版本控制系統。正如《持續交付》一書中討論的那樣(英文版第393頁和394頁),有很多理由說明,與之前已存在的同類工具相比,DVCS(Distributed version control system)代表了一種巨大的轉變。但正如所有強大的工具一樣,你會有很多種方法來使用它們,但並不是所有的方法都是好的。這裡所有的討論不是想說DVCS不好:使用特性分支和使用DVCS完全是正交的。而且,我認為,DVCS的支持者用這種工具的功能分支來推銷DVCS,是對DVCS的一種傷害。

首先看幾個定義。請注意,一些人以不同的方式使用這些術語,所以你需要暫時從你的大腦中把先把其它的定義擦去,否則我的討論就沒有什麼意義了。

持續整合 是一種實踐,用於確保你的軟體一直是可以工作的,並且在幾分鐘內你就能夠得到關於 “你的修改是否破壞了系統”的反饋。

特性分支是一種實踐, 使用它的人直到他所開發的特性“完成”後才合併回主幹(這裡的“完成“不是“done done1”原則中的那個“完成”)。

主幹是指開發主線—— 通常是指版本控制庫中的。你的某交構建就是從這個主幹中的一個版本建立的,並會被放到你的部署流水線中。 注意,這些定義對DVCS和其它開源專案,甚至是GitHub,也完全適用。

先讓我們解決一個象稻草人一樣的爭論。當使用版本控制工具時,你就使用一個分支來工作:即本地工作目錄。使用DVCS,只是多了一個層次而已,因為你的本地庫就是一個有效分支。我並不反對建立分支。我所不贊同的是:讓你最終要釋出的程式碼在分支上堆積起來。
下面是我所看到的狀況。當你將最張要釋出的程式碼大量地堆積在分支上,會有幾個糟糕的事情發生:

● 這種狀態持續時間越長,就越難合併。因為隨著其他人向主幹提交,主幹的程式碼與你的分支上的程式碼之間的差異會越來越大。強大的合併工具的確會在一定程度上幫助你,但是任何一個做過很多開發工作的人都會有過這樣的經歷,即:程式碼的確成功合併了,但是應用程式執行不起來。隨著需要合併的那些程式碼數量的增加,以及初始分支與最終合併時間的增長,發生這種事情的可能性是遞增的,而且不僅僅是線性遞增。

● 在分支上的工作越多,在合併到主幹時越有可能破壞系統。每個人都有這樣的經歷:有個問題出現了,你似乎找到了一個非常聰明的解決方案。可是,幾個小時(或者幾天)後,你才發現需要廢棄所有的東西,或者(更常見地)那些引起未預期後果的程式碼提交。

● 當多個開發人員同時在這個程式碼庫上工作,並使用特性分支開發時,使程式碼重構變得很難。如果我重構並且提交到主幹了,而其他人在其分支上已經修改了很多東西的話,當他們向主幹合併時就更難了。這就會驅使我不做重構。而不充分的重構就等於劣質程式碼。

當大家頻繁將其程式碼合併到主幹時,就沒有這些問題了。如果不這麼做的話,隨著團隊人數的增加,這些問題的痛苦會成指數級增加。而且,還有一個惡性迴圈: 這種痛苦的自然反應是:更少做合併。正如我喜歡說的,當某些事情令你很痛苦時,解決方案是更頻繁地做,並將痛苦提前。在這裡,解決方案是每個人都更頻繁地合併到主幹。

然而,如果你正在做的一個功能中需要做很多工作,或者你對系統進行大面積修改時,這麼做就比較困難了。下面是一些解決方案:

1.將Story分解成一些更小塊的工作(有時被叫做Task)。我還沒有遇到過一大塊工作無法分解成更小塊的工作——通常少於1小時,並且肯定用不了一天時間——這樣讓我即能達到目標,又能保證系統可工作且可釋出。這需要細心的分析、討論、思考和嚴格的紀律。當我無法找到在增量開發方式下幾小時內可以完成的工作時,我就會先對某些想法做一些試驗(敏捷中叫做Spike2)。至關重要的點在於:我能儘早地對我的方案進行快速驗證:是可以解決問題,還是會對系統造成不良後果,影響了其他人的工作,或者引出了迴歸缺陷(這也是持續整合的動機所在)。

2.在實現Story時,最後再做面向使用者那部分介面。先從業務邏輯及以下部分下手。使用TDD完善你的程式碼。頻繁提交,與主幹合併。最後再完成介面部分。

3.使用抽象分支方法 來對複雜或大範圍變更進行增量開發,同時保證系統一直處於可工作狀態

你怎麼知道什麼時候沒有合併的東西太多了呢?想像一下,假如你是一個開源專案的維護者,有一個你不認識的剛剛提交了一個補丁。你會馬上合併它嗎?你能記住它與主幹之間的所有diff嗎?你能保證在不需要問你的前提下,團隊其他人員能在一分鐘之內就能清楚地理解這些diff嗎?如果你對上述所有問題的回答不是“Yes”, 那麼你就要停止工作,將其分成更小的工作單元。
很明顯,只要 “特性”足夠小,我並不真正反對特性分支。然而,通常使用特性分支的人大多無法通過上一段中的問題測試。真正有經驗的開發人員能理解使用特性分支與為了高效使用它而建立的紀律之間的平衡,但仍舊有一定的危險——GitHub就被Forks搞得很亂,這些Forks很多是不可合併的,因為它們與主幹的差異太大了。

我更想強調的是下面這個觀點,即:讓“儘早地持續地交付有價值的軟體” 中最重要的實踐之一就是確保你的系統一直是可工作的。

對於開發人員來說,達到這一目標最好的方法是:通過確保他們可以將“提交可能對系統造成破壞”的風最小化。我們可以通過“保持小步提交、在主幹持續整合,並且有全面的自動化測試套件來驗收本次修改的預期行為,且不會引發迴歸缺陷”,從而達到這一目標。

 

 

 

相關文章