靜態程式碼掃描為整個發展組織增加價值。無論您在開發組織中發揮的作用如何,靜態程式碼掃描解決方案都具有附加價值,擁有軟體開發中所需要的尖端功能,最大限度地提高質量並管理軟體產品中的風險。
背景
微服務架構模式具有服務間獨立,可獨立開發部署等特點,獨立開發誘發了技術上的分離,HTTP通訊增加了問題診斷的複雜度,對系統的功能、效能和安全方面的質量保障帶來了很大的挑戰。
“
微服務架構對測試的挑戰
微服務架構模式下多個獨立業務服務同時開展開發工作,每個系統都有各自的業務範圍和開發週期要求,這樣一來,下圖所示的傳統流程中產品經理提供需求,需求人員進行需求分析、開發人員進行開發,最後交給測試人員進行測試的方法,就無法滿足測試覆蓋和測試效率的要求。
相對於傳統的單體模式而言,微服務模式下對測試帶來的挑戰總結起來包括以下內容:-
1. 微服務系統模組層次化,需要保證模組內部程式碼的質量。這種場景下傳統的端到端的測試無法滿足測試要求;
-
2. 需要保證各個微服務系統內部模組間的正確性。系統模組間以及前端和後端通常會同時開展開發工作,模組間或者前後端通過介面(通常是Restful http介面)進行連線,而模組和後端往往沒有介面,為了保證各個系統單個依賴系統的正確性,因此需要藉助Mock技術隔離依賴的前提下進行介面級的測試;
-
3. 需要保證微服務系統中的介面一致性,即契約的一致性。需要通過契約測試手段保證契約的正確性,進而保證同步開發過程中的前後開發的正確性和一致性;
-
4. 需要保障單個微服務系統的正確性。需要進行元件級的測試進行微服務系統的正確性;
-
5. 需要保障整個系統的正確性。各個微服務系統串接之後通過端到端的測試保證整體系統的正確性;
“
微服務架構下如何開展測試
針對上面提到的微服務對測試的挑戰,一方面為了保證在服務各個層級上對微服務進行全面的測試,特別是對於分散式系統;另一方面又要確保測試執行的效率,這樣才能保證持續整合/持續交付(CI/CD)。因此,總體的測試策略採用如下解決方法:
-
1. 開展「質量」文化。讓開發人員建立起程式碼「質量」意識,用於保障模組內部的質量;
-
2. 採用自動化測試手段。在微服務架構中,開發分解為負責不同服務的多個小組,測試人員往往每天要花費大量的時間,瞭解不同團隊的開發進度。如果還需要手動進行迴歸測試(Regression Test),最終將會不堪重負。所以自動化測試在微服務模式下是必須採取的手段。
-
3. 分層的自動化測試策略。自動化測試分層在Mike Cohn 提出的測試金字塔(Test Pyramid)原理中進行了詳細的闡述。它提倡在程式碼級、介面級、應用級進行不同粒度的測試來保證系統的質量。從自動化測試投入比例來看,單元測試和靜態程式碼掃描的投入比例最大,其次是介面自動化測試,最後是UI自動化測試。同時為了提高測試效率和測試覆蓋率,功能測試需要藉助探索式測試手段開展測試。
- 4. 採用流水線技術進行視覺化快速反饋。由於微服務系統非常多,這樣往往會增加了運維和溝通成本,為了提高溝通效率,需要藉助流水線的技術,視覺化檢視每一個構建(Build)、測試(Test)、部署(Deploy)過程,快速做出質量反饋和處理決策。通過視覺化流水線最終可以實現各個環節的監控,採用DevOps手段打通業務、開發、測試和運維的部門牆。
靜態程式碼掃描
“
靜態程式碼掃描背景
靜態程式碼分析是指在不執行程式碼的方式下,通過詞法分析、語法分析、控制流、資料流分析等技術對程式程式碼進行掃描的技術。它的目的是驗證程式碼是否滿足規範性、安全性、可靠性、可維護性的要求。靜態程式碼掃描處於分層自動化測試的最底層,它和單元測試同級別。為了保證公司程式碼的規範性、安全性、可靠性的要求,通過定製公司級的靜態程式碼掃描規範、掃描規則和掃描實施流程保證實施高效落地。
“
靜態程式碼掃描意義
為開發者
軟體開發人員最終負責程式碼質量。程式碼質量是非功能性需求的一部分,因此是開發人員的直接責任。程式碼質量不應該存在技術債務,在開發的過程中每一步都提供反饋,從IDE到釋出。這使得開發人員能夠儘早做出有關程式碼質量的決策,使他們能夠做得更好,並提供質量更好的軟體產品。
為DevOps
DevOps需要確保軟體的構建方式正確。DevOps中涉及的責任很多,其中包括支援開發流程,自動化測試,確保質量,提高生產力.....並最終實現持續部署。良好的程式碼質量是實現所有這些目標的必要條件,儘管不是充分條件。靜態程式碼掃描可在任何構建/測試/部署步驟中新增的程式碼質量檢驗門檻,能夠自動執行一組統一的質量標準,從而確保組織交付更好的軟體。
為管理者
程式碼靜態掃描可降低風險並提高團隊生產力。管理人員需要能夠安全地執行軟體,並且需要花費合理的投資回報。我們的解決方案一目瞭然地顯示了他們面臨的技術債務以及他們緩解的成本。它還具有開箱即用的功能,可以系統地提高開發團隊的可維護性和長期生產力。這使管理人員能夠以最佳成本使用風險控制方法確保其組織能夠交付更好的軟體。
“
靜態程式碼掃描介紹
靜態程式碼掃描處在特性分支開發完成之後,具體的描述如下:
-
1. 開發人員從Master分支拉取特性分支作為開發分支;
-
2. 開發完特性分支後、程式碼構建、單元測試、靜態程式碼掃描;
-
3. 通過後合併到Master分支,用於投產;
“
靜態程式碼掃描流程
隨行付靜態程式碼掃描平臺的具體實現是通過整合SonarQube平臺工具、Jenkins整合工具、IDE SonarLint外掛和CheckStyle本地化規則模板等開源工具、外掛集而成。實現本地化程式碼的實施檢測,版本構建後的二次檢測,以及郵件反饋等功能的流程閉環,保證投產前程式碼符合隨行付程式碼規範的要求。具體的流程如下圖所示:
- 1.本地化IDE中通過SonarLint外掛實現和SonarQube平臺規則、規範的同步、實現原生程式碼檢查;隨行付定製化了java規則、XML規則257條,javascript規則86條,用於檢測程式碼的規範性、程式碼缺陷、漏洞、壞味道、重複率等資訊。並將定製化的規則放到了SonarQube平臺上,SonrLint外掛的規則比較全面,包括所有的sonajava規則和javascript規則,為了保證本地使用定製的規則,且同sonarqube中的規則一致,需要遠端連線SonarQube伺服器,並繫結專案。以Eclipse為例,展示SonarQube連線和專案繫結過程:
- 2.程式碼提交到程式碼庫GitLab中後,在Jenkins中測試環境構建時,自動觸發Sonar掃描,並將掃描結果釋出到SonarQube平臺。下圖為SonarQube展示的一個專案的結果:
- 3.SonarQube平臺根據質量閥的要求,不滿足質量閥要求則郵件通知開發人員。
質量閥要求:
1.新覆蓋率大於等於80%;
2.新增Bugs為0;
3.新增漏洞為0;
4.新增壞味道為0;
複製程式碼
-
4.開發人員收到郵件後,進行程式碼處理,直到滿足規範要求為止。
-
5.以周為單位統計SonarQube平臺中靜態程式碼掃描出來的Bugs\漏洞\壞味道的數量,定時自動傳送週報給相關干係人,報告中會包含問題處理情況的趨勢圖。
SonarQube是一個用於程式碼質量管理的開源平臺,支援25+種程式語言的質量掃描。SonqrQube由遠端機、Server端和資料庫構成。遠端客戶機可以通過各種不同的分析機制,從而將被分析的專案程式碼上傳到SonarQube server 並進行程式碼質量的管理和分析,SonarQube 還會通過Web API將分析的結果以視覺化、可度量的方式展示給出來。邏輯結構如下圖所示:
“
SonarQube的整合能力
SonarQube平臺中支援整合各種靜態程式碼掃描檢測工具。SonarQube中各種程式碼檢測工具分析物件及應用技術對比:
Java靜態分析工具 | 分析物件 | 應用技術 |
---|---|---|
CheckStyle | Java原始檔 | 缺陷模式匹配 |
FindBugs | 位元組碼 | 缺陷模式匹配;資料流分析 |
PMD | Java原始碼 | 缺陷模式匹配 |
CheckStyle
可以很方便的幫我們檢查Java程式碼中的格式錯誤,它能夠自動化程式碼規範檢查過程,從而使得開發人員從這項重要,但是枯燥的任務中解脫出來。基本上都是根據開發規則定製規則。主要涵蓋以下內容:
-
Javadoc 註釋:檢查類及方法的 Javadoc 註釋
-
命名約定:檢查命名是否符合命名規範
-
標題:檢查檔案是否以某些行開頭
-
Import 語句:檢查 Import 語句是否符合定義規範
-
程式碼塊大小,即檢查類、方法等程式碼塊的行數
-
空白:檢查空白符,如 tab,回車符等
-
修飾符:修飾符號的檢查,如修飾符的定義順序
-
塊:檢查是否有空塊或無效塊
-
程式碼問題:檢查重複程式碼,條件判斷,魔數等問題
-
類設計:檢查類的定義是否符合規範,如建構函式的定義等問題
FindBugs
Findbugs是一個靜態分析工具,它檢查類或者JAR檔案,將位元組碼與一組缺陷模式進行對比以發現可能的問題。主要涵蓋以下內容:
-
Bad practice 壞的實踐:常見程式碼錯誤,用於靜態程式碼檢查時進行缺陷模式匹配
-
Correctness 可能導致錯誤的程式碼,如空指標引用等
-
國際化相關問題:如錯誤的字串轉換
-
可能受到的惡意攻擊,如訪問許可權修飾符的定義等
-
多執行緒的正確性:如多執行緒程式設計時常見的同步,執行緒排程問題
-
執行時效能問題:如由變數定義,方法呼叫導致的程式碼低效問題
PMD
一種開源分析Java程式碼錯誤的工具,其原理為使用JavaCC生成解析器來解析原始碼並生成AST(抽象語法樹)。與其他分析工具不同的是,PMD通過靜態分析獲知程式碼錯誤。也就是說,在不執行Java程式的情況下報告錯誤。PMD附帶了許多可以直接使用的規則,利用這些規則可以找出Java源程式的許多問題,例如:
-
潛在的 Bugs:檢查潛在程式碼錯誤,如空的 try/catch/finally/switch 語句
-
未使用程式碼(Dead code):檢查未使用的變數,引數,方法等
-
可選的程式碼:String/StringBuffer的濫用
-
複雜的表示式:檢查不必要的 if 語句,可被 while 替代的 for 迴圈
-
重複的程式碼:檢查重複的程式碼
-
迴圈體建立新物件:檢查在迴圈體內例項化新物件
-
資源關閉:檢查 Connect,Result,Statement 等資源使用之後是否被關閉掉
此外,使用者還可以自己定義規則,檢查Java程式碼是否符合某些特定的編碼規範。例如,你可以編寫一個規則,要求PMD找出所有建立Thread和Socket物件的操作。
三種工具對比
由表中可以看出幾種工具對於程式碼檢查各有側重。其中,Checkstyle 更偏重於程式碼編寫格式,及是否符合編碼規範的檢驗, 對程式碼 bug 的發現功能較弱;而 FindBugs,PMD著重於發現程式碼缺陷。在對程式碼缺陷檢查中,這三種工具在針對的程式碼缺陷類別也各有不同,且類別之間有重疊。“
規則定製
考慮到Sonar Java規則已經包含了PMD和CheckStyle規則,因此我們選擇了Sonar的預設規則,並對其進行了定製化。下圖中SonarQube中展示了部分定製化規則內容。
定製化後的規則覆蓋的程式碼缺陷型別如下表所示(部分規則):
程式碼缺陷分類 | 示例 |
---|---|
引用操作 | 空指標引用 |
物件操作 | 物件比較(使用==而不是equals) |
表示式複雜化 | 對於的if語句 |
陣列使用 | 陣列下標越界 |
未使用變數或程式碼段 | 未使用變數 |
資源回收 | I/O未關閉 |
方法呼叫 | 未使用方法返回值 |
程式碼設計 | 空的try/catch/finally塊 |