2010/11/08

應用系統的版本管理

一段歷史

經過幾年軟體版本管理工具爆炸性的競合, 如果不考慮控制的問題, 我們可以自由選用 subversion(svn), mercurial(hg) 以及 git。svn 存在時間最早, 在有一些歷史的專案和中小公司比較常見; hg 由於簡單明確, 大型源碼社群如 sourceforge, codeplex, google code 普遍接受; 而 git 強大穩定, 則是技客首選。

這三者陸續在用, 雖然深淺各有不同, 從歷史角度來看: 最早通用的 cvs 是管理檔案版本, 所以會有 v1.0, v1.1, v1.2, ….。svn 側重整個專案版本, 標示版本以整個儲存庫為準 r123, r223, r323, … (r=revision)。大概是 cvs 時期一個檔案就可做完一件事, 到了 svn 得靠一堆檔案 … 請參考『軟體工程師的進化』一文。

到了 dvcs(hg, git) 回歸功能面管理, 版本像是 229a46966a72, 13a7d2806d50, 64d88c389b67, … 的 uuid。意義不再是檔案版本編號(v1.0), 或由儲存庫變更序號(r123)做認定。應該沒有人可從 dvcs 裡版本號碼看出任何意義。一方面在每次提交版本(commit)輔以適當註解, 而整體來看, 端視儲存庫擁有者認定版本的意義。因為是 dvcs … 只要有心, 人人都可以是儲存庫擁有者 … peace!

對一個專案來說, 針對檔案變更追蹤是過小, 像流行的 MVC (Model-View-Controller)在概念上就跨了三層。若針對儲存庫變更追蹤又太大, 變更頻繁的話, revision 就如同雪片般, 好看是好看, 但一般也只是好看。因此, dvcs 當是比較符合趨勢的選擇。

一種問題

交待完歷史, 回頭看主題。假設專案有源碼要管理, 這個應用系統是承上啟下, 也就是依據上游源碼為基礎, 提供下游客戶穩定、加強、或客製的版本。是種常見模型:
上游儲存庫 UR - Upstream Repository
我的儲存庫 MR - My Repositroy

源碼儲存庫畢竟是技術人員才會接觸到, 大部分狀況以策略解決: 有時將上游源碼設定為程式庫, 簡化問題; 或以廠商分枝(Vendor Braches)將上游源碼納入專案; 而產品類專案, 可忽略 n 個客戶問題。

但如果使用開放源碼 CMS, CRM 或 ERP 這類應用為主的系統, 上游持續加強版本, 下游因應需求不斷變更 … 會爆炸的點大概就是位居中間的儲存庫。
在網路上, 看到相關問題討論有:
  1. 非官方 hg 流程 中 Offsite working on dynamic websites。其中『Upgrading Drupal with Git』(部落格已落幕, 可參考 archive.org 資料)。
  2. 也是 drupal 開發, 教學視訊 Git With Drupal 7
  3. opentaps(ERP) 的建議 Managing Customizations with Upgrades, 大抵是分為四個層次: a. 瞭解現有的, 將異動最小化 b. 貢獻源碼, 免除版本差異, 透過社群改進 c. 獨立應用程式在特定目錄下 d. 若修改核心及社群不接受的源碼, 得注意合併問題。最末項不建議, 因容易出包。
上面第三項 "在特定目錄下" 放應用程式, 是大部分應用系統普遍的做法, 像 SugarCRM 也有類似的機制。

通常專案會設定上游的版本, 但長期提供服務, 必然會面對上游版本變更。而下游的需求, 投入行業時間夠久, 一般也會有共通方式解決, 例如提供一個檔案上傳或流程整合的功能, 應該也不希望一家處理過版本提升後, 還得要處理其他家客戶相同問題。

技術上, 沒有通用做法的話, 能抑制爆炸的源碼就大概只有爆炸的肝。(以爆制爆?)

一項解法

如果著眼於儲存庫, 所有問題都成為一團。首先區分上游變更, 與下游需求這兩個變動的來源。其他像共通功能的開發, 問題的修正, … 先納入下游需求。

再來, 如版本管理的演化(csv → svn → dvcs), 因時制宜般, 上游變更以分枝(branches)處理, 下游需求以變更佇列(patchs queue)對付, 再建立一個儲存庫負責照拂需求的變更佇列, 是為『變更儲存庫』。
變更儲存庫PR - Patch Repository
變更佇列在 git 中有外掛 stgit, quilt, 至於 hg 是內建 mq (mercurial queues)。

在手上實際 ERP 案例中, 上游儲存庫每個月大約有 800kb 左右的差異檔(diff), 而變更佇列除了中文化有 5mb 的差異檔, 其他加起來不到 300kb。每月同步上游儲存庫後, 再更新變更佇列, 也就是 UR 與 PR 會有版本對應的關係。只要 UR 與 PR 同步後, 就可一體適用其他相同系統的客戶。節省下的資源可專注差異化部份。

一方面是變更的大小與不同機制的搭配, 另一方面是變更佇列對每項修補差異的處理, 比分枝來得直覺。例如把中文化和其他修補一起放入同一個分枝中, 當上游版本更新, 要合併到分枝時, 假使自動合併無效, 要看到檔案才能處理, 同時可能也要處理 API 差異之類的。簡單來說, 就是要有經驗的工程師才能處理版本合併的事務。如果是以變更佇列處理的規劃, 就很方便分工, 中文化部份安排通中/英文, 細心的工程助理打點即可。

參考

0 comments: