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