說好的軟體品質
提升軟體品質是我們一直追求的理想,但軟體開發唯一不變的真理就是變,為了應付變化多端的軟體開發過程,敏捷開發提倡了一種擁抱變化的軟體開發理念,少說也替軟體開發人員帶來了不少小確幸。
這些軟體開發模型與方法論,最終的目的在於軟體開發管理與品質的提升,與其說品質提升倒不如說是維持一定的水準。雖然敏捷開發有很多不同的方法論 (例如 Scrum, XP 等等),但我們注意到這些方法論都一定會提到「持續整合 (Continuous Integration)」這個概念。持續整合到底是何方神聖?讓它在軟體工程中被如此受重視。換個方式來說,我常把敏捷開發比喻為武功心法,心法是虛的,代表方法論核心的理念,其招式才是起作用的媒介,然而持續整合便是敏捷開發實現的武功招式之一。
掌握軟體開發節奏
先不管敏什麼捷開什麼發了,先說說為什麼要推薦各位「持續整合」這個招式。在軟體開發一定相當重視專案管理,因為軟體在建構的過程中含有太多不確定的因素,專案永遠 Delay。經常發生在產品開發後期,系統漸漸開始浮現各種 Bug 與不穩定的徵兆,越後期的版本提交期限 Delay 機會越高。持續整合就是為了避免這樣的情形發生,我認為持續整合最大的好處在於能夠「掌握軟體開發節奏」!
蛤?什麼是軟體開發節奏?這其實表示著我們對軟體開發專案的掌握性,能夠確保軟體在承諾的時間下,交付出合乎規格與品質要求的產品。在持續整合的過程中,我們會隨時將軟體當下的健康狀態透明化,這些狀態一旦透明化,問題就容易被顯現,問題進而容易被掌握與排除。而不是交付到客戶手上,才發現某個功能有問題。通常的軟體開發專案都有以下幾個願望:
- 程式設計師想踏實地寫程式
- 專案經理想確實地掌握時程
- 組織想降低成本與開發風險
- 客戶想拿到品質優良的產品
我們也希望藉由掌握軟體開發節奏讓這些願望實現!
快避免由病轉疾
若是我們長期參與低劣的軟體開發過程,久而久之就容易失去信念,失去對軟體品質的堅持,這對於組織與團隊的傷害相當大,但也因為不易根除,往往日久為患。工程師為了專案時程而加班,PM 為了時程犧牲品質。程式設計師漸漸為了趕緊搞定眼前的難題,開始不踏實地建構軟體,開始用一些奇怪的方法 (Dirty Hard Code) 解決系統自動產生的 Bug...。我想您應該明白這些奇怪的方法指的是什麼?時間一久,我們對軟體的感情就淡了,反正有了摩菲定理的加持,專案一定延遲,Bug 永遠改不完。我們面對軟體開發的複雜性,不知不覺已經由病轉疾,病可以醫的好,疾就只能控制病情了。
那持續整合到底是什麼?
假設我們能隨時掌握軟體的狀態,讓開發中軟體一切的狀態變得透明,那不是很好嗎?回到「持續整合」這個議題,簡單從字面上解釋「持續」就是「不間斷、不停地、一直、有事沒事就做一下」大概這樣的意思;那「整合」呢?在軟體開發中的整合不就是「把大家寫的 Code 在一起跑看看有沒有錯!」。以此類推「持續整合」四個字的意思就是「有事沒事就把大家寫的 Code 在一起跑看看有沒有錯!」,聽起來很簡單吧!?
我們先來講講持續整合的用意好了,我們常接觸的敏捷開發 (Agile),為了快速適應變化,常常在很短的週期 (Scrum 大約兩週) 就會發佈一個新版本,這件事在 XP (極限編程) 中稱為 Small Release。然而每一個版本發布重視的不是新增的多少功能?而是產生一個逐漸接近市場的產品。注意喔,每次發佈的軟體都必須是可以被正確執行的!在很多敏捷開發方法論都提到,可正確執行的程式碼勝過一切,當然也勝過那些該死的文件。
問題來了,要如何在短時間驗證軟體是可以正常運作的呢?如果一開始功能少還可以花點時間手動測,到後期功能多就沒辦法了,更不用說除了測試新版本的功能,還要確保既有的功能能夠運作正常。這時候「持續整合」就是發揮效用的時候了。回到剛剛提到的:「有事沒事就把大家寫的 Code 在一起跑看看有沒有錯!」這樣的事情對我們而言,其實就是自動地從版本控制系統拉 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 建置腳本,特別在測試環境的自動化建置與執行測試等等工作。雖然方法不同,但是所有的概念還是環繞在「自動化+測試+系統反饋」這三個精神上。我認為我們都需要一種義無返顧的勇氣,好讓我們持續在持續整合工作上投入心力,讓軟體變得更好!我相信我們都能打造出讓自己也能驕傲的軟體!
我們常忙著處理路上發生的狀況,而卻忘了當初為什麼要走這條路!
參考投影片
2 comments for “內修敏捷開發心法 + 外練持續整合招式”