提升軟件品質是我們一直追求的理想,但軟件開發唯一不變的真理就是變,為了應付變化多端的軟件開發過程,敏捷開發提倡了一種擁抱變化的軟件開發理念,也替軟件開發人員帶來了不少佳音。
這些軟件開發模型與方法論,最終的目的在於軟件開發管理與品質的提升,與其說品質提升倒不如說是維持一定的水準。雖然敏捷開發有很多不同的方法論 (例如 Scrum, XP 等等),但我們注意到這些方法論都一定會提到持續整合 (Continuous Integration)這個概念。持續整合是敏捷開發實現的武功招式之一,有助掌握軟件開發節奏
為何要持續整合
在軟件開發一定相當重視專案管理,因為軟件在建構過程中含有太多不確定的因素,專案永遠延期。經常發生在產品開發後期,系統漸漸開始浮現各種Bug與不穩定的徵兆,越後期的版本機會越高。持續整合就是為了避免這樣的情形發生,我認為持續整合最大的好處在於能夠「掌握軟件開發節奏」!
若是我們長期參與低劣的軟件開發過程,久而久之就容易失去信念,失去對軟件品質的堅持,這對於組織與團隊的傷害相當大,但也因為不易根除,往往日久為患。工程師為了專案時程而加班,PM為了時程犧牲品質。程式設計師漸漸為了趕緊搞定眼前的難題,開始不踏實地建構軟件,開始用一些奇怪的方法 (Dirty Hard Code) 解決系統自動產生的 Bug…。專案一定延遲,Bug永遠改不完。軟件開發的複雜性,不知不覺已經由病轉疾,病可以醫的好,疾就只能控制病情了。
那持續整合到底是什麼?
假設我們能隨時掌握軟件的狀態,讓開發中軟件一切的狀態變得透明,那不是很好嗎?回到「持續整合」這個議題,就是不間斷地把大家寫的 Code 放在一起跑看看有沒有錯。我們常接觸的敏捷開發 (Agile),為了快速適應變化,常常在很短的週期 (Scrum 大約兩週) 就會發佈一個新版本,這件事在 XP (極限編程) 中稱為 Small Release。然而每一個版本發布重視的不是新增的多少功能?而是產生一個逐漸接近市場的產品。注意喔,每次發佈的軟件都必須是可以被正確執行的!在很多敏捷開發方法論都提到,可正確執行的程式碼勝過一切,當然也勝過那些該死的文件。
問題來了,要如何在短時間驗證軟件是可以正常運作的呢?如果一開始功能少還可以花點時間手動測,到後期功能多就沒辦法了,更不用說除了測試新版本的功能,還要確保既有的功能能夠運作正常。這時候「持續整合」就是發揮效用的時候了。其實就是自動地從版本控制系統拉Code進行建置與測試,一旦我們不停的在開發的過程中持續地進行這件事,當軟件發生不穩定時就可以立即察覺,將能夠大幅降低整合測試的風險與時間,因為我們隨時隨地都在進行整合測試!
關於測試與自動化
上述提及的測試並非手動測試或半自動測試,而是全自動測試。在必須反覆且密集測試的過程中,相信沒有人想手動測試的,而且只要是人做的都有機會錯!自動化測試會是比較好的方法。
在實際上,對於「撰寫測試」這件事,大概是整個持續整合過程中最難推動的,常因為我們的教育一開始就沒有讓新手程式設計師明白測試程式的重要性,日常的工作也都是在追求功能的實現,而不是功能正確無誤地實現,往往只重視在程式本身的執行結果 (用眼睛看)。在敏捷開發中,也曾提到測試驅動開發 (TDD, Test-driven development) 這樣的概念,但如果您開發的系統沒有經驗老道的軟件架構師,那麼這個模式在實務推行上將更為困難,因為常發現根本沒辦法在既有的軟件架構設計自動測試,要改就得大改,實行測試的信心與意念就被消滅了。
在實作測試的過程中,其實有些重新審核系統的味道,像是我們都可以發現更多軟件設計上的缺失,發現更多可以改進的設計,像是利用解耦合、物件抽象化、資料連結層 (Data Access Layer)、Mock Object、Dummy Data 等等技巧對架構進行軟件重構。
實行測試還有另一種很棒的方法,就是實行「結對編程 (Pair Programming)」,結對編程中常常一位寫程式另一位寫測試,這樣的過程迫使我們能夠設計出可被其他程式測試的程式碼,間接達到自動化測試。有的老闆很難理解為什麼要兩個人做同一件事,但公司卻要付兩個人的薪水!
實行自動化測試困難重重,但這些都不是我們逃避的原因,其實一開始不用急著提高測試覆蓋率,先從基本的功能測試開始。大致上有兩個方向可以慢慢實現:
先進行基本功能的正確性測試,至少保證功能可以被執行(雖然不一定對)。 當系統出現 Bug 時,解 Bug 前撰寫複製錯誤的測試程式,接著才修正 Bug 確保未來同樣的 Bug 不會一再發生。
這兩點對於已經開發中的系統特別有效,可以慢慢搭建起自動化測試的工作,有了開始就容易多了。我曾經看過實際的例子,在一個開發已久的軟件後期才加入自動化測試,雖然覆蓋率不到 30%,但是管理者做了一個很有約束力的決策,就是整合版本控制系統,未來 Commit 的程式碼不能降低整個系統的覆蓋率。所以每次 Commit 後就會進行自動測試,約束未來加入的程式碼必須強制撰寫自動化測試,保證產品的品質不會越來越糟。
測試的模式與種類繁多,試著找出適合自己產品的自動化測試手段即可,並沒有一定的標準答案。最後,儘管我們可以達到的測試覆蓋率有限,或者當下複雜的軟件架構導致難以撰寫測試,但這些都不是藉口,必須先開始才會有進步的空間。
系統反饋
前面提到,由於持續整合系統無時無刻都在進行系統整合與測試,當持續整合發現軟件不穩定時(指的是建置或測試失敗),就會發出警示給予開發者。這個行為我們稱為「Feedback 系統反饋」,系統反饋是持續整合系統中相當重要的一件事。當我們收到系統給予我們這樣的回饋時,應當立即著手處理,而不是拖到接近產品釋出期限,才開始面對持續整合早就給予我們的警示,造成產品時程與品質的憂慮。
最容易實現系統反饋的方法可以透過「每日建置」來完成,每日建置通常在晚上執行 (或稱為 Nightly Build),由於通常程式設計師會在下班前提交比較穩定的程式碼,在夜深人靜的時候進行整合測試是一個好方法。由於系統每天晚上會更新最新的程式碼進行建置,當遇到問題時就會發出「系統反饋」警示,通常是發出 Email 告知幾位相關人,好讓事主在隔天一早上班就可以著手處理問題,盡可能讓我們所建構的軟件在軟件開發過程中,能夠隨時保持穩定的狀態。若是在合理的測試覆蓋率下,甚至可以隨時發佈開發中的系統,「快速適應變化」這不就才是敏捷開發的精神嗎?
持續整合的精神:自動化 + 測試 + 系統反饋
由於每個軟件專案都不盡相同,軟件建構流程並沒有絕對的標準答案,只有做適合團隊的對應作法。實務上建置持續整合系統,確實要花上不少功夫撰寫 Script 建置腳本,特別在測試環境的自動化建置與執行測試等等工作。雖然方法不同,但是所有的概念還是環繞在「自動化+測試+系統反饋」這三個精神上。
Agile Dev到底是甚麼秘笈?試談持續整合的重要性
https://www.facebook.com/hkitblog