黃 緯, 黃曉華, 張 源, 陳 翔, 錢柱中
(1. 南京工程學院 計算機工程學院, 南京 211167; 2. 北京中電普華信息技術有限公司, 北京102208;3. 南通大學 信息科學技術學院, 江蘇 南通 226019; 4. 南京大學 計算機科學與技術系, 南京 210023)
軟件缺陷產(chǎn)生于開發(fā)人員的編碼過程. 軟件開發(fā)人員對軟件需求的理解不正確、 對軟件開發(fā)過程設計不合理或者開發(fā)人員自身的經(jīng)驗不足等因素都可能產(chǎn)生軟件缺陷. 含有缺陷的軟件在應用后會產(chǎn)生不可預知的結果, 從而影響軟件的正常使用. 軟件缺陷分析技術[1-5]是避免軟件發(fā)生運行故障的一種可行方法, 在軟件工程領域已得到廣泛關注. 軟件缺陷分析技術通過挖掘軟件代碼倉庫(如缺陷跟蹤系統(tǒng)和版本控制系統(tǒng)), 分析軟件歷史開發(fā)數(shù)據(jù)以及軟件運行故障等信息, 借助機器學習等技術構建缺陷分析模型以識別新軟件模塊是否存在缺陷. 軟件缺陷分析的目的是在軟件正式發(fā)布前盡可能多地找到潛在的缺陷程序模塊, 以便優(yōu)化測試資源, 提高軟件質(zhì)量. 軟件缺陷分析主要包括兩個階段: 模型構建階段和模型應用階段. 模型構建階段首先挖掘并收集軟件代碼倉庫和缺陷跟蹤系統(tǒng); 然后設計度量元指標并對程序模型進行度量元取值的量化以及對模塊是否含有缺陷進行標注; 最后基于標注的數(shù)據(jù)集, 進行必要的數(shù)據(jù)預處理(如數(shù)據(jù)取值歸一化、 特征選擇、 噪聲移除等)后, 使用特定的機器學習方法(如樸素Bayes和決策樹等)完成模型的構建. 在模型應用階段, 對新的程序模塊, 首先對其按照度量元進行量化, 然后將其輸入到模型中進行分析, 以判斷新產(chǎn)生的模塊是否含有缺陷.
目前, 研究人員已提出了多種軟件缺陷分析方法, 并且驗證了這些方法的有效性[6-9]. 但大多數(shù)的軟件缺陷分析方法都只關注于識別粗粒度代碼模塊(類/文件/模塊)中的缺陷. 盡管這些方法在一些情況下可行, 但其缺陷阻礙了其在實際場景中的應用, 特別是在測試資源受限的情況下. 因此, 研究人員又提出了新的軟件缺陷分析方法, 這些方法能識別出細粒度代碼模塊(如代碼變更)中存在的缺陷[10-14]. 近年, 基于代碼變更的軟件缺陷分析已引起研究人員的廣泛關注, 因為其能精細、 及時地幫助開發(fā)人員識別軟件中有缺陷傾向的模塊[15-17].
基于代碼變更的缺陷分析方法通常稱為即時軟件缺陷分析, 因為其能識別在軟件更新瞬間引入缺陷的變更. 引入缺陷的變更是指引入一個或者一些缺陷使軟件失效[18]的代碼修改. 相比于粗粒度的缺陷分析, 即時軟件缺陷分析有如下優(yōu)點:
1) 在細粒度的級別進行分析, 被識別出引入缺陷的變更被鏈接到特定的代碼修改部分, 極大的縮小了代碼搜索的范圍;
2) 將分析結果反饋給最合適的開發(fā)者, 被識別出的引入缺陷變更被鏈接到特定的代碼修改部分, 能迅速地找到具體是哪一個開發(fā)者對這段代碼進行的修改, 并將修復這些缺陷的任務指派給相應的開發(fā)者;
3) 在代碼提交時進行分析, 新的代碼變更在提交到代碼倉庫時, 能及時的被分類成有缺陷的或無缺陷的變更.
目前, 有監(jiān)督的軟件缺陷分析方法受到廣泛關注. Kim等[25]提出了一個模型, 該模型利用文件名、 更改的元數(shù)據(jù)、 更改的日志等幾個基于代碼變更的特性分類一個代碼變更是否含有缺陷; Yin等[26]在開源系統(tǒng)上(包括Linux,OpenSolaris,FreeBSD和成熟的商業(yè)軟件)研究了引入缺陷的代碼變更和修復缺陷的代碼變更之間的關系; Shihab等[16]為更好地理解有缺陷的代碼變更而開發(fā)了一個工具, 以幫助開發(fā)人員在提交代碼變更的同時對其進行有缺陷或者無缺陷的標記. 在實際應用中, 由于資源受限, Kamei等[20]首先提出了代價感知方法EALR, 并在開源項目和商業(yè)項目上進行了大規(guī)模的實證研究, 他們使用修改的代碼行數(shù)作為檢查代碼變更所需工作量的一種代理; Yang等[27-28]先后提出了兩種方法, 傾向于使用先進和復雜的技術(即集成學習和深度學習)分析軟件缺陷. Nayrolles等[29]使用代碼克隆檢測技術提出了一種可捕獲具有缺陷傾向性的代碼變更方法CLEVER, CLEVER包含兩個階段: 在第一階段, CLEVER評估代碼變更成為有缺陷變更的可能性; 在第二階段, CLEVER采用克隆檢測截獲前一階段識別出的易發(fā)生缺陷的代碼變更. Huang等[11]提出了一個簡單的改進有監(jiān)督模型CBS, 該模型認為較小的模塊會等比例地出現(xiàn)缺陷, 因此應被優(yōu)先檢查, CBS包括兩個階段: 構建分類器階段和對用于測試的代碼變更排序階段. Huang等[12]進一步改進了CBS的性能并命名為CBS+. Fu等[9]提出了一個即時軟件缺陷分析方法OneWay, 其包含兩個階段: 在第一階段, OneWay根據(jù)類標信息選擇最好的基于代碼變更的特征; 在第二階段, OneWay使用該特性構建一個模型在測試數(shù)據(jù)中識別含有缺陷的代碼變更.
除有監(jiān)督的即時軟件缺陷分析方法外, 研究人員也提出了無監(jiān)督的方法, 因為這些方法更簡單, 并且性能也較好. Yang等[21]首先提出了一種簡單的無監(jiān)督方法LT, 并在6個廣泛使用的開源項目上對有監(jiān)督方法和無監(jiān)督方法進行了比較. Liu等[13]提出了另一種無監(jiān)督方法Code Churn, 實驗結果表明, 該方法的性能優(yōu)于之前提出的有監(jiān)督方法和無監(jiān)督方法.
Python作為最受歡迎的開發(fā)語言之一, 如何有效、 即時地識別Python項目中的潛在軟件缺陷, 對提高軟件質(zhì)量具有重要意義. 針對該問題, 本文提出一個能自動收集、 抽取、 標注Python項目, 然后基于標記數(shù)據(jù)構建即時軟件缺陷分析模型的框架GIF(a framework of Git based just-in-time software defect quality analysis). 該框架主要包含數(shù)據(jù)收集階段和數(shù)據(jù)分析階段. 在數(shù)據(jù)收集階段, GIF從項目的代碼倉庫中復制項目, 從GIF日志中分析軟件項目的變更特征, 使用SZZ算法[17]對代碼變更進行標注, 并將其存儲到數(shù)據(jù)庫中. 在數(shù)據(jù)分析階段, GIF基于標注的數(shù)據(jù)集進行缺陷分析模型的構建, 并對新產(chǎn)生的代碼變更進行有無缺陷的分析. 本文收集了GitHub上最受歡迎的前10個用Python開發(fā)的項目(時間截止到2020-05-30), 使用隨機森林(random forest, RF)、 邏輯回歸(logistic regression, LR)和樸素Bayes(Na?ve Bayes, NB)3種經(jīng)典有監(jiān)督方法, 在這10個項目上以AUC(area under the ROC curve)和F1值指標進行實證研究, 結果表明, GIF能有效地識別出基于Python語言開發(fā)項目中的軟件缺陷.
為能自動化地抽取并標注基于代碼變更的Python項目數(shù)據(jù)集, 本文提出一個即時軟件質(zhì)量分析的框架GIF. 該框架主要包括兩個階段: 數(shù)據(jù)收集階段和數(shù)據(jù)分析階段. 在數(shù)據(jù)收集階段, GIF從項目的代碼倉庫中復制項目, 從Git日志中分析軟件項目的變更特征, 使用SZZ算法對代碼變更進行標注, 并將其存儲到數(shù)據(jù)庫中. 在數(shù)據(jù)分析階段, GIF基于標注的數(shù)據(jù)集進行缺陷分析模型的構建, 并對新產(chǎn)生的代碼變更進行有無缺陷的識別. GIF的框架結構如圖1所示.
圖1 GIF的框架結構Fig.1 Framework of GIF
在數(shù)據(jù)收集階段, 首先需要為GIF提供一個有效的基于Git的遠程代碼倉庫地址(如GitHub,GitLab,Gitee,Bitbucket等); 然后根據(jù)該地址, GIF將Python項目數(shù)據(jù)拷貝到本地, 使用SZZ算法對Git commit日志進行分析, 根據(jù)即時軟件缺陷的特征對每個commit進行量化, 并標注每個commit是否有缺陷; 最后將標記好的數(shù)據(jù)存儲到關系型數(shù)據(jù)庫(如Mysql,Sql Server,DB2 Sybase等)中, 以備后續(xù)數(shù)據(jù)分析使用.
1) 識別修復缺陷的代碼變更. SZZ算法利用一些特性搜索, 旨在修復以前缺陷的代碼變更. 特別地, SZZ算法使用一些關鍵詞(如bug,fix,wrong,error,fail,problem,patch)在代碼變更的日志中搜索, 以標記該代碼更改是否為進行缺陷修復的變更.
2) 識別引入缺陷的代碼變更. 首先, 對每個候選修復缺陷的代碼變更, SZZ算法使用Git diff命令標識之前對同一行代碼進行修改的所有更改, 這些修改過的代碼行被識別為導致缺陷的代碼行; 然后, SZZ算法使用Git blame命令找出最后一次引入代碼變更的修改, 這些修改引入了最后導致錯誤的內(nèi)容, Git blame可顯示文件每行的修改內(nèi)容以及是誰對這些行做了修改; 最后, 這些代碼變更被標記為引入缺陷的變更, 而其他變更則被標記為干凈的變更.
在數(shù)據(jù)分析階段, 基于GIF第一階段標記的數(shù)據(jù), 構建有監(jiān)督的缺陷分析模型, 從而對新產(chǎn)生代碼變更進行有無缺陷的分析.
在數(shù)據(jù)分析階段, 主要有預處理、 模型構建和模型應用3個步驟. 預處理步驟對數(shù)據(jù)集進行預處理操作(如標準化和特征選擇等), 以使數(shù)據(jù)集滿足模型構建的需要, 提高數(shù)據(jù)集的質(zhì)量; 在模型構建步驟中, 使用較成熟的機器學習模型或自定義一個新模型, 該模型能捕獲數(shù)據(jù)的特征與類標特征之間的關系; 在模型應用步驟中, 首先對新產(chǎn)生的代碼使用相同的特征指標進行量化, 然后對其進行必要的預處理, 分析其是否含有缺陷.
本文使用14個被廣泛使用的基于代碼變更的特征, 這些特征可分為5個類別: 擴散類別、 尺寸類別、 目標類別、 歷史類別和經(jīng)驗類別. 表1列出了這些特征的統(tǒng)計信息, 包括名稱、 描述以及所屬類別.
表1 基于代碼變更的特征
本文先使用Python關鍵字在GitHub上進行搜索Python開發(fā)的項目, 然后使用most stars對搜索結果進行降序排序. 為選擇最適合的項目, 本文設置了如下選擇標準: 1) 以“.py”結尾的文件數(shù)量占整個項目中文件數(shù)量的比例不低于90%; 2) 這些文件不是教程、 使用Python實現(xiàn)的算法、 面試經(jīng)驗的收集和一些實用Python代碼的集合這些類別的文件. 通過這些規(guī)則對搜索結果進行過濾后, 選取了排名前10的、 最受歡迎的Python項目. 表2列出了這些項目的統(tǒng)計特征.
表2 數(shù)據(jù)集特征
本文使用AUC指標和F1值指標評估缺陷分析模型的效果. AUC為ROC曲線下的面積, 其取值范圍為[0,1], 取值越接近于1, 表示對應的模型效果越好. 使用ROC曲線可考慮不同的閾值, 其中x軸表示TPR(true positive rate)值,y軸表示FPR(false positive rate)值. 根據(jù)不同閾值, 模型具有不同的TPR值和FPR值, 其對應坐標上的一個點, 將所有這些點進行連接即可得到ROC曲線.F1值是準確率p和查全率r的折中. 根據(jù)實例的實際類別和預測得到的類別, 可計算出真正率(true positives, TP)、 假正率(false positives, FP)、 真負率(true negatives, TN)和假負率(false negatives, FN). 然后基于以上4種情形, 可計算
2.4.1 實驗方案
為更好評估方法的性能, 根據(jù)文獻[11,23]的研究成果, 本文考慮時間敏感的十折交叉檢驗設置, 這種設置可保證用于訓練的代碼變更提交時間早于用于測試的代碼變更. 即對于一個項目, 將其所有代碼變更按時間的順序進行升序排序, 然后將這些代碼變更均勻地劃分成12等份, 分別標記為第0~11份. 即第0份的代碼變更是最早提交的代碼變更, 而第11份的代碼變更是最晚提交的代碼變更. 對于其中的每一折i(i∈[1,10]), 其包含的訓練數(shù)據(jù)為由從第0份到第(i-1)份中所有代碼變更組合成的數(shù)據(jù). 本文使用十折交叉檢驗上的結果計算每種方法的性能. 但本文并未考慮在第0份和第11份中的代碼變更, 因為它們并不滿足SZZ算法的要求. SZZ算法僅能識別出有父節(jié)點的代碼變更, 并且其子節(jié)點被標記為修復的缺陷代碼變更. 因此, 移除第0份的代碼變更, 因為其并沒有父節(jié)點的代碼變更, 同時也移除第11份的代碼變更, 因為其是最新被添加的代碼變更, 可能尚未被正確標記.
2.4.2 模型方法
在經(jīng)驗性實驗中, 為評估基于代碼變更的特征是否能識別出Python語言開發(fā)項目中的缺陷, 本文采用廣泛使用的機器學習包sklearn提供的方法, 包含如下3個經(jīng)典方法: 隨機森林(RF)、 邏輯回歸(LR)和樸素Bayes(NB). 隨機森林是一個包含多個決策樹的集成分類器, 其輸出類別由個別樹輸出類別的眾數(shù)而定, 其中決策樹又是一個基于規(guī)則的分類算法; 邏輯回歸是一種廣義線性模型, 其假設因變量類別服從Bernoulli分布, 邏輯回歸與線性回歸有很多相同之處, 是線性回歸與Sigmoid映射函數(shù)的結合; 樸素Bayes是一組基于Bayes理論的有監(jiān)督學習算法, 其假設每個特征與類標特征之間是條件獨立的. 實驗使用sklearn包中這3個模型的缺省參數(shù), 即未對這些方法進行其他優(yōu)化操作.
2.4.3 統(tǒng)計檢驗
為檢驗各方法之間的性能差異是否顯著以及統(tǒng)計顯著的程度, 本文使用無參的統(tǒng)計分析Wilcoxon無符號秩檢驗[30]和Cliff’s Delta效應檢驗[31].
在GitHub中最受歡迎的前10個Python項目上對GIF框架進行實驗測試, 使用3個基準模型(邏輯回歸、 樸素Bayes和隨機森林), 基于兩個常用的性能評價指標(AUC和F1值)對軟件缺陷分析技術在Python上的性能進行實證研究. 表3列出了3種基準方法在不同項目上的平均性能. 表4列出了不同方法的統(tǒng)計信息, 包括平均性能、 最好方法相對其他方法的性能提高比例(提升值)、 最好方法與其他方法之間的Wilcoxon統(tǒng)計結果(p值)以及Cliff’s Delta數(shù)值和相應的顯著因子(規(guī)模).
表3 3種基準方法在不同項目上的平均性能
表4 不同方法的統(tǒng)計信息
由表3和表4可見:
1) 3個基準方法在10個Python項目上能取得相似的平均性能. RF方法性能最好并且在統(tǒng)計上相比其他兩種方法更具優(yōu)勢. 在AUC指標上, RF不低于中等級別的統(tǒng)計因子, 在統(tǒng)計上好于LR和NB. 在F1值指標上, RF在統(tǒng)計上好于LR和NB, 并且統(tǒng)計顯著因子為小級別.
2) 文獻[20]的研究表明, 在其他開發(fā)語言項目上, 使用LR能得到最好的AUC和F1值, 分別為0.76和0.45. 本文使用RF能得到AUC和F1值的最好結果分別是0.87和0.44. 表明本文提出的GIF框架能有效地識別出Python項目中的潛在缺陷.
影響本文研究結果有效性的因素主要包含三方面: 1) 內(nèi)部有效性主要涉及到可能影響實驗結果正確性的內(nèi)部因素, 其中最主要因素是實驗代碼的實現(xiàn)是否正確, 因此, 為盡可能減小實現(xiàn)各方法過程中引入人為因素對實驗結果產(chǎn)生的影響, 本文使用了成熟的框架, 例如來自sklearn中的機器學習包; 2) 外部有效性主要涉及到實驗研究得到的結論是否具有一般性, 為確保實證研究結論的一般性, 本文抽取并標注了GitHub上最受歡迎的前10個開源項目, 這些項目涵蓋了不同類型的應用場景, 可在一定程度上確保研究結論具有一定的代表性; 3) 結論有效性主要涉及到使用的評測指標是否合理, 本文考慮兩個廣泛使用的評價指標AUC和F1值, 可以更好地評估模型的性能.
綜上所述, 本文針對目前現(xiàn)有技術無法自動抽取軟件倉庫、 標記數(shù)據(jù)、 構建質(zhì)量分析模型和分析軟件質(zhì)量的問題, 提出了基于Git日志的即時軟件缺陷分析框架GIF, 該框架可以自動抽取并標注數(shù)據(jù)集, 然后構建針對Python項目的即時缺陷分析模型. 此外, 本文收集并分享了使用Python語言開發(fā)的10個在GitHub上最受歡迎的項目數(shù)據(jù)集, 通過實證研究證明了GIF框架可有效地識別出使用Python語言開發(fā)項目中的缺陷.