接下來就看看Branch By Abstraction有多厲害,實際看下來,的確是一套很有用的方法,簡單來說,就是把整合的工分散到每日的開發中。但是要實行有一些現實的問題需要克服
- 當我要新加一個Feature,會改動3個Class,這3個Class可能所有Module都要參考,而且與其它Module的Code綁很緊,要抽成Abstraction要改動的地方也是會很多,根本就是翻了。
- 就算我做好抽象層,把所有Module參考到這三個Class的地方改為呼叫抽象層,這樣還是對Code有變動,也是有可能對產品造成衝擊。
- 如果這3個Class的修改連介面都換掉,整個Class改頭換面,煥然一新,原來的使用流程已經不在,就算有抽象層當緩衝,還是免不了對產品造成衝擊。
這些現實的問題,我想是可以克服的,第一就是要有完整的Test,Unit Test,Integration Test,UI Test,但是如果Test不夠完整,可以使用這招嗎?我想答案是肯定的,但是要邊做邊補Test。而沒有任何Feature Branch,大家都只看Trunk,也就是mainline,這件事對目前的我而言,簡直就是美麗的夢境!我自己參與的產品就有遇到這種狀況,目前是分支一個Branch來做,如果用Branch By Abstraction,新的東西就可以不用等好幾個版本之後才進mainline,也不用擔心如果合併回mainline,到底會是怎麼樣的地獄。如果我有機會參與決策,我一定直接就這麼搞。
另一點作者提到除了Release之外,完全沒有其它Branch,這點我還是有點存疑,除非有一套機制讓Developer拿著Commit去取得認證,保證不會Break掉任何東西。不然Developer自己一個人做測試還是有限,如何保證不Break mainline?如果一個產品的開發編制如下:
- 100個Developer
- 分成15個Team,有的Team人多,有的Team人少
- 25個Component,從Web UI,Mobile UI,Database,Domain,Infranstructure.....
- 有跨Component,跨Team修改的需求,也就是一個需求需要改UI,Domian,Infranstructure一路改到底。
所有人都進mainline,哇塞,這太硬了,如果有個超級CI Server Cluster,Developer把Commit送上去,5分內跑完所有Test,取得Commit Token,然後Commit,那我覺得OK。但是有這麼超級的CI Server嗎???如果沒有,感覺還是以Team為單位,有各自的Private Branch,一周或三天與mainline同步,然後各自有自己的CI,一周整合回mainline一次,把測試的負載分散到各個Team會比較好。Mainline當然也有自己的CI。不過這個方式對於跨Compoent與跨Team的需求,分出Private Branch也是可以,但是Branch要維護就麻煩...感覺跟在某一個Team的Branch會好些....
果然,分Branch就是麻煩的開始...
- "Branch by Abstraction"是很少人知道的Best practice
- 避免使用需要合併回mainline的Short lived feature branches
- 因為這些Branches的狀態隨著不斷開發,可能會無法正常運作,導致developer需要花很久的時間去整合,最後可能就是整合不完,不斷的再整合,這個short lived變成long lived...
但書
架構要滿足以下條件才能用Branch by Abstraction,這些條件與Agile Development相符合:
- 你已經將Application分成不同的Component
- 每一個Component在trunk裡面是一個目錄(有可能是階層式)
- 每一個目錄有它自己的Source,而且可以自己被build出來(有可能是階層式)
- 你有一組良好的unit tests而且這些tests可以展現components怎麼用
- CI可以管理大量的Component的建置,Maven-like Repository可以存放Build好的Compoent,只需透過下不同的Command就可以做好Branch相關Component的管理
- 你的管理方式對Release Planning有良好規畫
- 每個Developer有絕不能Break Build的Sense
你的Trunk可能會長的像這樣:
<root>
trunk/
foo-components/
foo-api/
foo-beans/
foo-impl/
build.xml
src/
java/
test/
cruisecontrol-config-snippet.xml
remote-foo/
bar-services/
bar/
build.xml
src/
java/
test/
cruisecontrol-config-snippet.xml
bar-web-service/
當你的團隊想要從Hibernate轉到iBatis,因為底層架構改變,所以架構師可能會建議要建立一個分支,否則trunk可能會Break數周,這時候Branch by Abstraction登場代替Branch by Source Control。
Hibernate:一套很有名的ORM
iBatis:也是一套ORM
Branch By Abstraction步驟
- 在要修改的地方導入一個抽象層,底層實作還是原來的實作,然後Commit
- 修改所有相關Class,使其呼叫這個抽象層,然後Commit
- 打造另一個抽象層的實作,撰寫對應的unit test,確定功能OK後Commit
- 步驟2相關Class參考的實作換成新的實作,抽象層不變,然後Commit
- 把原來的實作標為廢棄,或是直接砍掉(如果不想要轉移期)
- 刪除原來的實作,到這裡已經沒有需要原來的實作了
- 移除抽象層(如果抽象層寫的不漂亮)
簡單來說,就是這幾張圖:
來源:Martin Fowler的 http://martinfowler.com/bliki/BranchByAbstraction.html
一開始長這樣

抽出Abstraction Layer

其它Client呼叫Abstraction Layer

開始做新的Supplier

把舊的Supplier換掉,大功告成

好處
- 只有一個小團隊會被影響
- 在修改中,trunk不會被Break,因為整個產品都是可以編譯可以跑的狀態
- 由於不會被Break,所以管理面可以滿足Schedule
- 避免Merge Hell
- 導入抽象層可以增加對架構的了解與優化Model,這件事本身就有好處
當然Branch By Abstraction不是萬靈丹,它只是一種Developer/架構師可以套用的實務作法,它用來取代架構師建議的Long Running Feature Branch,架構師應該爭取使用BBA而不是另開Branch。
什麼時候該Branch
真正的Branch應該只有在Release的時候,應該長的像這樣
<root>
trunk/
releases/
rel-1.0/
rel-1.1/
rel-1.2.x/
- 在Release前幾天才Branch
- 這個Branch當然是從trunk分支出來
- 然後作"Production harden"(為了產品化把bug修掉,集中測試,禁止別人亂改),Developer不能Commit到Release
- 只有被指派的人(在這裡是Release Engineer)才能Commit
- 讓CI證明trunk一直都保持良好的狀態
24-2009/5/2更新
- Mercurial,Git取代SVN變成主流
- 採用TBD,配合"Branch by Abstraction",與"little and often commits",與Agile Development搭配得很好。
Multi Branch VS trunk圖解
使用Multi Branch的示意圖
戰況報導:
- 紅色是無法正常執行產品所有功能的狀態
- 在任何分支之間都有可能有合併動作
- 某些Branch很短命,某些Branch很長命
- 某些Branch在開發時注意的是使用者介面下去的功能是否正常(應用程式開發Team)
- 某些Branch在開發時注重底層架構效能(引擎開發Team)
- 這就是混亂的代表
- 每個Branch都有可能Release
會遇到的問題:
- 一個獨立的Branch在經過幾周之後,有可能變成無法發布
- 研發團隊回報,他們整天在合併,解決合併相關的問題,沒辦法做正事
- 常會有Regressions,合併的時候總是會漏掉某些東西,然後就被業務部門X爆
- 標記Branch與處理標記讓人想換工作
如果用Trunk model就會長的像這樣
戰況報導:
- 所有人的開發都在Trunk上(這張有隱含一些細節,接下來的圖會說明)
- Release都在Release Branch上做
- 只有Bug fix會進Release,然後合併回Trunk(能先進Trunk再進Release更好)
- 幾乎每一天產品都是可以執行的,而且可以Deploy
- 可以滿足這句: "be ready to go live within a day's notice, and have a high level of confidence",隨時要出都可以
細節部分:
灰色部分可以是Developer本機下載的Code,或是小型的Private Repository,其他團隊看不到,沒有機會也禁止修改。