2011年2月5日 星期六

版本控制隨筆 (2) 關於開發支線

對於沒有版本控制系統使用經驗的人,可能還沒意識到二種需求的衝突面:開發成果必需被持續地追蹤且版本控制系統內的狀態同時保持最穩定的狀態。

因為,我們尚未提到開發支線的概念。個人認為版本控制系統最大的特色與差異並非集中式或分散式之別,是如何處理開發支線及使用開發支線會糟遇的各種衍生問題。若您試著使用版本控制系統,而沒有利用過任何開發支線的功能。您就是在預設的開發支線上工作,以 CVS 來說就是尚未設定開發支線標籤的情況。以 Subversion 來說,通常就是 trunk 目錄。trunk 目錄可以是想像的,或實際上建立的目錄。它的中譯即為主幹、樹幹的意思。隱喻著樹枝會伴隨著開發而萌發。以 GIT 來說,通常就是 master 開發支線。對於 GIT 或 Mercurial 來說,它們預設就建好了開發支線。開發支線的概念,對他們來說是明確且必需的功能。所以,他們在設計上,對於開發支線的操作都思考著如何以較低的成本(例如:儲存空間、建立的效率)來產生開發支線。

在您漸漸意識到開發支線的存在後,這時解釋開發需求的衝突就變得有意義。假設,在我們的開發活動中,僅使用一個開發支線(預設的開發支線)。在沒有建立程式碼提交規範的情況下,任何能操作版本控制系統的開發人員,都能隨時將手邊的程式或任意檔案提交給版本控制系統。團隊人數越多,修訂版本也就累積地越快。而這使得該開發支線上的程式碼,永遠處於不穩定的狀態。不穩定的狀態,最顯性的表徵就是當您由版本控制系統提取最新的專案內容時,因為存在著許多不完程式程式或組態設定造成編譯上的錯誤。這樣的錯誤傷害開發者的生產力。要替尚未完成的程式碼排除錯誤是徒勞無工的,何況對於同時使用版本控制系統的開發者,他們並不需要關注到同樣的軟體元件。

由於使用單一開發支線的情境下,毫無限制地提交新的開發結果很可能使專案最新的狀態毀損(Broken)。有種消極的對策:規範開發者在提交任何內容前,確定它是正確的、可進行編譯的。這是許多使用單一開發支線的團隊會使用的策略。不過總是有部分開發者無法確定自己的內容是否符合要求,這使得軟體品質時常因此而降低。在極端的例子,這類的版本控制系統使用者,會被取消提交權限,建議他提供修補檔案(Patch File),在經過驗證後由具有權限的使用者進行提交的動作。這種策略,勉強滿足使軟體/專案最新的狀態維持在較穩定狀態的需求。但在運用版本控制系統的開發流程中,並不能輔助開發者在開發活動尚未穩定之前的版本控制需求。在程式還未穩定前,只能依賴開發者逕自手工般地管理嗎?這樣消極的工作流程,讓需要加強訓練的生手與重新進行觀念調整的開發者缺少了成長的機會。即便,開發團隊已經採用此種保守的策略應付單一開發支線的使用情境,仍無法保證專案的穩定度。只是滿足在任何時間提取出最新的狀態時,編譯工作能順利地執行。為了達到較高的穩定度,更進一步要求,開發者在新功能(Feature)或是功能改善(Enhancement)被完整地實作與驗證後才能進行提交的工作。

這樣保守的工作流程規範,使得版本控制系統的採用,就像是學生被要求在合理的時間點,向 FTP 上傳已經完成的作業一樣。但是這種情況會在善用多個開發支線時轉變,您可以既保守,卻極積地使用版本控制系統的便利。將特定的開發支線定為穩定版本專屬的,僅在將已穩定狀態的變更合併(Merge)至此開發支線。而一般的開發活動,則是由此穩定的開發支線產生的分枝來進行開發。因此,維護產品品質的開發支線只有在合併經過多次檢驗的開發成果時才會用到,除了這個理由只剩下急迫性較高的錯誤修補會動到它。建立開發支線是為了滿足日常的開發活動,原因大致為:修正程式的錯誤、替程式進行完整的複察(Code Review)與重構(Refactoring)、嘗試不同的實作方案或是實作新的功能。當然,我們也能隨意地建立開發支線來測試任何的新想法,程式開發的過程中線出的活動,通常伴隨著有創意的點子產生。

對於使用開發支線的最大困擾是在開發活動告一段落,當開發者試著要將變更合併至另一個開發支線的時候,這時可能會產生程式碼衝突(Conflict)。衝突的產生,其實就是同一個地方,出現了些微的差異,導致版本控制系統無法透過演算法來決定該合併成什麼樣子。因此,標示檔案狀態為「衝突」是版本控制系統通知您,需要您的協助、請決定新的版本要是什麼樣子的途徑。只有全新的檔案、與舊有程式無關的全新的實作不會產生衝突。只要明白衝突的意義,就會知道,這是個決策的時候,而非新問題產生的時刻。不同的開發類型,有不同的方式降低衝突的機率。但不良的寫作習慣,卻會導致各種開發類型、分工都提高了衝突發生的機會。若您曾閱讀過重構的相關書籍,您可能已經聯想到有哪些壞味道(Bad smell)肯定會提高衝突發生的機率。個人認為最嚴重的,有立即重構必要的是:霰彈式修改(Divergent Change)與發散式變化(Shortgun Surgery)。一個會讓特定的程式常常產生變化,簡單地說,您設計的類別不符合單一責任原則。負責的越多,修改的理由就越多。另一種是,要增加一個新功能卻要改變許多的程式,即使他們的關係沒有那麼深厚。無論是同一個區間時常被改變,或著改變會動到的圍範太大,皆使得衝突發生的機會大增。經過這番的「提醒」相信您已經知道如何,輕易地製造產生許多衝突的開發支線,只要您掌握住通則,也能順利地避免。

沒有留言:

張貼留言