天天看點

提前在開發階段暴露代碼問題,攜程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平台包含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代碼品質平台

Alchemy架構圖

四、功能

4.1 Infer分析

Infer是Facebook出品的一個靜态分析工具,可以分析Java、Objective-c或者C代碼,報告潛在的問題,包括空指針,資源洩漏等。Alchemy平台将Infer引入代碼靜态分析階段,目前已支援全量和增量分析兩種模式。

全量模式需分析應用倉庫中的所有代碼,能分析出所有代碼引入的潛在問題,對于代碼量較大的應用,由于需要分析所有代碼檔案,掃描時間比較長,在一定程度上影響開發釋出進度,且對未修改的代碼進行了非必要的重複分析,在代碼修改量較少的情況下造成資源浪費。是以,我們嘗試加入緩存機制,并引入了增量分析模式,增量模式需要擷取本次送出修改的檔案,在分析階段隻針對這些改動檔案進行分析,能大大節省分析時間。Infer分析流程如下:

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

Infer分析流程圖

在分析過程中,首先判斷是否為第一次分析,如果沒有分析曆史記錄,則系統預設采用全量模式,否則需判斷Infer掃描配置,若配置為全量模式,則分析此代碼工程的全部檔案,若配置為增量模式,需擷取此次送出修改的檔案清單,編譯過程完成之後,在分析階段指定檔案清單進行分析。擷取到分析出的問題清單後,判斷問題所在的行是否為修改行,如果是,則記錄為本次修改導緻的新增問題,否則為曆史遺留的全量問題。

在實際應用中,針對封裝的判空方法,通過添加@TrueOnNull或@FalseOnNull注解,可識别對象的判空操作。但對于第三方包的判空方法,如CollectionUtils.isEmpty(), 由于未添加注解,即使添加判空方法,仍會被誤識别為空引用。是以,Alchemy平台加入了忽略操作,針對此類問題進行二次确認,避免重複誤判。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

Infer誤判結果

4.2 UT規則掃描

單元測試是DevOps流程中一個非常重要的環節,我們可以利用通過率和代碼覆寫率等名額來衡量單元測試用例的完整程度,卻很難保證用例的有效性。阿裡巴巴java開發手冊規定,單元測試不允許使用System.out來進行人肉驗證,必須使用斷言assert來驗證。

在實際的開發過程中,開發人員把主要的時間用在寫業務邏輯代碼上,在編寫單元測試用例時,往往容易忽略對結果的驗證,雖然通過率和代碼覆寫率很高,但上線後仍然出現未對接口結果進行驗證而導緻嚴重問題的情況。無效的單元測試用例包含以下幾種:

  • 空函數:函數體為空;
  • 空斷言:用例中實作了對被測接口的調用邏輯,但未對接口傳回結果進行驗證;
  • 僞斷言:用例中使用類似assertTrue(True)的假斷言。

通過掃描空斷言、空函數、僞斷言等問題,能判斷該用例是否對代碼邏輯進行必要的驗證。Alchemy平台支援單元測試用例的有效性驗證,目前,平台支援Java、Kotlin、Groovy和Nodejs,同時也支援全量和增量2種掃描結果,全量結果即為所有測試用例中不滿足規則的用例,增量結果為本次送出修改的測試用例中不滿足規則的用例。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

UT掃描流程

對單個單元測試檔案的掃描流程如圖。首先根據檔案字尾判斷語言類型,然後根據不同語言類型規則擷取該檔案中的用例資訊,包含case名稱、起止行、作者、最近修改時間、函數内容等,針對函數内容,先判斷用例是否有斷言,如果有,則判斷是否為僞斷言,如果未斷言或者被判為僞斷言,還需進一步根據用例的起止行,結合本次送出的改動資訊,分析該用例是否為增量改動的用例,如果是則标記為增量問題,最後将結果推送給gitlab,在合并代碼或釋出時根據紅線配置進行卡點。掃描結果如圖所示。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

UT掃描結果

4.3 重複代碼掃描

重複代碼即為重複或近似的代碼,在開發過程中,開發人員為了避免影響現有功能,使用複制粘貼快速完成開發任務,導緻出現大量的重複代碼。重複代碼不僅讓代碼量大增,造成編譯速度慢,而且占用大量存儲空間,如果想要修改其中一段代碼邏輯,則需要同時修改多個地方,容易遺漏,可維護性差。

目前市面上有很多代碼檢測工具,如Simian,PMD-CPD,CloneDR等,由于在實作算法上有所不同,不同工具所能檢測的重複代碼類型也不盡相同。我們利用PMD-CPD掃描代碼倉庫,可以檢測出單檔案或多個檔案中除了空格、注釋、換行以及變量名以外内容完全一緻的代碼段資訊,這些資訊包含檔案路徑、代碼段内容、起止行以及作者資訊,詳情結果如圖所示。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

重複代碼詳情結果

4.4 自定義規則掃描

Alchemy支援對自定義規則的掃描,通過配置自定義正規表達式和掃描範圍,識别代碼檔案中滿足配置規則的代碼段,可用于掃描代碼中的拼接SQL,敏感詞等,并且可将不合規的代碼定位到相關開發人員。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

自定義掃描流程

單個檔案掃描流程如圖,首先判斷檔案是否在掃描範圍内,若不在則直接跳轉掃描下一個檔案,否則讀取檔案内容,同時根據檔案類型擷取對應的自定義規則,比對滿足規則的代碼段資訊,包含代碼段内容、嚴重程度、起止行、作者等。在某些場景下,需要設定子規則進行二次比對,比如掃描update未指定where條件的sql語句,可先根據規則找到update語句,然後根據子規則判斷是否帶where條件,最終記錄二次比對的結果。

4.5 代碼分析

使用不同工具統計的代碼品質名額可能分散在不同的平台,對這些名額進行全面分析的過程中難免會有所遺漏,特别是對于未設定釋出卡點的名額,開發人員可能并不會關注它們,導緻代碼存在大量的潛在問題未被分析治理。

Alchemy代碼分析子產品可以對代碼不同次元的名額進行統計分析,包括代碼行、單元測試、infer問題、Sonar問題、重複代碼、圈複雜度等。使用者可以在代碼分析頁面檢視各次元問題分布情況,進而對項目的整體風險名額進行更全面的分析,可以根據問題的嚴重程度設定優先級進行針對性的治理。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

代碼分析結果

4.6 代碼搜尋

在開發過程中,對于一些公共操作如中間件的使用方式,開發人員可能需要四處尋找接入文檔。Alchemy提供代碼搜尋功能,可以幫助開發人員根據關鍵詞來查找收錄項目中的代碼使用示例,使用者可以根據項目倉庫、代碼語言以及作者等條件進行細分查詢。在編碼過程中,命名規範是一個容易被忽視的問題,使用Alchemy的變量命名功能,使用者可以根據不同語言,搜尋中英文關鍵詞來擷取推薦的規範命名參考,能極大地提高開發效率。

提前在開發階段暴露代碼問題,攜程Alchemy代碼品質平台

代碼搜尋結果

五、結束語

在本文中,我們介紹了Alchemy平台提供的代碼靜态分析,代碼探索以及通過與Gitlab CI/CD內建帶來的持續內建能力,可以在開發階段暴露出更多的代碼潛在問題和風險,并及時回報給相關人員。目前攜程酒店已接入項目800+,且在開發送出代碼和釋出階段将分析的潛在問題接入了卡點流程。在後續的工作中,我們将從以下幾個方向進行進一步的優化:

  • 在代碼分析層面支援更多語言;
  • 開發IDE插件,在編碼階段實時掃描代碼;
  • 繼續深挖代碼風險名額,并引入評估機制。

【作者簡介】 Lyan,攜程資深後端開發工程師,負責自動化測試架構及平台類工具開發,關注Devops、研發效能領域。

繼續閱讀