提前在開發階段暴露代碼問題,攜程Alchemy代碼質量平臺
一、背景
隨著敏捷開發,DevOps開發模式的流行,代碼質量分析作為研發質量保證體系的重要組成部分,不僅能有效的降低因頻繁迭代帶來的故障風險,而且對整個工程團隊的效能提升有著巨大的價值。
攜程很久以前就已經開始進行DevOps的建設,通過Gitlab CI/CD在開發提交代碼觸發的流水線pipeline中引入靜態掃描、單元測試、集成測試等流程,在開發過程中打造了一套閉環的代碼質量保障體系。其中,在靜態代碼分析階段引入了SonarQube,并且通過對原有SonarQube代碼規范庫中的規范進行篩選和擴展,形成了自己的代碼規范庫。但是在實際應用過程中,我們發現仍然有一些問題需要優化解決:
- 在開發過程中,代碼規范只能通過開發人員自我約束,缺少統一的平臺對各應用代碼的潛在風險問題統一進行分析,且問題難以定位到開發人員進行治理。
- 代碼單元測試通過率和代碼覆蓋率都很高,但仍然存在一些在單元測試階段應被發現的問題未暴露出來,導致上線后出現bug,單元測試用例的質量缺乏有效性及可靠性保證。
- 隨著項目的發展,開發人員為了避免影響已有功能,在開發過程中大量復制粘貼,導致出現很多難以維護的重復代碼,且程序邏輯結構過于復雜,修改邏輯牽一發而動全身,可維護性差。
- 代碼中充斥著大量的sql拼接,以及一些不規范的寫法導致潛在的問題,需要對此類代碼進行治理。
二、平臺介紹
Alchemy平臺是一個代碼質量分析平臺,提供Infer分析、代碼分析、自定義掃描、代碼搜索等功能,其中代碼質量分析內容包含代碼行,sonar問題, infer問題,UT規則,重復代碼以及圈復雜度等。用戶可以根據自己的需求在平臺上進行掃描項配置,并查看應用的代碼質量分析結果。
為了及時獲得對提交代碼變更的質量反饋,作為DevOps中重要的一環,Alchemy平臺與Gitlab CI/CD相結合,將靜態代碼分析提前至開發提交或合并代碼階段。開發人員提交代碼至Gitlab,觸發流水線相關任務執行,任務執行完成之后可以對某些指標(如增量代碼引入的空指針)設置紅線進行卡點,如果指標在指定范圍內,允許合并代碼并發布,如果指標超過了紅線設置范圍,則不允許合并代碼,開發人員修復問題后再次提交代碼進行流水線的集成發布。掃描分析結果可以在Gitlab或者Alchemy平臺上展示,幫助開發人員在快速迭代的同時保證代碼質量。
靜態代碼掃描流程
三、系統架構
Alchemy平臺包含Alchemy-client、Alchemy-service和Alchemy-web。其中,Alchemy-client為掃描腳本,包含Infer分析,UT掃描,重復代碼掃描、自定義掃描等功能,集成到Docker鏡像中,Alchemy-service提供數據存儲、分析等后臺服務,且依賴代碼搜索服務CodeSearch-Service實現代碼搜索功能,Alchemy-web負責頁面交互。
開發人員提交代碼,觸發Gitlab CI/CD中靜態代碼分析job在GitRunner中執行,執行時先從Docker倉庫下載鏡像,啟動容器后執行Alchemy-client腳本,腳本會根據平臺配置來執行相應的掃描任務,掃描完成后,將結果上傳至Alchemy-service,存儲到mongodb數據庫,最終在前端頁面展示分析結果。
Alchemy架構圖
四、功能
4.1 Infer分析
Infer是Facebook出品的一個靜態分析工具,可以分析Java、Objective-c或者C代碼,報告潛在的問題,包括空指針,資源泄漏等。Alchemy平臺將Infer引入代碼靜態分析階段,目前已支持全量和增量分析兩種模式。
全量模式需分析應用倉庫中的所有代碼,能分析出所有代碼引入的潛在問題,對于代碼量較大的應用,由于需要分析所有代碼文件,掃描時間比較長,在一定程度上影響開發發布進度,且對未修改的代碼進行了非必要的重復分析,在代碼修改量較少的情況下造成資源浪費。因此,我們嘗試加入緩存機制,并引入了增量分析模式,增量模式需要獲取本次提交修改的文件,在分析階段只針對這些改動文件進行分析,能大大節省分析時間。Infer分析流程如下:
Infer分析流程圖
在分析過程中,首先判斷是否為第一次分析,如果沒有分析歷史記錄,則系統默認采用全量模式,否則需判斷Infer掃描配置,若配置為全量模式,則分析此代碼工程的全部文件,若配置為增量模式,需獲取此次提交修改的文件列表,編譯過程完成之后,在分析階段指定文件列表進行分析。獲取到分析出的問題列表后,判斷問題所在的行是否為修改行,如果是,則記錄為本次修改導致的新增問題,否則為歷史遺留的全量問題。
在實際應用中,針對封裝的判空方法,通過添加@TrueOnNull或@FalseOnNull注解,可識別對象的判空操作。但對于第三方包的判空方法,如CollectionUtils.isEmpty(), 由于未添加注解,即使添加判空方法,仍會被誤識別為空引用。因此,Alchemy平臺加入了忽略操作,針對此類問題進行二次確認,避免重復誤判。
Infer誤判結果
4.2 UT規則掃描
單元測試是DevOps流程中一個非常重要的環節,我們可以利用通過率和代碼覆蓋率等指標來衡量單元測試用例的完整程度,卻很難保證用例的有效性。阿里巴巴java開發手冊規定,單元測試不允許使用System.out來進行人肉驗證,必須使用斷言assert來驗證。
在實際的開發過程中,開發人員把主要的時間用在寫業務邏輯代碼上,在編寫單元測試用例時,往往容易忽略對結果的驗證,雖然通過率和代碼覆蓋率很高,但上線后仍然出現未對接口結果進行驗證而導致嚴重問題的情況。無效的單元測試用例包含以下幾種:
- 空函數:函數體為空;
- 空斷言:用例中實現了對被測接口的調用邏輯,但未對接口返回結果進行驗證;
- 偽斷言:用例中使用類似assertTrue(True)的假斷言。
通過掃描空斷言、空函數、偽斷言等問題,能判斷該用例是否對代碼邏輯進行必要的驗證。Alchemy平臺支持單元測試用例的有效性驗證,目前,平臺支持Java、Kotlin、Groovy和Nodejs,同時也支持全量和增量2種掃描結果,全量結果即為所有測試用例中不滿足規則的用例,增量結果為本次提交修改的測試用例中不滿足規則的用例。
UT掃描流程
對單個單元測試文件的掃描流程如圖。首先根據文件后綴判斷語言類型,然后根據不同語言類型規則獲取該文件中的用例信息,包含case名稱、起止行、作者、最近修改時間、函數內容等,針對函數內容,先判斷用例是否有斷言,如果有,則判斷是否為偽斷言,如果未斷言或者被判為偽斷言,還需進一步根據用例的起止行,結合本次提交的改動信息,分析該用例是否為增量改動的用例,如果是則標記為增量問題,最后將結果推送給gitlab,在合并代碼或發布時根據紅線配置進行卡點。掃描結果如圖所示。
UT掃描結果
4.3 重復代碼掃描
重復代碼即為重復或近似的代碼,在開發過程中,開發人員為了避免影響現有功能,使用復制粘貼快速完成開發任務,導致出現大量的重復代碼。重復代碼不僅讓代碼量大增,造成編譯速度慢,而且占用大量存儲空間,如果想要修改其中一段代碼邏輯,則需要同時修改多個地方,容易遺漏,可維護性差。
當前市面上有很多代碼檢測工具,如Simian,PMD-CPD,CloneDR等,由于在實現算法上有所不同,不同工具所能檢測的重復代碼類型也不盡相同。我們利用PMD-CPD掃描代碼倉庫,可以檢測出單文件或多個文件中除了空格、注釋、換行以及變量名以外內容完全一致的代碼段信息,這些信息包含文件路徑、代碼段內容、起止行以及作者信息,詳情結果如圖所示。
重復代碼詳情結果
4.4 自定義規則掃描
Alchemy支持對自定義規則的掃描,通過配置自定義正則表達式和掃描范圍,識別代碼文件中滿足配置規則的代碼段,可用于掃描代碼中的拼接SQL,敏感詞等,并且可將不合規的代碼定位到相關開發人員。
自定義掃描流程
單個文件掃描流程如圖,首先判斷文件是否在掃描范圍內,若不在則直接跳轉掃描下一個文件,否則讀取文件內容,同時根據文件類型獲取對應的自定義規則,匹配滿足規則的代碼段信息,包含代碼段內容、嚴重程度、起止行、作者等。在某些場景下,需要設置子規則進行二次匹配,比如掃描update未指定where條件的sql語句,可先根據規則找到update語句,然后根據子規則判斷是否帶where條件,最終記錄二次匹配的結果。
4.5 代碼分析
使用不同工具統計的代碼質量指標可能分散在不同的平臺,對這些指標進行全面分析的過程中難免會有所遺漏,特別是對于未設置發布卡點的指標,開發人員可能并不會關注它們,導致代碼存在大量的潛在問題未被分析治理。
Alchemy代碼分析模塊可以對代碼不同維度的指標進行統計分析,包括代碼行、單元測試、infer問題、Sonar問題、重復代碼、圈復雜度等。用戶可以在代碼分析頁面查看各維度問題分布情況,從而對項目的整體風險指標進行更全面的分析,可以根據問題的嚴重程度設置優先級進行針對性的治理。
代碼分析結果
4.6 代碼搜索
在開發過程中,對于一些公共操作如中間件的使用方式,開發人員可能需要四處尋找接入文檔。Alchemy提供代碼搜索功能,可以幫助開發人員根據關鍵詞來查找收錄項目中的代碼使用示例,用戶可以根據項目倉庫、代碼語言以及作者等條件進行細分查詢。在編碼過程中,命名規范是一個容易被忽視的問題,使用Alchemy的變量命名功能,用戶可以根據不同語言,搜索中英文關鍵詞來獲取推薦的規范命名參考,能極大地提高開發效率。
?
代碼搜索結果
五、結束語
在本文中,我們介紹了Alchemy平臺提供的代碼靜態分析,代碼探索以及通過與Gitlab CI/CD集成帶來的持續集成能力,可以在開發階段暴露出更多的代碼潛在問題和風險,并及時反饋給相關人員。目前攜程酒店已接入項目800+,且在開發提交代碼和發布階段將分析的潛在問題接入了卡點流程。在后續的工作中,我們將從以下幾個方向進行進一步的優化:
- 在代碼分析層面支持更多語言;
- 開發IDE插件,在編碼階段實時掃描代碼;
- 繼續深挖代碼風險指標,并引入評估機制。