2014年1月31日 星期五

筆記:TBD是三小?---What is Trunk Based Development?

讀過了Perforce官方的mainline model的文件,又看到Google與Facebook都使用TBD,以及我自己在開發上遇到的問題,讓我想看看TBD到底如何可以幫助我們解決這些工程上的問題,看起來作者非常反對feature branch,而我自己親身經歷的感受也的確,要開feature branch,除非能做到Perforce官方推薦的經營方式,不然不只Merge會有災難,開發時也是災難連連。以人性角度來說,假設我做componentA,如果有10個feature branch都有componentA,那每個branch有問題我都要去看,我修了一個componentA的問題,由於每個branch分支出去的時間點不同,其它branch有的可能有,有的可能沒有這個問題,那我怎辦,只能等著人家來報問題,那我的時間很多都花在解這些Branch的問題上。如果採用的是TBD的概念,我只要保證trunk沒問題就可以了。或許在code撰寫方式上需要花很多工,但是我只需一次工,也可以將焦點集中在一個地方。對於我這種普通人,這是比較人性化的工作方式。

甚麼是TBD
  • 一個軟體開發的分支模型,也被稱作mainline
  • 同一個產品開發的所有人員共享一個Repository,有一個trunk,單一Developer或是Developer團隊可以有自己的private branch,所有修改最後都會回到主幹
  • 只有在Release時才會有官方的分支,一般Developer不能對Release Branch作動作,只有Release Engineer可以更動Release Branch,當Release Branch完成它的任務,就會被砍掉。
  • Google與Facebook都採用這種分支模型

有需要Release才Branch
  • Release之後的branch,就不會有大的更動,只有Release Engineer會進行將挑選Commit合併到Release Branch的動作
  • 多一個Release Engineer的帽子
  • Bug先在trunk修好,之後把Commit合併到Release Branch,而不是在Release Branch修好再整合到trunk,這樣可以把修改Release Branch的人限制在最小程度。

Developer的責任
  • 每個Developer都要保證Build會成功
  • Google與Facebook在新進員工訓練下很多工夫在這上面。一開始沒生產沒關係,但是不要讓公司產品Build不出來!
  • Rollback/revert是最後不得已的策略
  • 複雜產品或是大公司都會有一堆Pre-Commit認證。
  • Developer應該養成習慣,證明Commit是沒問題的:
  1. Commit之前把Code更新到最新
  2. 以最新的狀態將整個產品重Build一次
  3. 確認更改到的功能無誤(當然關聯的功能也要確認一下)
  4. Commit,總算搞定,休息一下
當某個功能花太長時間才能開發完
  • 使用Branch By Abstraction (2013重提)
  • 避免Branch到處開,最後整合不回來
什麼不是TBD
TBD Quick cheklist
  • Developer幾乎只commit到單一trunk
  • Release Engineer創建Release Branches, 幾乎只把Commit整合到Release Branch
  • 用「幾乎只」來形容是因為如果bug無法在trunk重現(有可能是相關的code已被改變),那Developer就要在Release Branch上修正,然後把Commit整合到trunk。
如果應用Release Branch的概念,請記住:
  • TBD代表Developer不能Commit到Release Branch
  • TBD代表你將會刪除不再使用的Release Branches,不會做任何整合回trunk的動作
Developer需要Commit到多個Branch
  • 當然不是TBD
  • 如果想要Branch,請使用Branch by Abstraction
  • 老鳥總是會說有Special Case需要Branch
  • 重點就是合併的複雜度,10個Branch,每個人都在那邊Commit來Commit去,有些相關,有些不相關,有些Commit到2個Branch,有些Commit到1個Branch。這我超有感,我們團隊面臨到的狀況正是如此。
  • To Branch or Not to Branch?這是已經被爭論許久的問題。
  • 作者說除了Release Branch之外,不應該有任何Branch在共用的Repository上,但是Developer或是Developer團隊可以有自己的Private Branch。
  • 就算Feature需要花很長的時間做而且沒時間花在整合上,還是不應該Branch by Feature,應該使用Branch by Abstraction。我們團隊遇到大Feature就會開一個Branch,由於這種Featrue Branch沒人經營,Feature開發中後期,就會花很多時間在整合,而複雜度隨著Commit數量增加越來越複雜,最後只要提到要整合回mainline,每個人的態度都是把一切交給命運。

沒有在Branch上作持續整合
  • 不是TBD
  • 很多Open Source的Developer聲稱沒有持續整合也不會怎樣,作者建議有10個以上的Developer就應該要做持續整合。個人認為就算1個也應該做,誰敢說自己完全不會改壞自己的Code。

手動管理Component Dependency版號
  • 對外來的Component,通常都是用外面已經Build好的穩定版本,版號是固定的,可以直接寫Build管理檔案內(例如makefile,Maven的pom.xml)
  • 對於內部的Component,自己手動指定該Build所需的Component版號(Ex:1.1.2之類),很容易造成不知到哪個版本的產品該用哪個版本的Component,要嘛就是把Code拉近Product Dir裡面全部Compnent都Build新的,要嘛就是根據Perforce或SVN的Revision Number,或是用Jenkins產的Build Number。手動是複雜度的地獄。
範例:
Perforce或SVN的架構
trunk
component1
component2
component3
component4
productA
productB
release
private

productA用到component1,component3
productB用到component2,component4

要Build productA,CI可以先build component1,component2,然後build productA,但因為可能component1不斷開發,已經到了reversion=1500,而productA不需要reversion=1234後續開發的功能,就可選擇從component1的reversion=1234抓code過來build。或是直接把compoent1的reversion=1234的code放到到productA底下,目錄架構就會變成
trunk
     component1
     component2
     productA
          component1
          component2
在Perforce有Module這個概念可以應用,History也會留存。

CI不是從Root開始Build
  • CI在Build所有的Component都應該重新開始Build,不可以有任何的快取,或是已經Build好的Component,因為這樣無法反應code的最新狀態。

用詞不當
Mainline意指其他事物
基本上Mainline就是指TBD,不過在1993年的ClearCase,它的mainline長的如下圖:

這是一個非常花時間的Branch Model,它的精神就是最後才整合,與TBD的早期整合正好相反。
上圖的劇本:
  1. mainline開發一段時間,Branch出1.1.x
  2. mainline繼續開發,1.1.x也繼續開發
  3. 接下來1.1.0要Release,即將合併回mainle,maineline因為要開發1.2.x,害怕1.1.0整合進來會很亂,所以先Branch出1.2。
  4. 1.1.x功能告一段落,1.1.0Release,此時合併回mainline,由於mainline的code已經不太相同,合併就是災難。
  5. 1.2繼續開發,mainline繼續處理混亂狀態
  6. 1.1.1Release,因為1.2需要有1.1的功能,所以又要合併回mainline,剛處理好混亂狀態的mainline要再處理一次混亂
  7. mainline處理完混亂,開始合併到1.2.x,因為兩個branch長得又不太一樣,所以又是災難
  8. 1.2處理完mainline下來的混亂之後,終於可以Release 1.2.0
可以看到,每次合併都是一場災難,而這個災難的次數還真不少。其實我們也是使用這個方式,由於有兩個以上的新版本同時開發,branch出去,branch執行有問題也不知道找誰修,要再回到mainline又是一堆工,雖然Branch by Abstraction不見得是萬靈丹,但作者提出的問題我已經有親身體會。

Feature Toggle
Martin Flower歸納出來的名詞,這個技巧是對一些已實作或是實作中,但還不想開放的功能,目前有些人以為這是與TBD一起用的,其實不然,這招早就存在,分為以下兩種
  • Toggles at runtime,執行時期判斷旗標,看要不要開放此功能。
  • Toggles at build time,建置時間判斷建置參數,看要不要把功能相關程式碼build進去。
不管如何,CI Server可以很好地對應這種需求

Branching is not the problem, merging is the problem
這就是TBD所想要解決的問題,Branch很方便,不是毒蛇猛獸,但是要如何管理好Branch,就是軟體工程的奧妙之處。

DevOps Lessons Learned at Microsoft Engineering 筆記

原文: https://www.infoq.com/articles/devops-lessons-microsoft 筆記 組織 講Microsoft裡面的DevOps 故事描述的是Cloud & Enterprise and the Bing ...