Dev Talks

5xRuby如何透過持續整合,維持高品質程式碼

5xRuby Technolgy Director QiuZhengXian
蒼時弦也 / 邱政憲, 技術總監 Mar 12, 2021

程式碼品質之所以重要,不僅與專案品質有關,更關乎維護便利性。為了提供優質程式碼給客戶,我們從 2016 年起逐步導入單元測試、整合測試等技巧來保障客戶的專案,能以最高品質完成。

從撰寫方式開始,打造優質系統

有經驗的工程師都懂,撰寫測試不是確保程式碼品質的保證,更重要的是在撰寫中反覆思考,最後在符合客戶需求下選擇適合的方式撰寫。

如果一個專案的程式碼沒有經過反覆思考及提煉,未來開發中我們會發現,想拓展功能時會逐漸出現難以擴充的狀況,同時也會有越來越多效能和維護問題,導致我們無法快速開發新功能和維護產品。

在五倍紅寶石,我們如何訓練工程師思考及提煉撰寫出來的程式碼?透過靜態分析、單元測試等方式。為了讓成品能通過靜態分析建議的風格與撰寫方式檢驗,我們在進行程式碼審查(Code Review)時,會針對不夠滿足標準的程式碼逐一討論,根據審查建議來確認不同語法的撰寫差異,確保程式碼是否能在變數命名、閱讀流程的狀況下以語意化方式表達意圖。

除此,我們也要求工程師對自己的程式碼撰寫單元測試。在大多數學習階段裡,我們所處理的專案不會太複雜,但因應客戶商業邏輯以及客製化設計的,驗證會越來越複雜。因此我們針對每一個商業邏輯進行分析、檢討,藉此產出適合的介面規劃,再透過單元測試的驗證沒有將過度複雜的邏輯封裝在物件中,能以單純的方式進行呼叫跟拆分。

這裡我們用生活化的方式舉例。

假設現在要製造一個衣櫃。衣櫃的製程可分為規劃設計、裁切木料、鑽五金孔、接合、打磨、上漆等步驟。而任一個步驟裡面又再可細分為小步驟,例如在規劃設計階段,有選料、丈量現場尺寸、抽屜設計、門開關設計、櫃內空間丈量等各種設計要做。而裁切木料又有分選木紋、選質地...等等。每個步驟內都還包含無數個步驟。

如果一個工序本身內容設計得太過複雜,那麼出錯時追蹤就會變得困難。

例如木料接合時發現五金件鎖上去門卻關不起來,有可能是負責選料的人選錯五金件,也有可能是設計師丈量錯尺寸,但到了這個階段,因為已經堆疊太多工作在上面,難以查出是哪個部分導致門板鎖上去了卻關不起來,也只能拆掉重來。

將過度複雜的邏輯封裝在物件中正如同這樣,當有錯誤發生時,糾錯和除錯會花非常多工夫。所以我們盡可能小範圍檢查,如此能很好追查每一工作階段是否正確,出錯時也能協助工程師更有效修復錯誤。

上面所提到的,衣櫃的製成步驟:選木料、標示螺絲位置、鑽孔等步驟,就可視為「單元」,前面提到的單元測試,就是在檢核每個動作是否做得正確,若每個單元(動作)都能通過測試,最後組合起來運作時的錯誤率自然也會下降。

實踐單元測試,完整實現客戶期待

如上面所舉例的,單元測試對於如何建構穩定的系統來說,至關重要。

不過對大多數工程師來說,撰寫測試是一大門檻,所以從養成撰寫測試習慣到理解及善用測試,一直都是我們追求的目標。撰寫測試時,我們要求測試簡潔、乾淨。以 Rubocop 的建議作為範例,通常一個測試案例不應該存在過多的參考變數,這很直觀的反映出我們在一個測試中是否設定了太多條件,同時也反映了原本的物件有過度複雜及參數太多等可能性。

這是因為當我們設計過度複雜的邏輯時,將非常難以測試(請見上個段落的範例)。也因此,我們鼓勵工程師討論、分析原始碼是否能夠實踐 SOLID 中的各項原則,進而達到「單元」測試的目標。

在撰寫測試時,我們也不斷反思,複雜設計對維護造成的挑戰,以及當相依第三方服務時,如何在單元測試中切割,並在整合測試及其他類檢驗中被順利實現。

除了致力改善原始碼品質,善用測試讓我們對修改程式碼以及重構增加更多的信心。除了自己撰寫的程式碼外,我們能善用各種測試技巧逐步改善客戶難以自行維護的專案,讓長期維護與營運變得可能。

標準化程式碼風格,提升撰寫品質

在專案開發中,我們固定啟用 Rubocop 來作為靜態分析的工具。我們會先根據習慣設定出標準風格指南,用來幫助剛加入的夥伴,快速熟悉在五倍紅寶石工作應有的程式碼風格。這個指南也能針對被分析工具偵測出來的問題,向新進工程師說明我們在程式碼撰寫上的思考方式及邏輯。

透過這種方式,我們的工程師大多能在兩週內改正習慣,並且交付一定水準的原始碼,有助人力調整時減少轉換成本。

嚴格資安審核,交付安全專案

資安領域是非常專業的學問,而五倍紅寶石在使用 Ruby on Rails 上經驗豐富,加上開發框架輔助,能避免非常多低級的安全性問題。為了不讓我們在資安意識上放鬆警戒,我們在每個專案都設置 Breakman 以及 Bundler Audit 兩套工具,前者跟 Rubocop 同樣作為靜態分析的工具,但能夠幫助我們針對 Ruby on Rails 中被忽略的問題程式碼進行警告,讓工程師時時對資安問題保持一定警覺。

Bundler Audit 則提供完整Ruby 套件漏洞資料庫,我們在開發過程中會不斷抓取最新漏洞資訊,第一時間更新有問題的套件,提供我們的客戶最安全且穩定的專案。

持續整合,加速開發效率

上述的分析檢驗步驟如果交由工程師各自執行跟驗證,容易有所缺漏。我們利用內部 GitLab 提供的持續整合工具,搭建大量檢查點,使每一次工程師發送合併請求 (Merge Request) 以及在其他專案運行的階段時,能經過不同工具的層層把關檢驗,藉此加快開發速度以及程式碼審核效率,提供客戶更佳的開發效率。

use CI tools provided by GitLab to build checkpoints

由上圖可以觀察到,我們不論在後端還是前端都設定對應檢查,嚴格檢視工程師在開發上的產出。透過持續整合維持專案原始碼的健康及穩定,快速培養出能夠穩定產出高品質原始碼的工程師。

監控品質,持續改善程式

為了能更加全面了解每個專案的品質與發展,我們也導入 SonarQube 作為品質分析控制台,透過將持續整合搜集回來的報告統合到 SonarQube ,檢驗每個專案是否持續正面發展,以及測試的覆蓋率、壞味道(Bad Smell)*註1、技術債等是否都有不斷改善。

Monitoring Quality and Continuously Improving Programs

透過這些工具,我們不斷改進五倍紅寶石在開發中提供客戶的程式碼品質,不斷與時俱進。

註1:壞味道泛指對程式可能造成問題的程式碼,有可能是過長或者難以理解的程式碼,或是過度依賴某些功能無法很好拆分等情況都屬於壞味道。

總結

程式碼品質對我們來說是非常基本的要求。透過改善程式碼品質,持續強化客戶的商業需求開發速度,協助客戶更快插旗市場版圖。交付原始碼給客戶的團隊時,也大量減少客戶團隊理解原始碼的時間,消除未來可能出現的隱患。

作為五倍紅寶石的技術總監,交付給客戶最高品質的原始碼是我們全團隊的任務與永不止息的追求。


分享