卜依凡,劉 輝,李光杰
(北京理工大學 計算機學院,北京 100081)
隨著產品需求的不斷變更,在程序設計之初設計好的代碼框架需要不斷調整以實現功能的變更.長此以往,程序將逐漸偏離原有的框架,使得整個程序混亂不堪,難以進行擴展和維護.為此,人們提出了軟件重構以對此類軟件進行優化,在不改變其軟件外部特性的情況下提高軟件的設計質量,進而提高軟件的可維護性和可擴展性[1].多年來,在開發過程中的實踐與應用表明[1-3],代碼重構在提升程序的可讀性和可維護性等方面都有著顯著的作用.通過對系統結構的重新整理,開發人員不僅可以改進原有的系統設計、延長軟件的生命周期,還能夠通過改善代碼邏輯來增強代碼理解,有助于從中發現程序缺陷[4].
軟件重構的關鍵步驟之一是明確需要重構的代碼片段[4].而為了幫助開發人員確定需在程序中的何處進行重構操作,Fowler等人提出了代碼壞味(code smell)的概念[4],意指軟件系統中影響軟件質量的設計問題.Fowler等人一共提出了22種代碼壞味,包括克隆代碼、特征依戀、長方法等.基于此定義,研究人員提出了一系列自動或半自動的方法,以從代碼中檢測這些代碼壞味[5-8].代碼壞味的概念及其檢測方法極大地推動了自動化軟件重構的應用和推廣,成為軟件重構領域的重要研究熱點和研究難點.
本文針對上帝類進行深入研究,研究其自動化的檢測方法.上帝類是一種常見的代碼壞味,指的是某個承擔了本應由多個類分別承擔的多個職責的類[9].上帝類違背了分而治之的基本思想以及單一職責的設計原則,嚴重影響軟件的可維護性和可理解性[4].對于上帝類的出現,Fowler等人推薦使用提取類(extract class)或提取子類(extract subclass)等重構操作,將一個大類拆分為小類,以提取出過大類中的一部分職責.為了提醒程序員及時處理上帝類,研究人員提出了眾多檢測算法以自動判定某個給定的類是否為上帝類[5-7,10].現有的檢測算法主要基于代碼行數、圈復雜度、內聚度等常見的軟件度量來判定給定的類是否為上帝類[11].不同的檢測方法往往采用不同的度量項,使用不同的閾值[12-14],因此,不同檢測方法間的檢測結果往往存在較大的差異[5].此外,現有檢測方法的查全率和查準率偏低,導致程序員這些檢測方法和檢測工具難以在工業界廣泛使用.
為此,本文提出了一種基于深度神經網絡的上帝類檢測方法.該方法不僅利用了常見的軟件度量,而且充分利用了代碼中的文本信息,意圖通過挖掘文本語義揭示每個類所承擔的主要角色.此外,本方法將深度學習技術應用于上帝類的檢測.深度學習在計算機視覺、自然語言處理等領域經過廣泛的實踐,得到了很大的發展.與傳統的機器學習相比,深度學習可以更容易地捕捉到輸入數據中的深層關聯,經過多層映射和抽象,擬合出更符合輸入數據分布的模型.本文利用深度神經網絡在文本處理方面的特長,將文本信息加入對上帝類的驗證中,同時結合與上帝類在耦合度、內聚度、類規模等屬性相關的多個度量項,以深度學習善于自動選擇原始數據特征的優勢,幫助提取出這些度量項之間的相互關聯,從而綜合評判待檢測程序是否應為上帝類代碼壞味.
有監督的深度學習通常需要大量的標記數據來作為訓練樣本,但手工標記上帝類樣本數據需要消耗大量的人工,難以收集足夠的訓練樣本.為此,本文提出了一種借助開源項目源碼來構建標簽數據集的方法.通過預定義的類合并操作,實現上帝類樣本的自動生成和標注.考慮到Github,SourceForge等開源網站上有海量開源程序,該方法可以自動構造海量的帶標簽的正負訓練樣本,從而為基于深度學習的上帝類檢測奠定了基礎.
最后,對本文所提出的上帝類自動檢測方法進行了實驗驗證.在第三方開源數據集上的實驗結果表明,該方法優于現有的檢測方法.在不降低查準率的前提下,較大幅度地提高了上帝類檢測的查全率(35.58%=95.56%-59.98%),最終綜合提高了上帝類壞味檢測的F1值(2.39%=8.15%-5.76%).
本文第1節介紹相關研究的現狀,并對此進行總結與分析.第2節具體介紹本文提出的上帝類檢測方法.第3節對所提出的方法進行驗證與評估.第4節進行總論和展望.
Fowler等人提出了代碼壞味的概念,并列出數十種常見的代碼壞味.其中,大類(large class)是承擔太多職責而變得臃腫的類.Fowler等人認為,這樣的類不僅會增加類中代碼的理解難度,同時也容易導致其他代碼壞味的出現[1].Brown等人引入了設計反模式(antipattern)的概念來代指在程序設計過程中所出現的設計缺陷[15].Blob Class是典型的反模式.當單個類中包含超過 60個成員變量及方法時,Brown等人認為此類違反了單一職責原則,應該對其進行重構.在此之后,Lanza等人正式提出了上帝類(god class)的概念,表示某些對外部數據操縱過多的類,并指出,這些類通常還會出現類內成員間內聚較低或類內復雜度過高的問題[9].大類、Blob Class以及上帝類本質上類似,都是指某個類承擔了過多的職責,從而導致該類過于復雜、缺乏內聚等問題.
研究者們迄今已提出了多種方法來對這樣一些在項目中承擔過多職責的類進行檢測與重構.Marinescu等人提出一種基于度量值指標的方法來確定對包括上帝類在內的 14種代碼壞味的檢測策略,并將此方法實現為工具 iPlasma[6].他們根據各代碼壞味的特征與定義選擇不同的度量項組合,以預設閾值的方式為各個壞味確定不同的檢測方案.如公式(1)所示,iPlasma將類內圈復雜度(weighted method count,簡稱WMC)、類內內聚度(tight capsule cohesion,簡稱TCC)和對外訪問數(Access to foreign data,簡稱ATFD)這3個度量值綜合起來以實現對上帝類的判斷.

其中,few、very_high以及one_third均為常量.當一個類的3個度量值同時滿足上述條件時,iPlasma會將其判定為上帝類.
Moha等人定義了一種領域特定語言(domain-specific language,簡稱DSL),并利用這種語言對代碼壞味檢測規則進行定義,以此形成了方法 DéCOR[7].通過對各類壞味的概念進行文本分析,DéCOR將代碼壞味的定義轉化為以這種DSL語言表示的壞味檢測算法,在將其給定的算法實現為真正的程序后,便可以完成對于此代碼壞味的檢測.DéCOR在利用NMD,NAD和LCOM5等度量項來定義對于上帝類的檢測規則的基礎上,還綜合了一些文本信息來輔助其判斷,如當類名中出現“Process”“Control”“Ctrl”等字樣時,即說明此類為上帝類的可能性相對較大.
Tsantalis等人提出了一種利用杰卡德距離來衡量兩個代碼實體之間相似性的方法,并以此方法為基礎實現了用于檢測代碼壞味的工具 JDeodorant.其最初用于檢測特征依戀(feature envy)代碼壞味并推薦移動方法(move method)的重構方案[8],在之后,則逐步增加了對于另外4種壞味——重復代碼(duplicated code)、switch語句(type checking/SwitchStatement)[16]、長方法(long method)[17]以及上帝類[10]——的檢測與重構推薦.JDeodorant為類中的每個成員生成與之相關的其他成員集合(entity set),即訪問此成員以及被此成員訪問的其他成員的集合.他們將兩個成員之間的距離定義為其相關成員集合間的杰卡德距離,計算方式如公式(2)所示.

其中,mi為類中所聲明的一個成員,Se則為成員e的相關成員集合.基于此距離度量項,JDeodorant可以由此定義一個類內的各個成員之間的節點距離,從而為被檢測類構建一個以類內成員為節點的樹狀圖層次結構,再根據所需閾值,對樹狀圖進行橫向切割[10].一旦樹狀圖可以被切割為多個節點簇,則說明此類存在進行提取類重構操作的必要性,即可判定此類是一個上帝類.隨后,鐘林輝等人在 JDeodorant的基礎上對杰卡德距離進行了擴展,公式如下.

其中,mi為類中聲明的第i個成員,n為類中的全部成員個數.他們利用擴展的杰卡德距離實現了一種改進的層次聚類重構方式,以彌補原方法難以衡量全局范圍內的成員相似性的缺陷[18].
綜上所述,上述檢測方法主要依賴于不同的代碼度量項(structural metrics)以及相應的閾值來判定某個類是否為上帝類.不同的檢測方法往往采用不同的度量項,使用不同的閾值[5,13,14],因此,不同檢測方法的檢測結果往往存在較大的差異[5].此外,現有檢測方法的查全率和查準率偏低,導致這些檢測方法和檢測工具難以在工業界廣泛使用.
隨著機器學習的演進與發展,研究者們提出了一批基于各類機器學習算法的代碼壞味檢測方法.Kreimer在2005年時提出了一種基于決策樹(decision tree)的對大類和長方法兩種代碼壞味的檢測方法[19].Khomh等人利用貝葉斯信念網絡(Bayesian belief network)實現了對上帝類相關反模式的檢測[20].Maiga等人則實現了基于支持向量機(support vector machine,簡稱SVM)的上帝類檢測方法[21].Palomba等人提出了一種基于信息檢索技術(information retrieval,簡稱 IR)來利用程序中的文本信息進行壞味檢測的方法[22].類似的,馬賽等人嘗試了利用潛在語義分析技術來對上帝類進行檢測[23].Fontana等人匯總了幾種常見的機器學習算法(J48,JRip,ERandom Forest,Baive Bayes,SMO以及LibSVM)來共同檢測各類代碼壞味,以便比較并總結不同算法在代碼壞味檢測領域中的表現與差異[24].
有別于基于傳統機器學習的壞味檢測方法,本文充分利用了最新的深度學習技術,能夠學習更加復雜的邏輯關系.此外,本文不僅利用了軟件度量信息,也使用了代碼中的文本信息以挖掘給定類所承擔的角色.最后,在訓練集的收集方面,現有方法主要依賴于手工收集訓練數據,而本文提出了標簽訓練數據自動生成方法.
為了自動檢測上帝類,本文提出了一種基于深度學習的檢測方法.第 2.1節給出本文所提出方法的概覽介紹,之后的各小節將詳細介紹該方法的各個關鍵步驟.
本文提出的基于深度學習的上帝類檢測方法如圖1所示.首先,利用大量的開源軟件項目工程作為代碼語料庫,實現了一種可以自動生成標簽樣本的工具來生成深度學習訓練所需的大規模數據集.此工具基于如下假設:若認定開源項目的現有設計合理,那么若將其中的兩個類合并為一個類,則可以認為這個大類承擔了兩個類的職責.因此,本工具在不改變類的外部行為的前提下,通過盡可能多地對源碼中的類進行兩兩合并以形成大類正樣本集合,隨后,從其余未參加合并的類中隨機抽取出相應數目的類作為負樣本集合.為了盡可能保留代碼中與上帝類代碼壞味相關的特征,從正負樣本集中分別提取出符合預設輸入格式的文本信息與軟件度量作為神經網絡分類器的輸入,分類器的預期輸出為樣本的標簽(即是否為上帝類).經過多次迭代訓練后,可以得到最終被訓練好的神經網絡分類器.對于給定的待測程序,首先提取每個待測試類的文本信息和軟件度量.將此信息依次輸入訓練好的神經網絡分類器,得到最終的檢測結果.后續章節將依次介紹每個關鍵步驟的具體細節.

Fig.1 Overview of the god class detection based on deep learning圖1 基于深度學習的上帝類代碼壞味檢測方法概圖
由于直接以全部代碼文本作為深度神經網絡分類器的輸入時所要求的模型學習難度過大,我們需要對代碼文本進行一部分的預處理操作,從代碼文本中提取出與上帝類代碼壞味相關的特征集合,并且摒棄一部分就本學習任務而言無價值的無關特征,以便降低模型構建的難度.為了在充分利用代碼中的各類特征與信息時避免因特征過多而導致的維度爆炸,我們經過反復考量與對比,選取了數個與上帝類代碼結構相關的代碼度量項作為神經網絡分類器的軟件度量特征;同時,從代碼中提取了部分相關標識符來作為神經網絡分類器的文本信息特征.然而,盡管已剔除了一部分的無關特征與冗余特征,這些原始特征彼此間的相互關聯以及輸入特征與輸出標簽間的潛在映射關系依然需要進一步地分析.因此,我們利用了神經網絡分類器來對原始特征進行映射與學習,以便最終輸出與樣本標簽所對應的分類結果.
軟件度量信息是代碼壞味檢測研究中常用的判斷依據.我們綜合了12個可以在不同方面體現上帝類特征的代碼度量項,基本涵蓋上帝類代碼壞味結構特征的各個方面,以期能夠在耦合度、內聚度、復雜度以及代碼規模等方面更全面地表示代碼的結構特征.表1為所選度量項的詳細信息.

Table 1 Metrics表1 度量項
此外,我們收集了被檢測類中所聲明的各成員標識符來作為輸入的一部分.Arnaoudova等人的研究表明,有意義的標識符可以有效揭示代碼組件在程序中的角色、行為與功能[25].一個類中的各個成員通過完成各自的功能,共同構成其所在類的對外行為與角色,故可以認為在理想情況下,存在于一個類中的多個成員標識符之間應該存在著語義上的相互關聯.因此,我們將這種隱含在標識符內的語義關聯作為衡量被檢測類內聚度的一個重要依據,并結合上述的軟件度量指標,組成了本文所提出方法的輸入,如公式(4)所示.

其中,mi為被檢測類中聲明的第i個方法或屬性,name(mi)為mi的標識符,metrics則為12個度量項的集合.
為了能夠挖掘標識符之間的深層語義關聯,我們利用Mikolov等人提出的著名詞向量化模型Word2Vector將標識符中的詞語映射到高緯向量空間[26,27],以詞向量在高維空間中的分布來揭示詞與詞之間的相似性關系.作為自然語言處理領域的重要工具,Word2Vector構建了一個以給定的文本作為輸入輸出的神經網絡.在進行訓練之后,可以利用此模型的隱含層將詞語轉化為稠密向量,實現以向量相似性來表示語義相似性的目的.我們利用大量項目源碼作為代碼語料庫,對Word2Vector模型進行訓練,構建了一個針對程序語言的向量空間.隨后,根據如下步驟對將作為神經網絡分類器輸入的各標識符分別進行預處理.
(1) 根據駝峰命名法規則(camel case)和下劃線命名法規則對標識符進行分詞,將單個標識符拆分為多個邏輯單字.
(2) 利用已訓練好的 Word2Vector模型將各邏輯單字分別映射為高維空間中固定長度(200維)的詞嵌入向量(word embedding).
(3) 將單個標識符中包含的各分詞向量相加后取均值構成一個新的詞向量,以作為此標識符在向量空間中的表示[28].
針對訓練過程所用的12個項目源碼進行的統計分析表明,訓練集中95.8%的類中不會聲明超過50個成員.因此,出于神經網絡的設計需要,我們將神經網絡輸入中的單個樣本的標識符個數固定在 50個,即只針對被檢測類中所聲明的前50個成員進行預處理,類中成員數少于50個則以全零向量來做補零擴展.
本文所提出的基于深度神經網絡的分類器結構如圖2所示.

Fig.2 Classifier based on neural network圖2 神經網絡分類器
如上文所述,此分類器的輸入分為文本輸入與度量輸入兩部分.文本輸入由類中的成員標識符組成,類中的成員標識符在經過預處理(詳見第2.3節)后,已經由文本信息轉為數值信息,將以詞向量(輸入形式為50×200矩陣)的形式經過輸入數據屏蔽層(masking,mask_value=0)進入長短時記憶網絡(long short-term memory,簡稱LSTM)中,其中,LSTM 層激活函數為 sigmoid函數,輸出維度為 2,并對該層權重做均勻分布(uniform)初始化.長短時記憶網絡作為循環神經網絡(recurrent neural network,簡稱RNN)的變體,通過規避梯度消失問題彌補了循環神經網絡長期記憶失效的缺陷[29],因而在自然語言處理領域中獲得了充分應用.我們希望利用長短時記憶網絡善于從長序列中提取關鍵語義特征的優勢來對所輸入的多個標識符詞向量進行處理,以幫助分類器分析被檢測類在語義上的內聚性.度量輸入體現了被檢測類的結構特征.通過將從類中提取出的12個度量值輸入全連接層(dense),分類器可以在有監督的情況下對輸入進行迭代訓練,逐步調整出與訓練集標簽最匹配的參數組合,其中,本全連接層激活函數為 tanh函數,輸出維度為 12,并對本層權重做均勻分布(uniform)初始化.之后,兩部分數據會經由融合層(merge)以向量拼接(concatenate,axis=-1)的形式合并,再由一層全連接層映射到最終的Sigmoid輸出層,此間的全連接層激活函數為tanh函數,輸出維度為4,權重初始化為全零矩陣(zero);輸出層激活函數為sigmoid函數,輸出維度為1.最終選取的模型損失函數(loss function)為binary_crossentropy函數,優化器(optimizer)為adam自適應方法,迭代次數(epoch)為10次,批尺寸(batch_size)為5.
深度神經網絡的結構決定了其對于訓練樣本數量的要求.為了防止出現過擬合現象,我們需要大量的數據樣本來幫助提高神經網絡的泛化能力.對此,我們提出一種通過合并類操作來自動構建標簽樣本集的工具來輔助收集上節所述分類器在訓練過程中所需的樣本集.在項目源碼可編譯的前提下,我們可以利用本樣本生成工具源源不斷地生成分類器所需的正負樣本,以及從所生成的樣本集中提取神經網絡分類器所需要的全部特征輸入.利用本工具來幫助收集帶標簽的訓練樣本集,可以省去人工識別上帝類代碼壞味時所需要耗費的大量時間和人力.由于此工具實現了自動的樣本生成和特征提取預處理操作,因此只要能夠獲取到優質的可編譯開源項目資源,整個訓練樣本的生成及特征提取過程均不需要人工干預.在這樣的前提下,以互聯網中基數龐大的開源項目為基礎,原則上我們可以利用此工具獲取到足夠充足的上帝類標簽樣本集.
假設某個程序的現有設計是合理的,那么將其中的兩個類合并成一個大類則是不合理的.這個合并起來的大類承擔本該由多個類一起承擔的多個角色,因此是一個上帝類.基于此,我們利用開源的高質量代碼自動構造上帝類的正樣本.為了保證合并后大類的外部行為與合并之前保持一致,我們會在將兩類合并的基礎上盡可能不對兩類源碼進行修改.
如算法 1所示,在獲取到可編譯的開源項目源碼后,為了在最大化節省樣本生成時間的基礎上秉持多多益善的原則盡可能多地生成訓練集正樣本,我們會對項目內的各編譯單元進行 3次篩選,以確定最終可用于生成訓練樣本集的編譯單元集合.
算法1.類型合并前后的判斷邏輯.

3次篩選的具體實現步驟如下.
(1) 第 1次篩選是對單個編譯單元中的頂層類進行判斷,主要目的是篩選出能夠進行合并操作的常規Class類.
(2) 隨后,我們將對剩余的編譯單元集合進行兩兩配對并開始第 2次篩選,這次篩選為初步判斷配對后的兩個編譯單元是否可以在不導致語法錯誤的前提下進行合并,如判斷兩個類中是否存在成員名沖突,或兩個類是否繼承于不同的父類.
(3) 一對編譯單元如果可以通過上述判斷,便對此二者實現合并類操作,以得到最終需要的大類.此時進行第3次篩選,用以確定此次合并類操作沒有導致任何的程序錯誤與外部行為變化.
兩個類C1和C2的合并類算法如下.
(1) 生成一個空的新類(NewClass),并C1和C2中的模塊導入語句(import statement)以及全部的成員聲明語句都遷移至NewClass類內.
(2) 在整個工程中搜索C1和C2以屬性類型、方法參數類型、方法返回類型等一系列形式出現在工程中其他類中的情況,將這些類中的C1和C2類型替換為NewClass類型.
(3) 刪除工程中的C1和C2類.此時,整個工程中全部與C1和C2相關的代碼均已被 NewClass替換,NewClass徹底取代了C1和C2類在此系統中的角色與職責.
我們將通過3次篩選的NewClass定義為人為注入的代碼壞味,由此便可以計算NewClass的12個度量值.根據第2.2節中所設計的輸入格式收集到所需數據后,我們即可導出以下格式的訓練集正樣本.

為了獲取負樣本集合,我們將經過第1次篩選的編譯單元集合定義為全集collection,將可成功合并為大類的類的集合定義為集合posCollection,由此可定義posCollection在collection上的補集為negCollection,即

假設某個程序的現有設計是合理的,那么negCollection中任意一個類都是上帝類的負樣本.為保證訓練效果,我們從每個開源程序中收集的正負樣本的比例控制在 1:1.為了保證訓練集負樣本的典型性以及此樣本生成工具設計思路的合理性,我們從negCollection中隨機抽取一個與正樣本集合樣本容量相同的集合,并入最終的帶標簽的訓練樣本.
為了對所提出的方法進行驗證,我們收集了12個高質量開源項目源碼作為樣本生成所需的代碼語料庫,并以此為基礎具體實現了該方法,相關的代碼與數據已上傳至 https://github.com/bby8808/GodClassDetection.同時,我們以Palomba等人提出的代碼壞味數據集作為測試樣本[30],對本文所提出的方法進行驗證與分析.
在實驗驗證階段,我們希望通過分析以下4個問題來對所提出的方法進行評估.
(1) 研究問題1:該方法是否能準確有效地檢測出上帝類?其查全率和查準率是否優于現有方法?
(2) 研究問題2:所提出的神經網絡分類器中的兩個特征輸入(代碼文本特征與代碼結構特征)對最終結果分別有什么影響?即如果只有其中的一個特征輸入,分類器的性能會如何變化?
(3) 研究問題3:利用其他網絡模型(如卷積神經網絡CNN和全連接網絡dense)替代神經網絡分類器中所使用的長短時記憶網絡LSTM,能否進一步提高分類器的性能,如查全率、查準率等?
(4) 研究問題 4:該方法訓練一個神經網絡分類器的時間需要多久?利用已訓練好的分類器進行預測又需要多長時間?
研究問題 1關注的是所提出的方法與當前方法的檢測結果在查準率(precision)與查全率(recall)等指標上的區別.為了回答這個問題,我們選擇了JDeodorant[10]作為評估階段的對比實驗對象.之所以選擇JDeodorant作為參照,是因為 JDeodorant作為知名的代碼重構推薦工具,其代碼壞味的檢測能力已獲得了業內的廣泛認可[5,23,30].比較新的一些上帝類檢測方法,如 TACO[22]和 DéCOR[7],都沒有公開的實現體(源代碼或者可執行程序),因此難以與他們在同一數據集上進行實際比較.
研究問題 2關注神經網絡分類器輸入特征選取的有效性.我們在保持模型其他部分不變的情況下,分別剪除原模型中的度量項代碼結構特征輸入與標識符代碼文本特征輸入,將原模型拆分為兩個獨立的單一輸入神經網絡并分別加以調優訓練.以各分類器在同一測試集上的最優平均F1值作為衡量指標來分析所提出的兩個特征分別在整個方法中所起的作用.
研究問題 3主要關注在本方法所構造的神經網絡分類器中文本特征的處理方式.我們通過將所提出的網絡模型中的長短時記憶網絡替換為全連接神經網絡和卷積神經網絡,并同樣以各分類器在同一數據集上的最優平均F1值作為指標來幫助考察和分析在已有的方法架構下3種神經網絡對于最終結果的影響.
研究問題 4則關注所提出方法的時間復雜度情況.由于基于機器學習的分類器訓練通常都需要在訓練過程中花費過多的時間成本,因此對于時間代價的考察也應成為我們對本文所提出方法的一個評估因素.對研究問題 4的考察,可以根據所提出方法在訓練過程與預測過程中分別所需花費的時間成本,探討基于深度學習的本方法在時間性能上的具體表現.
3.2.1 訓練數據
我們選擇了12個開源項目,以自動構造神經網絡的訓練數據.表2給出了訓練集所用工程各自的名稱、版本、類的數量(NOC)、方法數量(NOM)以及代碼行數(LOC).為了保證訓練集樣本的可靠性,我們選取了如下的12個開源項目來幫助神經網絡分類器的訓練.作為知名的開源項目,這些項目擁有更高的代碼質量,因此可以幫助我們獲取到更準確的標簽樣本,從而提高神經網絡的訓練效率.同時,我們在選取訓練樣本代碼語料庫的時候,會刻意參考項目的開發者與項目所涉及的領域.這一篩選條件的目的主要是為了消除特定開發者或特定項目領域可能會引入的特定代碼風格傾向,以便保證訓練集標簽樣本的綜合性.

Table 2 Projects for train set表2 訓練集所涉項目列表
3.2.2 測試數據
在測試數據的準備方面,我們利用了 Palomba等人提出的一個開源代碼壞味數據集來作為評估實驗的實驗對象,其中的代碼壞味記錄均經由人工驗證[30].之前的代碼壞味相關研究通常會綜合多個代碼壞味檢測工具的檢測結果作為研究數據的來源[24,31].盡管通過多個工具的互補可能可以獲取到不錯的檢測精度,但人工進行的代碼壞味檢測依然可以被認為是最為可信的評估參考標準.此數據集中包含了在30個軟件項目的395個歷史版本中13種代碼壞味的檢測情況.我們選擇包含上帝類而且可以通過編譯的13個項目作為測試項目.
表3展示了驗證所用的13個開源項目的詳細信息,包括其中的正樣本(在原有數據集上被標記為上帝類的類)個數(NOPS)與負樣本(沒有被標記為上帝類的類)個數(NONS).

Table 3 Projects for test set表3 測試集所涉項目列表

Table 3 Projects for test set (Continued)表3 測試集所涉項目列表(續)
我們以表2中所列出的各開源項目作為代碼語料庫,利用如前所述的標簽樣本生成工具(詳見第2.5節)逐條生成固定格式的正負樣本數據(詳見第 2.2節),以構建出神經網絡分類器的訓練集(其中包括正樣本 845條,負樣本775條).隨后,經過在訓練集上的多輪訓練,我們可以得到一個以類中成員標識符集合與軟件度量值集合為輸入的分類器.此分類器能夠輸出被檢測類中存在上帝類代碼壞味的概率.
以表3中所列的各項目作為測試項目,我們解析其中的源碼并按照神經網絡所定義的輸入格式從項目中提取數據作為測試樣本,由此生成測試集.將測試集輸入已訓練好的神經網絡分類器后,得到的輸出集合即為神經網絡分類器在此測試集上的預測結果.作為參照,我們在 JDeodorant中同樣對此測試集進行上帝類代碼壞味檢測,同時導出其檢測結果以便與本文所提出的方法進行對比.
所提模型代碼基于keras實現.在模型優化階段,我們以交叉熵作為損失函數,并選擇自適應學習率的Adam作為優化算法.同時,為了直觀對比不同方法的上帝類代碼壞味檢測能力,我們利用 Palomba等人提出的代碼壞味數據集作為測試樣本的正確標簽,并以如下方法來分別計算兩種檢測結果與正確標簽之間的查準率、查全率以及F1值:

為了回答研究問題1,我們總結了本方法與JDeodorant在相同測試集上的上帝類檢測結果,如下表4所示.其中,第1列顯示測試集中的項目名稱,第2列~第4列顯示我們所提出的方法測試結果的查準率與查全率,第5列~第7列顯示JDeodorant的測試結果的查準率與查全率.表中最后一行列出了各方法表現的平均值.
根據表4,我們可以看出:
· 在對于上帝類代碼壞味的檢測能力上,所提出方法在此測試集中的表現總體上優于 JDeodorant,平均F1值提高了2.39%=(8.15%-5.76%),其中,本方法相對于JDeodorant的優勢在查全率上尤為明顯,平均提高35.58%=(95.56%-59.98%).
· 盡管所提出方法的平均查準率(4.29%)是高于已有方法的(3.09%),但總體上兩種方法的查準率依然都偏低.
針對研究問題2,我們設計了一組對比實驗來考察所提出方法中的代碼文本特征與代碼結構特征分別對于最終上帝類檢測結果的影響.通過對比單一的代碼文本特征輸入、單一的代碼結構特征輸入和二者綜合輸入這3種輸入方式下的各神經網絡分類器在同一數據集上的上帝類代碼壞味檢測能力,我們可以直觀看出所提出方法中的兩個輸入特征在神經網絡中的作用.3種輸入方式在測試集上的具體表現見表5.

Table 4 Results on god class detection表4 上帝類檢測結果

Table 5 Results on god class detection among features表5 不同特征下的上帝類檢測結果
由表5可以看出:
· 當代碼文本特征與代碼結構特征均為神經網絡的輸入時,分類器在測試集上的綜合表現優于任何一種單一輸入的神經網絡分類器,具體表現為雙輸入分類器的平均F1值相對于單文本輸入分類器和單數值輸入分類器分別提高了7.01%=(8.17%-1.16%)和4.45%=(8.17%-3.72%).
· 與代碼文本特征相比,代碼結構特征對于分類器的預測成功率起到了更大的作用,尤其在查準率上的影響十分明顯,平均查準率高出了1.31%=(1.90%-0.59%).
此外,為了回答研究問題3,我們分別將全連接神經網絡、卷積神經網絡以及長短時記憶網絡這3種網絡模型運用于分類器中的文本特征處理環節.各分類器經過調優后在同一測試集上的具體表現見表6.需注意的是,表中3種神經網絡分類器除文本特征提取環節所用模型不同外,網絡其余部分均保持一致.其中,第2列~第4列數據相關的分類器采用長短時記憶網絡處理代碼文本特征信息,第5列~第7列所對應的全連接神經網絡在文本特征提取部分的隱含層激活函數為sigmoid函數,第8列~第10列相關分類器則采用三層一維卷積神經網絡進行文本特征提取.

Table 6 Results on god class detection among approaches to text feature exacting表6 不同文本特征處理方式下的上帝類檢測結果
由表6可以看出:
· 在本文所提出方法的架構下,長短時記憶網絡的代碼文本特征提取能力整體上高于全連接神經網絡與卷積神經網絡,LSTM 分類器的F1值與另兩者相比,分別高出了 0.7%=(8.17%-7.47%)和3.81%=(8.17%- 4.36%).
· Dense分類器的表現在測試集中的不同項目間差異很大,既有不少項目的查準率和F1值均高于LSTM分類器,也出現了檢測不出項目中的上帝類代碼壞味的情況(FreeMind和Hadoop).
· 針對上述情況,為保穩妥,我們認為,選擇長短時記憶網絡作為整個神經網絡中的代碼文本特征提取層時的最終效果較為良好.
針對研究問題 4,我們對所提出方法的時間性能進行了考察.通過在普通配置的個人電腦(16GB RAM,Intel Core CPU i7-6700)上運行所提出方法的全部流程,我們記錄了所提出的分類器的整個訓練與預測過程的耗時情況.表7列出了訓練集所涉各工程提取訓練樣本數據時所耗的時間(以min為單位).

Table 7 Time of train set data generation表7 訓練集數據生成所用時間
可以看出,收集樣本數據的過程耗時頗久.為從 12個開源項目中提取分類器的訓練集,我們累計花費了559min,平均每個項目需要 46.6min.其中,耗時最多的兩個項目 android-backup-extractor(LOC=304,458)與 weka(LOC=444,493)花費了超過總時長一半(56.9%=318÷559)的時間.與耗費了近10個小時的訓練集生成過程相比,神經網絡在12個開源項目上的訓練過程僅需46s.在13個開源項目上的測試過程中耗時36′46″(平均每個項目2′50″),其中36′24″均用于從測試項目中提取輸入信息,占了總測試時間的99.1%.但是訓練集的自動生成是可以提前準備的,并不需要在每次使用該方法進行上帝類檢測的時候再次生成訓練集.
對于評估有效性的第1個威脅在于用來驗證實驗結果的數據集中只包含了25個開源項目.這些項目的某些特性可能會使結論產生偏差,從而導致所得結論不適用于其他項目.為了減少這一威脅,我們選擇的訓練及測試項目均出自不同的研究領域及開發人員,以期減少某些項目間的特定關聯對于驗證結果造成影響.
其次,對于評估有效性的第 2個威脅在于評估所用的測試集中被人工標注的上帝類代碼壞味個數普遍較少.在這樣的數據集上進行上帝類檢測時,很容易出現檢測效果兩極分化的情況.為了盡可能保證所得出的結論適用于實際應用,我們選擇了符合實際開發過程中上帝類出現情況與分布概率的標簽數據集作為結果驗證的基準.在現實開發場景中,項目中出現上帝類代碼壞味的概率平均保持在1.7%左右.
對于評估有效性的第 3個威脅在于所用的開源代碼壞味數據集中的上帝類壞味是由開發人員手動標注的.人工標注雖然更符合實際應用場景,但難以避免數據集貢獻者在標記時由于個人主觀原因而出現判斷誤差.為了減少這一威脅,我們選擇了各類代碼壞味數據集中研究人員最常用的開源數據集,希望通過使用經過反復驗證的數據集可以更有效地避免主觀性標注所帶來的影響.
由于所提出方法中的樣本生成方法(詳見第 2.5節)是建立在所涉及的各個類均符合單一職責原則的假設上的,即假設用于構建訓練集正負樣本的全部類均不存在上帝類代碼壞味,且均可獨立承擔其作為一個類的職責.然而實際上,這樣的假設也許并不成立.我們用以構造訓練集的項目源碼中是可能出現上帝類代碼壞味的.因此,這樣的樣本生成方式可能會導致所生成的訓練集中出現噪音——即訓練集中有些樣本的標簽是錯誤的.為了減少這種噪音對于分類器訓練結果的影響,我們盡可能地選取了高質量的項目源碼用以構造訓練集,以盡量避免設計不夠完善的類出現在樣本集合中.同時,為了增加神經網絡的魯棒性,在神經網絡的設計過程中,我們選擇了在自然語言處理領域獲得很大成功的長短時記憶網絡,并輔以一些防過擬合手段來幫助減少樣本噪音對于訓練結果的干擾.
所提出的方法在對神經網絡的文本輸入進行預處理時(詳見第 2.3節),為了將從源碼中提取出的標識符以詞向量的形式輸入到神經網絡,我們會以大寫字母和下劃線為分隔符來對標識符執行分詞操作.這種分詞方式對于代碼中的大部分標識符(如AbstractMethodFragment、text_length)是有效的,但對于由多個大寫字母連接組成的詞語(如 XMLReader)則并不能完全按照詞語語義進行劃分.針對這一情況,我們對大量的開源工程源碼文本進行類似的分詞操作,并將分詞后的結果作為 Word2Vector訓練的語料庫.在這樣的語料庫下訓練出的Word2Vector模型隱含層將既可以為語料庫中已出現的詞語在高維空間中映射詞向量,同樣可以為語料庫中連續出現的字母序列映射空間距離相近的高維向量.此外,標識符中的縮寫詞(如,numberOfChildren縮寫為numOfChildren)也可能會導致標識符語義上的不準確.為此,我們在對Word2Vector的訓練語料庫的選取過程中遵循了大規模和高質量兩個原則,從而盡量保證完整收集常見縮寫詞并且避免非常規縮寫詞的出現.
在神經網絡的應用過程中,過擬合是最常見的影響網絡模型泛化能力的原因之一[32].對此,研究人員提出了降低模型復雜性[32]、添加正則懲罰項(regularization)[33]、增加隨機噪聲(noise)、隨機刪除隱層神經元(dropout)[34]以及選擇適合的迭代訓練次數(early stopping)[35]等多種方法,以提高神經網絡的泛化性能.由于本文所提出方法中的神經網絡模型參數數量較大,我們也在模型訓練過程中加入了一些手段來降低過參數化對網絡模型的影響.在盡量減少不必要的神經元和神經網絡隱層的同時,我們嘗試了上述多種防過擬合手段,最終確定了目前的整體模型.首先,經過實驗對比我們發現,相對于添加高斯噪聲和正則化參數,隨機刪除隱藏層內的一部分神經元對于所提出的分類器最終測試效果的提升更為明顯.在實際訓練過程中,我們將 Dropout的丟棄率設為60%.其次,我們以訓練樣本集中 10%的隨機樣本集作為驗證集,在每輪迭代后,對權重更新后的網絡進行驗證,發現經過10次迭代訓練后,神經網絡的訓練結果進入相對穩定階段,且驗證結果數據沒有與訓練結果數據出現大的偏差,由此確定了神經網絡訓練的迭代次數為 10次.通過上述消除過擬合的方法和手段,我們最終顯著提高了神經網絡分類器的泛化能力,所提出的方法在測試集上的平均F1值由之前的 0.18%提高至上文所述的8.17%.
在本文中,我們提出了一種基于深度學習的上帝類代碼壞味檢測方法.通過分析大量源碼的文本信息與軟件度量信息,深度神經網絡在反復迭代中學習從輸入中提取出與上帝類壞味相關的特征,最終生成分類器模型.為了滿足深度神經網絡訓練過程對于大規模樣本集的需求,我們還實現了一種可以自動利用開源項目源碼來構建上帝類樣本的方式來生成大量訓練數據的工具.
為了保證實驗評估結果的精準可靠,我們利用開源代碼壞味數據集來對所提出方法進行驗證.我們從12個開源項目中提取訓練樣本以訓練神經網絡模型,并在13個人工標記的開源項目上對所生成的網絡模型進行測試.實驗結果表明,相對于現有方法,本文所提出的上帝類檢測方法在測試集上的綜合表現更佳,具體體現為F1值平均提升2.39%,查全率和查準率分別提高35.58%和1.20%.
可以看出,盡管所提出的方法在測試集上的查準率較現有方法已有提高,但總體來說依舊偏低,導致所提出的方法可能并不適合直接應用于實際開發場景的完全自動化檢測.然而得益于本文所提出方法的查全率有了較大幅度的提高,上帝類的檢出成功率得到了更高的保障,被檢測程序中的潛在上帝類壞味中的大多數都可由此方法檢測出來.因此,本方法可用于實際開發中的上帝類代碼壞味輔助檢測,通過提供上帝類壞味候選清單,來幫助開發人員縮小人工檢測的范圍,從而更快地鎖定上帝類代碼壞味的重構時機.同時,在未來的研究中,我們將針對上帝類代碼壞味檢測的可用性做進一步改進,以實現完全自動化的上帝類壞味檢測.此外,在本文所提出的代碼壞味檢測的模型基礎上,我們也將對基于深度學習的提取類重構操作進行進一步的研究.
上帝類代碼壞味屬于類級別的代碼壞味,因而在本文中,我們的訓練樣本自動生成工具的合并粒度也在類級別上.同時,由于上帝類是因違反了單一職責原則而引發的代碼壞味,因此我們為模擬生成上帝類代碼壞味,實現了為單個類中注入多個職責的自動化工具,以此來實現上帝類代碼壞味標簽樣本的自動生成.此外,在開發人員人工判定上帝類代碼壞味的過程中,相對于檢測數據類等壞味會更偏向于對代碼規模和類內內聚度的考察,而相對于長方法等壞味則更偏向于對代碼耦合度的考量,因此我們綜合了各種與上帝類代碼壞味相關的結構特征,以上文中的12個度量項作為神經網絡分類器的代碼結構特征輸入.
然而由于不同的代碼壞味的特點不同,在壞味檢測過程中所需的文本特征和結構特征也不同.針對除上帝類以外的其他代碼壞味,我們可以基于所提出方法的框架模式,通過替換各類壞味所特有的特征表現以及壞味合成方式來實現不同的基于深度學習的壞味檢測方法.例如,與上帝類代碼壞味在類級別上過于臃腫不同,長方法屬于方法級別的代碼壞味.因此,若要在本文所提出方法的基礎上實現長方法代碼壞味的深度學習檢測方法,我們可以通過批量調用方法內聯(inline method)重構操作來實現長方法壞味樣本集的自動構建,并以與長方法相關的幾項度量值作為二分類神經網絡的輸入特征,來實現針對長方法代碼壞味的深度學習檢測方法.結合以上分析,我們可在未來以本文所提出方法的模式為基礎來實現對數據類、長方法等其他代碼壞味在不同程序語言中的深度學習檢測方法.