特性分支是邪惡的?!

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

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

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

持續集成是一種實踐,用於確保你的軟件一直是可以工作的,並且在幾分鐘內你就能夠得到關於 “你的修改是否破壞了系統”的反饋。
特性分支是一種實踐, 使用它的人直到他所開發的特性“完成”後才合併回主幹(這裏的“完成“不是“done done1”原則中的那個“完成”)。
主幹是指開發主線—— 通常是指版本控制庫中的。你的某交構建就是從這個主幹中的一個版本創建的,並會被放到你的部署流水線(參見《持續交付》一書,中文版於2011年10月中旬出版)中。 注意,這些定義對於DVCS和其它開源項目,甚至是GitHub,也完全適用。

先讓我們解決一個不必要的爭論。當你在使用版本控制工具時,你就是在使用分支方式來工作,這個分支就是本地工作目錄。而使用DVCS,只是多了一個層次而已,因爲你的本地倉庫就是一個有效分支。我並不反對創建分支。我不贊同的是:你把最終要發佈的代碼在分支上積攢起來。

下面是我所看到的。當你將最張要發佈的代碼大量地堆積在分支上時,將有幾個糟糕的事情發生:

  • 這種狀態持續時間越長,就越難合併。因爲隨着其他人向主幹提交,主幹的代碼與你的分支上的代碼之間的差異會越來越大。強大的合併工具的確會在一定程度上幫助你,但是任何一個做過很多開發工作的人都會有過這樣的經歷,即:代碼的確成功合併了,但是應用程序運行不起來。隨着需要合併的那些代碼數量的增加,以及初始分支與最終合併時間的增長,發生這種事情的可能性是遞增的,而且不僅僅是線性遞增。
  • 在分支上的工作越多,在合併到主幹時越有可能破壞系統。每個人都有這樣的經歷:有個問題出現了,你似乎找到了一個非常聰明的解決方案。可是,幾個小時(或者幾天)後,你才發現需要廢棄所有的東西,或者(更常見地)那些引起未預期後果的代碼提交。
  • 當多個開發人員同時在這個代碼庫上工作,並使用特性分支開發時,使代碼重構變得很難。如果我重構並且提交到主幹了,而其他人在其分支上已經修改了很多東西的話,當他們向主幹合併時就更難了。這就會驅使我不做重構。而不充分的重構就等於劣質代碼。

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

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

  1. 將Story分解成一些更小塊的工作(有時被叫做Task)。我還沒有遇到過一坨工作無法被分解成更小塊兒的工作——通常少於1小時,肯定用不了一天時間——這樣讓我即能達到目標,又能保證系統可工作且可發佈。這需要細心的分析、討論、思考和嚴格的紀律。當我無法找到在增量開發方式下幾小時內可以完成的工作時,我就會先對某些想法做一些試驗(敏捷中叫做Spike2)。至關重要的點在於:我能儘早地對我的方案進行快速驗證:是可以解決問題,還是會對系統造成不良後果,影響了其他人的工作,或者引出了迴歸缺陷(這也是持續集成的動機所在)。
  2. 在實現Story時,最後再做面向用戶那部分接口。先從業務邏輯及以下部分下手。使用TDD完善你的代碼。頻繁提交,與主幹合併。最後再完成界面部分。
  3. 使用抽象分支方法 來對複雜或大範圍變更進行增量開發,同時保證系統一直處於可工作狀態

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

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

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


注:本文來自於《持續交付》中文站


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章