邊奕心,王露穎,趙 松,朱 曉
(哈爾濱師范大學(xué) 計算機科學(xué)與信息工程學(xué)院,黑龍江 哈爾濱 150025)
由于移動通信技術(shù)的迅猛發(fā)展,移動應(yīng)用程序已經(jīng)成為軟件行業(yè)的發(fā)展主體。而代碼異味不僅存在于傳統(tǒng)桌面應(yīng)用程序中,也存在于Android應(yīng)用程序中。由于Android應(yīng)用程序與傳統(tǒng)桌面應(yīng)用程序在內(nèi)存、CPU、網(wǎng)絡(luò)、電池以及程序編寫等方面的諸多差異,使得Android應(yīng)用程序中不僅存在傳統(tǒng)面向?qū)ο蟮拇a異味,還存在Android特有代碼異味(Android-specific code smells)。Android特有代碼異味的存在對Android應(yīng)用程序產(chǎn)生了諸多負(fù)面影響,比如能耗、安全性、穩(wěn)定性、內(nèi)存和啟用時間等,極大降低了用戶體驗。隨著機器學(xué)習(xí)技術(shù)的發(fā)展,近年來很多學(xué)者嘗試使用不同的機器學(xué)習(xí)方法來檢測面向?qū)ο蟮拇a異味,并取得了很好的效果[1-7]。然而,目前還沒有使用機器學(xué)習(xí)算法來檢測Android特有代碼異味的相關(guān)研究。
為了檢驗機器學(xué)習(xí)模型是否可用于檢測Android特有代碼異味,本文提出了基于集成學(xué)習(xí)的檢測策略。該策略將代碼度量與程序文本信息相結(jié)合作為特征集,避免模型受限于度量信息,無法學(xué)習(xí)到度量之外的程序特征,提高了單一模型的學(xué)習(xí)能力和泛化能力。此外,為了快速、準(zhǔn)確獲得機器學(xué)習(xí)所需的大量標(biāo)簽數(shù)據(jù),提出了一種基于Android項目構(gòu)建正負(fù)樣本的工具。能夠自動生成機器學(xué)習(xí)模型需要的大量標(biāo)簽數(shù)據(jù)。
忽略成員的方法(member ignoring method,MIM)是指某個類中的方法,該方法即非空方法,也非靜態(tài)方法,但該方法沒有訪問所在類的任何屬性[8]。MIM的存在對Android應(yīng)用程序有諸多負(fù)面影響,比如,增加程序的能耗,降低程序的可維護性等[8]。
迄今為止,研究人員提出了一些MIM的檢測方法。Rasool等[8]根據(jù)代碼異味的不同特征與定義選擇不同的度量,以預(yù)設(shè)閾值的方式為各個異味制定不同的檢測規(guī)則,來檢測異味MIM,并實現(xiàn)了工具DAAP。Nucci等[9]通過度量和簡單的文本比較來檢測包括MIM在內(nèi)的15種Android特有代碼異味,并實現(xiàn)了工具aDoctor。隨后Iannone等[10]對aDoctor進行了擴展,使其能重構(gòu)包含MIM在內(nèi)的5種與能耗相關(guān)的異味。
綜上所述,目前的檢測方法主要采用傳統(tǒng)的程序靜態(tài)分析技術(shù),依賴于不同的代碼度量以及相應(yīng)的閾值檢測Android特有代碼異味。然而,基于規(guī)則的檢測方法,為找到合適每個度量的閾值,往往需要做大量的校準(zhǔn)工作。此外,同一規(guī)則可能與多種代碼異味相關(guān),這將導(dǎo)致不同檢測方法的檢測結(jié)果存在較大的差異。
隨著機器學(xué)習(xí)技術(shù)的迅速發(fā)展,以及以Github開源代碼庫為支撐的“Big Code”的出現(xiàn)[1],很多學(xué)者嘗試使用機器學(xué)習(xí)方法檢測代碼異味。目前已有一些研究使用機器學(xué)習(xí)方法檢測面向?qū)ο蟠a異味。王帆等[2]在C4.5算法中加入對稱不確定性,利用其計算條件屬性間的相關(guān)度,更新信息增益率的計算,提高代碼異味檢測精確度。艾成豪等[3]提出基于Stacking集成學(xué)習(xí)模型的代碼異味檢測方法,提高了單一模型的泛化能力。以上研究在訓(xùn)練模型時,使用的特征集都是傳統(tǒng)的代碼度量。
近年來,隨著深度學(xué)習(xí)模型在各個領(lǐng)域的卓越表現(xiàn),軟件工程領(lǐng)域的學(xué)者們開始嘗試使用深度學(xué)習(xí)方法解決代碼異味檢測問題。Liu等[4]提出一種基于卷積神經(jīng)網(wǎng)絡(luò)的檢測方法,用于檢測依戀情結(jié)異味。在此基礎(chǔ)上,Liu等[5]提出了一種基于卷積神經(jīng)網(wǎng)絡(luò)和長短時記憶網(wǎng)絡(luò)的代碼異味檢測方法,檢測4種代碼異味。以上研究在訓(xùn)練模型時,不僅使用了傳統(tǒng)的代碼度量,還結(jié)合了代碼文本信息(標(biāo)識符信息)。Sharma等[1]分別使用卷積神經(jīng)網(wǎng)絡(luò)、循環(huán)神經(jīng)網(wǎng)絡(luò)和自編碼器對4種代碼異味進行檢測。Sharma認(rèn)為使用代碼度量作為模型的輸入,機器學(xué)習(xí)算法受限于度量信息,無法獲得度量以外的源代碼特征,影響模型的學(xué)習(xí)效果。此外,即便使用相同的度量,因為閾值的不同,導(dǎo)致不同檢測方法的檢測結(jié)果存在較大的差異。因此,Sharma沒有使用任何傳統(tǒng)的度量信息,而是使用程序文本信息作為模型的輸入,不同于Liu等[5]使用的文本信息(僅標(biāo)識符),Sharma將源代碼轉(zhuǎn)換為整數(shù),然后以數(shù)字向量形式表示程序的文本信息,這種文本信息涵蓋了程序的全部信息。
綜上所述,已有使用機器學(xué)習(xí)或者深度學(xué)習(xí)檢測代碼異味的方法都只關(guān)注面向?qū)ο蟠a異味。目前還沒有使用機器學(xué)習(xí)方法檢測Android特有代碼異味的相關(guān)研究。因此,為了檢驗機器學(xué)習(xí)模型是否可以用于檢測Android特有代碼異味,針對異味MIM本文提出基于集成學(xué)習(xí)的檢測策略。
本文提出一種基于集成學(xué)習(xí)的MIM檢測方法。該方法首先以開源的Android應(yīng)用程序作為實驗所需的代碼語料庫,從中提取度量和文本信息。通過特征融合將兩種特征融合在一起,并與之相對應(yīng)的分類標(biāo)簽一起構(gòu)成MIM數(shù)據(jù)集。再對數(shù)據(jù)進行歸一化,最后將得到的特征集送入的Stacking集成模型中進行分類。圖1總結(jié)了本文異味檢測技術(shù)的主要流程。
圖1 融合文本信息和集成學(xué)習(xí)的MIM檢測方法
本節(jié)詳細(xì)介紹生成標(biāo)簽數(shù)據(jù)集的過程及使用的工具。
2.2.1 實驗對象獲取
在開源代碼庫AndroZooOpen[11]中下載Android應(yīng)用程序,作為備選的代碼語料庫。AndroZooOpen是一個公開的Android應(yīng)用程序集合,包括Gitbub、F-Droid和Google Play在內(nèi)的多個數(shù)據(jù)來源。AndroZooOpen目前包含76 466個由不同語言開發(fā)的Android應(yīng)用程序。本文選擇主要由Java語言開發(fā)的Android應(yīng)用程序,因為Java 是目前移動應(yīng)用軟件開發(fā)的主流語言之一,而且目前Android特有代碼異味的檢測工具只能檢測由Java語言開發(fā)的應(yīng)用程序。
首先,從AndroZooOpen下載110個開源Android應(yīng)用程序。然后,使用工具RepoReapers[12]去除低質(zhì)量的Android應(yīng)用程序。RepoReapers可以從8個方面對AndroZooOpen中的程序質(zhì)量進行評分(分別是體系結(jié)構(gòu)、社區(qū)、持續(xù)集成、文件、提交歷史、許可證、問題和單元測試)。如果待選應(yīng)用程序在7個方面的評分均大于零,則選取該程序。經(jīng)過篩選,最終確定70個Android應(yīng)用程序作為代碼語料庫,這70個應(yīng)用程序共有747 264行代碼,9574個類和87 320個方法。
2.2.2 樣本生成
在圖像處理領(lǐng)域,研究者可以免費獲得大量的有標(biāo)簽的圖像數(shù)據(jù)集,用以構(gòu)建模型的訓(xùn)練集。而在代碼異味檢測研究中,目前還沒有類似的資源可供研究者使用[1]。為了解決這個問題,Liu等[4,5]和Sharma等[1]利用已有代碼異味檢測工具的輸出結(jié)果,構(gòu)建模型的訓(xùn)練集。本文借鑒這種方法,使用工具ASSD檢測異味MIM并自動生成正、負(fù)樣本集。本文使用的工具ASSD是在檢測工具DAAP[8]源代碼的基礎(chǔ)上對其功能進行擴展,以自動生成正負(fù)樣本。ASSD沒有改變DAAP的異味檢測規(guī)則,為區(qū)別于原DAAP工具,本文將改進后的工具稱為ASSD,其流程如圖2所示。
圖2 ASSD自動生成正負(fù)樣本集的流程
DAAP是目前檢測異味種類最多、檢測準(zhǔn)確度最好的Android特有代碼異味檢測工具。DAAP可以檢測包括MIM在內(nèi)的25種Android特有代碼異味,無論在檢測的異味種類還是檢測精度方面,都優(yōu)于知名的檢測工具aDoctor[8],并且DAAP是完全開源的工具,使用者不僅可以免費獲得,而且可以在其基礎(chǔ)上進行功能擴展,以滿足不同的需求。因此,本文首選DAAP檢測MIM異味。但是,由于DAAP的檢測結(jié)果只能定位到類級別,而MIM屬于方法級別的異味。因此,本文在DAAP的基礎(chǔ)上,對其功能進行擴展,開發(fā)了ASSD。ASSD首先利用JavaParser將待分析的Java源代碼解析生成抽象語法樹,然后根據(jù)檢測規(guī)則遍歷語法樹,輸出異味。圖2中虛線部分所示為DAAP工具,虛線外的功能是本文擴展的功能。ASSD不僅可以將檢測出的MIM異味定位到所在的方法,而且還可以將每個存在MIM的方法和不存在MIM的方法提取到單獨的文件夾中,生成正負(fù)樣本集,即存放有異味方法的文件夾為正樣本集,存放無異味方法的文件夾為負(fù)樣本集。因此,ASSD從異味檢測到樣本生成完全自動完成。
由于檢測規(guī)則自身的局限性,檢測工具在檢測異味的過程中會產(chǎn)生一定數(shù)量的誤檢。因此,為了保證輸入模型數(shù)據(jù)的準(zhǔn)確性,本文采用人工復(fù)檢方法,對ASSD輸出的代碼異味進行檢查,去除誤檢。
2.2.3 提取特征
分類器的特征集由兩部分構(gòu)成:代碼度量和代碼文本信息。
(1)提取代碼度量特征
代碼度量表示程序的結(jié)構(gòu)信息,是代碼異味檢測研究中常用的判斷依據(jù)[13]。本文選擇代碼度量作為模型的部分輸入特征。度量指標(biāo)選擇檢測工具DAAP檢測MIM異味時使用的度量指標(biāo),分別為NSM(被檢測方法是非靜態(tài)方法)、AM(被檢測方法所訪問的內(nèi)部成員的個數(shù))和FACC(被檢測方法所訪問的內(nèi)部屬性的個數(shù))。本文使用ASSD提取其中的度量值,其數(shù)據(jù)集格式如圖3所示。
圖3 度量數(shù)據(jù)格式
(2)提取文本信息特征
Sharma等[1]認(rèn)為,只使用代碼度量作為特征集,模型受限于度量信息,無法學(xué)習(xí)到度量之外的程序特征。因此,Sharma使用工具Tokenizer將源代碼轉(zhuǎn)換為整數(shù),用數(shù)字向量表示程序文本信息,并將這些數(shù)字向量作為模型的特征集。Tokenizer可以將源代碼轉(zhuǎn)換為整數(shù),不同的代碼信息匹配不同的整數(shù),圖4為一小段Java方法和相應(yīng)的由Tokernizer產(chǎn)生的整數(shù)。
圖4 Tokenizer標(biāo)記MIM示例
本文參考Sharma等的方法,將ASSD輸出的標(biāo)簽樣本集中的源代碼轉(zhuǎn)換成數(shù)字向量,用這些數(shù)字向量表示代碼文本信息,作為模型輸入的部分特征集,其數(shù)據(jù)集如圖5所示。
圖5 文本信息數(shù)據(jù)格式
此外,在對Tokernizer提取的代碼文本特征統(tǒng)計和分析中發(fā)現(xiàn),80%的方法中不會超過61個元素。為了避免因特征過多而導(dǎo)致的維度爆炸,在本文中將模型輸入的單個樣本中的代碼文本特征個數(shù)固定在61個,即只針對被檢測方法中的61個元素進行預(yù)處理,將方法中元素少于61個以全零向量來做補零擴展。
2.2.4 特征融合
盡管已有檢測方法均使用代碼度量作為特征集[16],但是,代碼度量只能提供程序的結(jié)構(gòu)信息,為了提高機器學(xué)習(xí)模型的學(xué)習(xí)效果,本文在代碼度量的基礎(chǔ)上,融入了代碼文本信息。融合過程如下:將兩組數(shù)據(jù)讀入到numpy數(shù)組中,利用MIM在Android應(yīng)用程序中的位置信息作為匹配鍵對代碼度量和文本信息進行合并。此外,為避免重復(fù)樣本數(shù)據(jù)對實驗結(jié)果的影響,還需對相同的樣本數(shù)據(jù)進行去重操作。刪除重復(fù)數(shù)據(jù)后,得到一個含有2552條正樣本和3265條負(fù)樣本的數(shù)據(jù)集。其中,每條樣本由3個代碼度量、61個文本信息和1個異味標(biāo)簽組成,共65個元素,樣本格式如圖6所示。
圖6 樣本格式
(1)
不同的機器學(xué)習(xí)模型對代碼異味檢測的效果是不同的,為了使不同的模型之間能夠取長補短,增強模型的泛化能力,從而避免單一模型預(yù)測性能不佳、魯棒性較差的特點。本文構(gòu)建了一種兩層結(jié)構(gòu)的Stacking集成學(xué)習(xí)模型,如圖7所示。
圖7 Stacking 集成學(xué)習(xí)模型流程
Stacking模型的第一層選擇XGBoost、隨機森林和決策樹作為基分類器。它們之間存在異構(gòu)性,且各自對MIM的檢測效果也較為優(yōu)異。以這3種機器模型作為基分類器,可以使Stacking模型通過不同的學(xué)習(xí)策略,學(xué)習(xí)到更多的特征,實現(xiàn)模型間的互補性,有助于提升模型整體的檢測效果。由于模型第二層的輸入是由基分類器的預(yù)測結(jié)果所組成的數(shù)據(jù)集,不再是原數(shù)據(jù)集。所以,在模型訓(xùn)練時,可能會發(fā)生過擬合的情況。這是由于第一層基分類器在提取數(shù)據(jù)特征時,使用較復(fù)雜的非線性變換所導(dǎo)致的[15]。因此,在選取第二層元分類器時,本文與艾成豪等[3]和Tang等[15]一樣選擇邏輯回歸作為元分類器。該分類器結(jié)構(gòu)簡單且可以使用正則化進一步防止過擬合的情況發(fā)生,常被用于處理二分類問題。它的實現(xiàn)過程如算法1所示:
算法1:Stacking 集成學(xué)習(xí)模型
輸入:歸一化后的數(shù)據(jù)集
輸出:MIM檢測結(jié)果
(1)將原始數(shù)據(jù)集D隨機劃分成3份,分別表示為D1、D2和D3;
(2)通過交叉驗證的方法,確定各個模型的最優(yōu)參數(shù);
(5)將D*作為第2層檢測模型的輸入,對元模型進行訓(xùn)練,得到最終的檢測結(jié)果。
實驗環(huán)境如下:操作系統(tǒng)是windows 10處理器是Intel Core CPU i7-5500,內(nèi)存是4 GB,實驗工具為PyCharm和IntelliJ IDEA中完成,編程語言為Python和Java。在實驗過程中,采用十折交叉驗證對模型進行驗證。此外,實驗相關(guān)數(shù)據(jù)已上傳至https://github.com/18745332164/MIMDetection。本文主要圍繞以下3個問題進行實驗研究:
RQ1:融合代碼文本信息是否能提高模型的檢測性能?若僅以單一特征作為模型的輸入,其檢測性能會有何變化?
RQ2:Stacking集成學(xué)習(xí)模型對MIM的檢測性能是否有提高?
RQ3:本文提出的檢測方法是否優(yōu)于現(xiàn)有的檢測方法?
本文使用常用的查準(zhǔn)率、查全率和F1值對模型進行評估,它們的計算方法如式(2)~式(4)所示
(2)
(3)
(4)
其中,式(2)和式(3)中的TP(true positive)為被檢測為正的正樣本數(shù);FP(false positive)為被檢測為正的負(fù)樣本數(shù);FN(false negative)為被檢測為負(fù)的正樣本數(shù)。
此外,由于實驗數(shù)據(jù)集呈現(xiàn)不平衡狀態(tài),本文引入G值對模型進行更全面的評估,該指標(biāo)能夠更直觀評價類不平衡的表現(xiàn),其計算方法如式(5)所示
(5)
實驗一:為了回答RQ1,分別以2.2節(jié)構(gòu)建的融合兩類特征的數(shù)據(jù)集、僅代碼度量和僅文本信息的數(shù)據(jù)集作為6個機器學(xué)習(xí)模型(XGBoost、隨機森林、決策樹、支持向量機、樸素貝葉斯和K最鄰近)的輸入,使用十折交叉驗證對模型進行驗證。最后,使用查準(zhǔn)率、查全率、F1值和G值對不同特征輸入下的6種檢測模型的檢測效果進行比較。
實驗二:為了回答RQ2,將融合代碼度量和文本信息的特征集作為模型輸入的數(shù)據(jù)集,采用十折交叉驗證的方法分別對3個機器學(xué)習(xí)模型以及由它們所集成的Stacking模型進行驗證。最后比較4種檢測方法的查準(zhǔn)率、查全率、F1值和G值。
實驗三:為了回答RQ3,首先,從Palomba等[9]提出的一個開源Android應(yīng)用程序數(shù)據(jù)集(共60個Android應(yīng)用程序)中選取了10個開源Android應(yīng)用程序作為待測試程序。其中,這10個應(yīng)用程序與模型訓(xùn)練階段的70個應(yīng)用程序沒有重疊。表1列出了所用的10個開源Android項目的詳細(xì)信息。然后,將新的測試集輸入已訓(xùn)練好的Stacking分類器進行MIM異味檢測。此外,為了進行對比,本文使用檢測工具DAAP和aDoctor分別對這10個應(yīng)用程序進行MIM異味檢測。為準(zhǔn)確評價兩檢測工具的檢測結(jié)果,本文以Palomba等[16]提出的MIM異味目錄作為參考,最后使用查準(zhǔn)率、查全率、F1值和G值對3種檢測方法的檢測效果進行比較。
表1 10個Android應(yīng)用程序及相關(guān)信息
RQ1:表2為不同機器學(xué)習(xí)模型在不同特征下對異味MIM的檢測結(jié)果。根據(jù)表2的結(jié)果可以看出:
表2 不同模型在不同特征下的MIM檢測結(jié)果
(1)融合文本信息后,6種分類器對MIM的檢測性能綜合排名為:XGBoost>隨機森林>決策樹>樸素貝葉斯>支持向量機>K最鄰近。
(2)當(dāng)以代碼度量和文本信息共同作為特征輸入時,除K最鄰近對MIM的檢測結(jié)果較僅以代碼度量為特征輸入的檢測結(jié)果降低了以外。其余5種機器學(xué)習(xí)模型對異味MIM的檢測結(jié)果,均優(yōu)于僅以代碼度量為特征輸入和僅以文本信息作為特征輸入的模型檢測結(jié)果。其中,在融合文本信息后,決策樹的檢測性能提高的最為明顯,其F1值提高了4.1%=(86.86%-82.76%)、 G值提高了3.59%=(87.29%-83.70%)。
(3)當(dāng)僅以單一特征作為機器學(xué)習(xí)模型的輸入時,以代碼度量作為特征輸入的分類器,其檢測效果均優(yōu)于以代碼文本信息作為特征輸入的分類器。以代碼度量作為輸入數(shù)據(jù)集時,6種分類器對MIM的檢測性能綜合排名為:XGBoost>隨機森林>決策樹>支持向量機>樸素貝葉斯>K最鄰近。
XGBoost、隨機森林和決策樹無論是以代碼度量作為特征集,還是以代碼度量和文本信息作為特征集,其檢測效果均優(yōu)于其它分類器。故為避免由單一模型泛化導(dǎo)致模型檢測性能不佳的問題,本文選擇XGBoost、隨機森林和決策樹作為后續(xù)Stacking集成學(xué)習(xí)模型的基分類器。
RQ2:表3列出了文本信息融合后單一模型和Stacking 集成學(xué)習(xí)模型的性能比較。根據(jù)表3的結(jié)果可以看出:相對于單一機器學(xué)習(xí)模型,Stacking集成學(xué)習(xí)模型的檢測效果更好,在F1值和G值上都有一定提升。
表3 文本信息融合后單一模型和Stacking集成學(xué)習(xí)模型的比較結(jié)果
從理論層面來分析Stacking集成模型優(yōu)于單一模型的原因,是因為Stacking集成學(xué)習(xí)模型能發(fā)揮各模型的自身優(yōu)勢,從不同的角度來學(xué)習(xí)數(shù)據(jù),屏除預(yù)測結(jié)果較差的環(huán)節(jié)。從模型優(yōu)化的角度來分析,單一模型在訓(xùn)練優(yōu)化的過程中,通常會陷入局部最小點的風(fēng)險,有的局部最小點通常會導(dǎo)致模型的泛化性能不佳,而通過集成多個基學(xué)習(xí)模型可以減少此風(fēng)險發(fā)生的概率,提高檢測性能。
RQ3:表4列出了3種檢測方法對表1中的10個Android應(yīng)用程序檢測結(jié)果的平均值。根據(jù)表4的結(jié)果可以看出:在相同測試程序的前提下,對異味MIM的檢測效果,本文方法在查準(zhǔn)率、查全率、F1值和G值上都優(yōu)于DAAP和aDoctor。其中,本文所提方法較DAAP的查全率提高的最為明顯,平均提高了43.12%=(97.98%-54.86%)。
表4 不同方法間的平均比較結(jié)果
不同方法對10個Android應(yīng)用程序中的異味MIM的具體檢測結(jié)果如圖8所示。
圖8 不同方法在10個Android應(yīng)用程序上的檢測結(jié)果
從圖8中可以看出本文所提出的檢測方法明顯優(yōu)于DAAP和aDoctor。其中,對應(yīng)用程序aLogCat中的異味MIM檢測效果最好,F(xiàn)1值達(dá)到97.44%、G值達(dá)到97.47%。
以上實驗結(jié)果表明,使用本文方法檢測Android特有代碼異味MIM取得了很好的結(jié)果,驗證了本文所提檢測模型的有效性。
本文提出一種基于集成學(xué)習(xí)的MIM檢測策略。該策略首先將代碼度量與文本信息相融合作為特征集,避免模型因受度量信息的限制,無法學(xué)習(xí)到度量之外的程序特征。然后,為了避免單一機器學(xué)習(xí)模型的局限,提高模型的泛化能力,本文構(gòu)建了Stacking集成學(xué)習(xí)模型。然后,將特征集輸入所構(gòu)建的集成學(xué)習(xí)模型中進行異味檢測。實驗結(jié)果表明,融合文信息的方法和Stacking集成學(xué)習(xí)算法有更好的查準(zhǔn)率、查全率、F值以及G值。此外,為了快速、準(zhǔn)確生成機器學(xué)習(xí)模型所需的大量樣本集,本文還實現(xiàn)了一種可以利用開源Android項目自動構(gòu)建正負(fù)樣本的工具ASSD。本文只介紹了1種Android特有代碼異味的檢測,后續(xù)也會對更多類型的異味進行檢測。