單個團隊內部的持續整合已經是成熟的實踐. 跨團隊的整合則碰到了很多問題, 包括全部測試回合時間過長,
合并成本高等問題. 針對這些問題有一些對應的解決方案, 如合理的分支策略, 分層的整合等.
這裡想討論一下幾個基本的矛盾, 和理想中的解決方案
1. 並行開發 與 整合 之間的矛盾
這是本質問題, 如果所有功能都是由單一開發人員循序漸進的完成, 則整合並不是大問題.
由於團隊內部的整合已經有大量成熟的實踐, 因此前面的假設可以修改為"如果所有功能都是由同一團隊循序漸進的完成, 則整合並不是大問題".
這就為我們指出了一條思路: 如果把需要整合的部分, 都分配給一個團隊去完成, 則會大大降低整合的難度
傳統的大規模開發中, 往往按照模組劃分Team Dev, 比如做UI的, 做網路通訊的, 做資料庫訪問的,
做協議的, 等等, 分別是不同的團隊. 而最終為了完成某個使用者可見的功能, 需要協調多個團隊並行開發, 然後聯調, 也就是整合. 也就是說, 是特性需要整合.
如果我們按照特性來劃分團隊, 則跨團隊的整合將轉化為團隊內部的整合. 而團隊內部的整合已經有大量成熟的實踐
關於特性團隊和模組團隊的全面比較, 請參見<<Choose
Feature Teams over Component Teams for Agility
>>
降低整合成本的第一原則就是避免整合
. 減少跨團隊的整合需求, 如果不能避免的話.
按照特性劃分團隊將帶來一個明顯的問題, 就是不同的團隊的人可能會同時修改同一個檔案, 同一個類,
同一個函數等, 因為不同特性都會涉及同樣的功能模組, 如資料庫/網路/UI等. 這就是我們想討論的第二個問題
2. 基於文本的合并 與 基於語意的邏輯 之間的矛盾
現代的版本控制系統都能夠智能的自動合并文本. 然而合并後的結果是不是我們所期待的,
則只能通過測試來驗證. 並且對文本層級的衝突, 版本控制工具也無能為力, 還需要開發人員人工幹預. 因此降低合并成本第一原則, 就是避免合并
.
這裡有幾種可能的方式來達到這一目標:
基於外掛程式的架構: 這是開閉原則
的應用. 增加任何新的功能,
都不需要修改原來的檔案或類, 而是增加檔案或類. 一個大尺度的例子就是Eclipse生態系統.
如果把Eclipse的各個外掛程式都看作某個完整系統的所需要的特性的話, 那麼這些特性的開發人員有的甚至從未謀面,
開發過程中也不需要跟其它外掛程式進行代碼層級的整合, 然而最後它們卻能和諧的一起工作
基於小檔案/小類/小函數的程式碼群組織: 這是單一職責原則
的應用,
"小"只是代碼外在的表現, 真正的含義是職責單一. 以C語言為例, 考慮兩種極端的情況. 一個極端是把整個系統都寫在main函數裡,
另一個極端是每個獨立的功能都寫成獨立的函數, 並且每個檔案只包含一個函數. 前一種情況下, 任何團隊的任何改動, 都需要跟其它團隊的改動做合并,
並通過全面測實驗證合并後的行為. 後一種情況下, 合并的需求大大降低, 只有大家改同一個函數的時候才需要, 並且測試也可以以影響範圍為邊界進行測試.
當然我們不需要像後一種情況這樣極端, 但至少指明了前進的方向.
這類方案也帶來一個問題, 就是我們無法一開始就設計出如此良好的外掛程式體系, 只能是一個演化的架構.
這期間, 外掛程式和架構之間的介面變化將為整合帶來挑戰, 即舊客戶與新服務如何和平相處. 這就是我們要討論的第三個問題
3. 依賴的穩定性 與 依賴自身的演化升級 之間的矛盾
這是一個普遍問題, 尤其對分層的體繫結構, 或者"平台 + 產品"模式的開發項目.
在理想情況下, 所謂的理想情況是指, 代碼集體所有制/IDE完善的重構功能/全面的自動化測試案例/等,
公用API的變化所引起的客戶代碼的修改, 都可以由某個團隊一次性的完成並提交. 然而在大量的大規模遺留項目中這是不可能的. 這種情況下,
"第三方代碼線"(參見<<Software
Configuration Management Patterns
>>)或者"變更控制修改組"(負責實現變更, 並提交)是可選的解決方案
這裡想討論一下另外一個大尺度上相對更通用的但會引入管理成本並有點風險的解決方案, 就是向後相容,
或者Versioning
. 幾個例子:
我們知道COM技術就是為瞭解決DLL版本地獄的問題. COM組件的新版本與老客戶能和平相處,
是因為COM組件的升級, 並不是直接修改老介面, 而是增加新介面, 保留老介面, 並提供能力查詢介面, 這樣新老客戶都能各取所需.
這是"擴充項物件"模式的一種應用. 這是API層級的向後相容/Versioning
Subversion. Subversion的用戶端可以和伺服器協商版本,
從而選擇一種大家都理解的協議. 這是協議層級的向後相容/Versioning
XML. XML本身就是為擴充設計的, 可用於實現向後相容的訊息/協議等.
但實際的項目中, 我們並不希望老客戶和老API/老協議長期存在, 而是希望把老API/老協議刪掉,
所有老客戶全部使用新的API和協議. 因此我們需要階段性的應用上述方案, 並提供管理或者技術手段, 在過渡時期結束的時候, 確保新老交替已全部完成.
這裡的風險就是, 混亂無力的管理一旦允許老介面存在一段時期, 它就會一直存在
以上三個問題在大規模遺留系統中很難得到徹底解決, 因此這幾種解決方案或思路,
僅僅希望在開發新系統時能夠提供一些考慮的因素