抽象分支與版本控制系統(VCS)分支功能的對比
抽象分支其時或多或少有那么一點兒“文不達意”,因為它是你對系統做大規模變更時,替代VCS中分支的一種方式。很多團隊經常使用VCS的分支功能進行大規模變更,以便能夠在主干上正常開發功能,修復缺陷。當然,頭痛的問題也就隨之而來,即:將分支合并回主干時相當痛苦,痛苦的程度決定于你在分支上所做修改的多少、大小,以及在這段時間里,主干上做了多少工作1。
也就是說,迫使你使用VCS分支的力量越強,當你需要合并回主干時,痛苦就越大。如果你還在分支上開發了新功能,那情況就更糟糕。一般來說,“利用分支開發特性或者做大的變更”不是一個好主意,原因有很多種,但最重要的一個原因是:它妨礙了持續交付和重構2。老馬(Martin Fowler)寫了為什么特性分支不好?, 以及 如何使用特性開關做為分支的替代方案?
但這并不是說,版本控制系統的所有分支都不好。如果只是想到了一個好點子,拉個分支出來做試驗,到最后并不需要將代碼合并回主干的話,此時用分支也無所謂。另外,當需要發布時才為該發布建立一個發布分支也是可以的。但要記住,在這個發布分支上,你只能做一些小的、嚴重缺陷的修復。 然而,對于那些正在做持續部署的團隊來說,通常他們都不會這么做。因為在主干上修復任何問題對他們來說很容易,可以通過向前發布來代替向后回滾。 這種容易來自于兩個版本之間的差異非常小。
另外,最后一種可容忍使用分支的情況是:你的代碼基正處于一團亂麻模式。在這種情況下,創建抽象層可能非常困難。為了能創建這個抽象層,你必須首先找到一個“接縫”(如果你使用靜態類型面向對象的編程語言的話,典型地是一個接口集合),在這個“接縫”處放上抽象層。如果找不到“接縫”的話,你就要通過一系列的重構創造出一個。然而,如果因為某種原因實在弄不出來“接縫”的話,那么你就只能依靠在分支上重構,以達到那種有“接縫”的狀態了。當然,這是一個極端手段。
抽象分支與其它模式之間的關系
重構:重構被定義為“一種對軟件內部的變更,使軟件更容易理解,更方便地修改,但卻不改變軟件的外部行為”。從這個角度來講,上面提到的兩種抽象分支的例子也都屬于重構。關鍵是,抽象分支是與重構相關的一種有效步驟,能夠對軟件架構進行大規模的修改。你不但能夠隨時發布軟件,而且同時還能進行重構,這也許是在主干上開發最重要的收益了。
特性開關: 大家常常把抽象分支和 特性開關搞混。二者都能夠讓你在主干上做出增量式改變的模式。不同點在于,特性開關的主要目的是在開發新功能時,如果需要發布,讓這些未完成的新功能對用戶不可見。所以,特性開關通常是用于部署或者運行時選擇是否讓某個或某組特性在應用程序中可見。
抽象分支是為了增量式地對應用程序進行大面積改動,所以是一種開發技術。抽象分支當然可以與特性開關一起使用,比如,你可能通過開關決定是使用 iBatis,還是Hibernate來訪問一組特定的數據調用,用于運行時的性能對比。但這種實現的選擇通常是由開發人員決定,是硬編碼進去的,也可能是構建時設定的,比如,通過依賴反轉的配置項放進去的。
抽象分支與強制應用(strangler application)的關系。 強制應用模式包括增量式地用一個全新的系統替代整個系統(通常是遺留系統)。所以,與抽象分支相比,它是一種更高層上的抽象,即增量式地改變系統中某個組件。如果你的系統結構是面向服務的架構,那么兩者之間的界線是比較模糊的。
你可能會說,這不就是一個“好的面向對象設計”嘛? 是的。在遵循SOLID 原則的代碼庫上,非常容易使用這種模式,尤其是遵循了依賴反轉原則和接口分離原則(ISP)。ISP原則非常重要,因為它提供了良好的粒度劃分,很容易做到對不同實現的切換。David Rice(敏捷項目管理產品Mingle的的Lead)指出,對于改變軟件系統中某個特定組件的具體實現方式,抽象分支是唯一一種明智的選擇。老馬(Martin Fowler)也有相同的觀點,他把組件(component)定義為系統中可以被另一種實現方式完全替代的那個部分。
1還有一種爭論是:分布式版本控制系統讓代碼合并變得很容易,所以我們不應該害怕分支。這種誤解有兩個原因。首先,正如老馬指出的,自動合并工具無法捕獲語義沖突。其次,即使使用世界上最好的合并工具,也改變不了“分支存在的時間越長,合并的困難越大”這種事實。你到GitHub上看一看,就不難發現,每個人可能都想把他的分支合并回去,無奈的是,與主干的差異太大,合并需要大量的集成工作。
2 當然,每個規則都有一些例外。如果你的團隊比較小,而且每個成員都很有經驗,并且分支的生命周期很短(比如少于一天),那么,此時的分支操作未嘗不可。
原文轉自:http://www.continuousdelivery.info/index.php/2013/01/04/branch_by_abstraction/