劉丹丹,趙逢禹
(上海理工大學(xué) 光電信息與計(jì)算機(jī)工程學(xué)院,上海 200093)
?
代碼依戀檢測與重構(gòu)研究
劉丹丹,趙逢禹
(上海理工大學(xué) 光電信息與計(jì)算機(jī)工程學(xué)院,上海 200093)
代碼依戀是指一個(gè)類中的方法對其他類的興趣高于定義此方法的類的一種代碼壞味道。文中基于代碼依戀的思想,給出代碼依戀度的定義與度量方法,設(shè)計(jì)了代碼依戀檢測算法,并設(shè)計(jì)出一種工具BADFeature檢測代碼依戀味道且重構(gòu)代碼。經(jīng)實(shí)驗(yàn)證實(shí),BADFeature能檢測代碼依戀味道,且可通過重構(gòu)消除代碼味道。
代碼依戀;壞味道;度;檢測;重構(gòu)
軟件開發(fā)時(shí),軟件設(shè)計(jì)和編寫代碼的過程中會不可避免地引入一些缺陷或不合適的代碼。Fowler 等人[1]將這些不好的設(shè)計(jì)和不合適的編碼描述為代碼味道。近年來,代碼味道的檢測與優(yōu)化已成為軟件工程研究的一個(gè)熱點(diǎn)領(lǐng)域[2-5]。文獻(xiàn)[6]中將代碼味道分為類間味道和類內(nèi)味道,其中代碼依戀就是一種類間味道,其是指一個(gè)方法對其他類的興趣高過本身所在的類[1],一般情況下主要發(fā)生在調(diào)取數(shù)據(jù)時(shí),某個(gè)方法為了計(jì)算某值,從另一個(gè)類中調(diào)用諸多的取值方法。代碼依戀增加了軟件模塊的耦合度,從而使系統(tǒng)中一個(gè)小的改變可能會致使一系列不可預(yù)知的風(fēng)險(xiǎn)。重構(gòu)能有效消除代碼依戀味道。所謂重構(gòu)就是改變程序內(nèi)部結(jié)構(gòu)而不改變其外部特征的行為[7]。代碼重構(gòu)可增加代碼的可讀性,提高軟件質(zhì)量,有效降低維護(hù)成本[8]。
在過去的十幾年中人們提出了諸多方法去檢測代碼依戀。Moha在文獻(xiàn)[9~11]中提出了一個(gè)領(lǐng)域特定語言形式化代碼依戀味道,并提出了檢測算法。而M.Kessentini 等在文獻(xiàn)[12]提出了一種自動(dòng)生成代碼依戀味道檢測規(guī)則的方法,該方法從以前手動(dòng)檢查的項(xiàng)目中總結(jié)出被稱為缺陷例子的設(shè)計(jì)缺陷,產(chǎn)生基于軟件質(zhì)量度量組的新的檢測規(guī)則。Tsantalis和Chatzigeorgiou在文獻(xiàn)[13]中提出對代碼依戀基于方法距離的檢測和校檢,根據(jù)實(shí)體與其他類的距離相對與源類的距離大小確定是否存在代碼依戀味道。在文獻(xiàn)[14]中,J Dexun等對文獻(xiàn)[13]中的方法進(jìn)行了改進(jìn),提出了一種加權(quán)距離度量理論用來檢測代碼依戀,此方法考慮到了實(shí)體之間的調(diào)用關(guān)系,對實(shí)體和類之間的距離進(jìn)行加權(quán)計(jì)算,在檢測效率上有一定提高。盡管這些研究取得了眾多研究成果,但也存在一些問題:(1)代碼依戀?zèng)]有一個(gè)明確統(tǒng)一的定量度量標(biāo)準(zhǔn);(2)存在誤報(bào)問題,以前的代碼依戀檢測方法沒有對公共方法、Web服務(wù)、公共接口中的代碼依戀味道進(jìn)行篩選;(3)多數(shù)研究只探討了檢測代碼依戀方法,對代碼去依戀的重構(gòu)研究較少。
本文基于抽象語法樹提出了一種先檢測后篩選再重構(gòu)的兩重檢測重構(gòu)方法。首先,引入開源項(xiàng)目NRefactory[15]將源代碼抽象成語法樹,遍歷語法樹計(jì)算出各個(gè)方法對每個(gè)類的依戀度,根據(jù)判定準(zhǔn)則找出偽代碼依戀方法;然后經(jīng)過篩選器過濾掉公共方法、Web服務(wù)、公共接口中的偽代碼依戀方法;最后重構(gòu)代碼消除代碼依戀味道。實(shí)驗(yàn)證明,BADFeature能準(zhǔn)確檢測代碼依戀味道,并可通過重構(gòu)消除代碼依戀味道。
定義1 方法自依戀值。方法自依戀值是類中定義的某個(gè)方法mk對聲明自身的類即源類的依戀程度,用CS(mk)表示,CS(mk)值越大,方法mk對源類越依戀。CS(mk)=dS(mk,Datt)+dS(mk,Dmethod),其中ds(mk,Datt)是方法m對源類中屬性的依戀值,用mk中使用源類中屬性的個(gè)數(shù)來度量;ds(mk,Dmethod)是方法mk對源類方法的依戀值,用mk使用源類中其他方法的次數(shù)和源類中使用mk方法的次數(shù)總和來度量。
定義2方法異類依戀值。方法異類依戀值是方法mk對除源類以外的類的依戀程度,用CE(mk)表示,其越大,方法mk對異類越依戀。CE(mk)=dE(mk,Datt)+dE(mk,Dmethod),其中dE(mk,Datt)是方法mk對異類CE中屬性的依戀值,用mk中使用異類CE中屬性的個(gè)數(shù)來度量;dE(mk,Dmethod)是對異類CE中方法的依戀值。用mk使用異類CE中其他方法的次數(shù)和異類CE中使用mk方法的次數(shù)總和來度量。
定義3 類的元素集。類C的元素集是類C的全部屬性和方法作為元素的集合,用D(C)表示,D(C)=(Datt,Dmethod),其中Datt表示類C中所有的屬性,Dmethod表示類C中所有的方法;|D(C)|表示元素集D(C)中的屬性與方法的總數(shù)。
(1)
式(1)中的方法mk是源類CS中的方法,Datt、Dmethod分別是源類中的屬性和方法。
(2)
式(2)中的方法mk是源類CS中的方法;Datt、Dmethod分別是異類CE中的屬性和方法。
定義6 依戀比。方法mk與源類CS的依戀度和其他任一類CE的依戀度比值,用λ(mk)表示
(3)
依戀度檢測結(jié)束后可利用依戀比λ(mk)偵測代碼依戀味道,若λ(mk)>1,說明方法mk與異類CE(mk)的依戀度比定義mk方法的源類CS(mk)依戀度更大,則mk有可能存在代碼依戀味道。若λ(mk)≤1,說明方法mk對源類CS(mk)的依戀度不小于對異類CE(mk)的依戀度,mk不存在代碼依戀味道。當(dāng)CS(mk)=0時(shí),若方法mk是靜態(tài)方法,則源類定義了某種方法mk供其他類調(diào)用,mk不屬于依戀方法;若方法mk不是靜態(tài)方法,且CE(mk)>0直接判定mk是依戀方法。當(dāng)CE(mk)=0且CS(mk)=0時(shí),方法mk不是代碼依戀方法。
定義7 方法的最強(qiáng)依戀類。方法mk的最強(qiáng)依戀類指的是使得λ(mk)最大的那個(gè)異類CE,記為Cmax。
基于AST的代碼味道檢測重構(gòu)工具BADFeature分為偽代碼依戀檢測、偽代碼依戀篩選器過濾、代碼重構(gòu)3部分。
3.1 偽代碼依戀檢測
通過遍歷抽象語法樹,可計(jì)算方法與相關(guān)類的依戀度,進(jìn)而檢測出代碼依戀味道的存在。算法1給出了代碼依戀檢測的D-FE算法。首先構(gòu)造出一棵抽象語法分析樹AST,然后通過抽象語法樹的遍歷統(tǒng)計(jì)出每個(gè)方法與各個(gè)類的依戀度,根據(jù)式(1)~式(3)判斷方法是否含有代碼依戀味道。在抽象語法樹中,每個(gè)方法節(jié)點(diǎn)均對應(yīng)方法信息表中一條信息記錄,每條記錄包括方法源類、是否是靜態(tài)方法、方法位置、方法自依戀度、最強(qiáng)依戀類、最大依戀度等信息。所有節(jié)點(diǎn)的信息記錄形成一張信息表。
算法1 D-FE算法。
Input:項(xiàng)目源代碼。
Output:含有標(biāo)記偽代碼依戀的源代碼文件ASTFile。
(1)輸入項(xiàng)目名、包名、源代碼文件;(2)項(xiàng)目名作為根節(jié)點(diǎn),包作為根的子節(jié)點(diǎn),依次從代碼文件中抽取類Ci(i=1,2,3…,n)作為包的子節(jié)點(diǎn);(3)抽取類Ci(i=1,2…,n)中的方法mk(k=1,2,3,…,t)作為Ci的子節(jié)點(diǎn),方法中的屬性作為方法的子節(jié)點(diǎn)。創(chuàng)建抽象語法分析樹AST。計(jì)算并構(gòu)建方法的節(jié)點(diǎn)信息并存到數(shù)據(jù)庫中;(4)遍歷抽象語法樹AST,取樹中方法mk。
ifmk不是靜態(tài)方法 then
計(jì)算CS(mk),CE(mk),λ(mk);
將CS(mk)的值寫入方法信息表;
ifCS(mk)=0
ifCE(mk)=0 then
mk不含代碼依戀味道;
else if
ifCE(mk)>0 then
mk含有代碼依戀味道;
標(biāo)記mk為偽代碼依戀“FE”;
將Cmax(mk)寫入方法信息表;
end if
ifλ(mk)>1 then
判定mk含有代碼依戀味道;
標(biāo)記mk為偽代碼依戀“FE”;
將Cmax(mk)寫入方法信息表;
end if;
else 方法mk是靜態(tài)方法寫入方法信息表;(5)輸出方法信息表中的具有標(biāo)記為“FE”方法的代碼文件至ASTFile。
3.2 偽代碼依戀篩選器
公共方法、Web服務(wù)、公共接口等一類經(jīng)常被調(diào)用的公用方法在第一步的代碼依戀檢測中會被誤報(bào)成代碼依戀方法即偽代碼依戀方法。本文在BADFeature中加入了代碼依戀的篩選器用以過濾掉公共方法、Web服務(wù)、公共接口中的偽代碼依戀方法以保證檢測的準(zhǔn)確率,設(shè)計(jì)了一組偽代碼依戀方法的篩選規(guī)則和篩選流程。
3.2.1 偽代碼依戀篩選規(guī)則
(1)若某個(gè)偽代碼依戀方法FE聲明前含有WebMethod關(guān)鍵字,則此FE是Web服務(wù)方法不是代碼依戀方法;(2)若某個(gè)偽代碼依戀方法FE是聲明在Common包或System Library中的方法,本文認(rèn)為此FE是公共方法也不是代碼依戀方法;(3)若某個(gè)偽代碼依戀方法FE繼承接口方法,則此方法不是代碼依戀方法。
3.2.2 篩選器的篩選流程
(1)輸入含有FE的ASTFile文件至篩選器;(2)檢測FE,若檢測出方法FE的定義前含有關(guān)鍵字WebMethod,則此FE不含代碼依戀味道;(3)若方法FE是在Common或者System Library的包中聲明,則此FE不含代碼依戀味道;(4)若檢測到FE是繼承接口方法,則此FE也不含代碼依戀味道;(5)將含有上述3種情況的FE標(biāo)記為非代碼依戀味道UFE;(6)篩選掉UFE剩下即是真正的代碼依戀味道,將含有此味道的方法標(biāo)記為RFE;(7)輸出RFE。
3.3 對含有代碼依戀的代碼進(jìn)行重構(gòu)
為消除檢測出的代碼依戀味道,本文提出了兩種重構(gòu)方法:一種是代碼復(fù)制移植重構(gòu);另一種是抽象類重構(gòu),用兩種重構(gòu)方法消除代碼依戀味道。
3.3.1 代碼復(fù)制移植重構(gòu)方法
代碼復(fù)制移植重構(gòu)方法是指將含有代碼依戀味道的方法從源類移動(dòng)到依戀類中,讓其作為依戀類的聲明方法之一。若源類中有子類重寫代碼依戀方法,則將代碼依戀方法復(fù)制到依戀類中。此重構(gòu)方法能有效消除代碼依戀味道。方法分以下幾個(gè)步驟進(jìn)行(假設(shè)源類中的方法mk是依戀方法):(1)從源代碼中找出被標(biāo)記成RFE的代碼依戀方法mk;(2)檢測最強(qiáng)依戀類Cmax中是否有同mk重名的方法,若無則直接進(jìn)入(3);若有則將mk重命名為Rmk其他調(diào)用該方法的名稱也改成Rmk,進(jìn)入(3);(3)將源方法mk的代碼復(fù)制到最強(qiáng)依戀類Cmax中,調(diào)整這些代碼;(4)檢測源類Cs中是否有子類重寫mk,若有,則將代碼依戀方法復(fù)制到依戀類中;若無,則直接刪除源類中的方法mk。
3.3.2 引入抽象類消除代碼依戀味道
抽象類是對一系列看上去不同,但是本質(zhì)相同的具體概念的抽象[16]。若代碼依戀方法在項(xiàng)目中大量被調(diào)用,就其他許多類產(chǎn)生了依賴關(guān)系,在此情況下即使通過代碼復(fù)制移植重構(gòu)方法重構(gòu)代碼,類間的聯(lián)系依然緊密,軟件模塊的耦合度并沒有有效地減小;若多個(gè)類對某幾個(gè)方法依戀,代碼復(fù)制移植重構(gòu)需要在多個(gè)類中移植方法,會造成大量代碼冗余。所以抽取此方法寫成抽象類,讓調(diào)用此方法的類繼承抽象類,消除代碼依戀。對于單個(gè)的公共依戀方法,將此方法抽取到抽象類中即可。
為了證實(shí)BADFeature對代碼依戀的檢測效果,文中選取了以C#語言編碼的兩個(gè)項(xiàng)目,企業(yè)生產(chǎn)管理系統(tǒng)EPMS以及認(rèn)證管理系統(tǒng)CertiF進(jìn)行了代碼依戀味道檢測,表1為檢測結(jié)果。由檢測結(jié)果看出,項(xiàng)目中確實(shí)存在一些代碼依戀味道。對存在于公共接口、Web服務(wù)、公共接口中的代碼依戀味道若不進(jìn)行篩選會影響檢測的準(zhǔn)確率。
表1 BADFeature檢測代碼依戀結(jié)果
通過對CertiF項(xiàng)目代碼進(jìn)行方法移植重構(gòu),對比方法getZhiBe()重構(gòu)前后自依戀度與各個(gè)異類的依戀度以及依戀比可看出移植重構(gòu)方法有效的消除了代碼依戀味道。重構(gòu)前getZhiBe()的源類是AdoptionE.aspx.cs,重構(gòu)以后getZhiBe()的源類變成了RApplyDeal.aspx.cs。重構(gòu)前后的指標(biāo)對比如表2所示。
由表2可發(fā)現(xiàn),重構(gòu)之前getZhiBe()與異類RApplyDeal.aspx.cs的依戀度要大于其對源類AdoptionE.aspx.cs的依戀度,于是對getZhiBe()進(jìn)行重構(gòu),重構(gòu)之后方法getZhiBe()達(dá)到了方法與源類的依戀度大于任意一個(gè)異類的依戀度的目的,有效消除了代碼依戀味道。
表2 重構(gòu)前后方法getZhiBe()與各個(gè)類的依戀度及依戀
最后重新對CertiF和EPMS項(xiàng)目進(jìn)行代碼依戀檢測,結(jié)果如表3所示。
表3 重構(gòu)后代碼依戀味道分布情況
由表3可看出,通過重構(gòu)代碼依戀味道有效減少,同時(shí)軟件耦合度也隨之減少,軟件質(zhì)量有效提高。BADFeature能檢測、消除代碼依戀味道,良好的檢測效果經(jīng)過實(shí)驗(yàn)得到證實(shí)。
本文通過建立、遍歷抽象語法分析樹AST并通過計(jì)算方法的自依戀度與異類依戀度的依戀比,找出偽代碼依戀方法,而后利用篩選器過濾出公共方法、Web服務(wù)、公共接口中的偽代碼依戀方法,確定代碼中真正的代碼依戀方法。最后通過對代碼依戀進(jìn)行代碼重構(gòu),消除了代碼依戀味道。
[1] Fowler M,Beck K,Brant J,et al. Refactoring:improving the design of existing code[M].Massachusetts: Addison-Wesley,1999.
[2] 陳丹,袁捷,繆淮扣.類間結(jié)構(gòu)型代碼味道自動(dòng)檢測的研究[J].計(jì)算機(jī)工程, 2007,33(7):59-61.
[3] Fontana F A,Braione P,Zanoni M. Automatic detection of bad smells in code:an experimental assessment[J]. Journal of Object Technology, 2012, 11(2):1-38.
[4] Liu Hui,Ma Zhiyi,Shao Weizhong,et al. Schedule of bad smell detection and resolution: a new way to save effort[J]. IEEE Transactions on Software Engineering, 2012,38(1):220-235.
[5] Liu Hui,Niu Zhendong, Ma Zhiyi,et al. Identification of generalization refactoring opportunities[J].Automated Software Engineering,2013,20(1): 81-110.
[6] Wake W C.Refactoring workbook[M]. Massachusetts:Addison-Wesley,2003.
[7] 劉偉,劉宏韜,胡志剛.代碼缺陷與代碼味道的自動(dòng)探測與優(yōu)化研究[J].計(jì)算機(jī)應(yīng)用研究,2014,31(1):170-176.
[8] 李軍超.面向自動(dòng)化重構(gòu)的代碼味道識別器的設(shè)計(jì)與實(shí)現(xiàn)[D].長沙:國防科學(xué)技術(shù)大學(xué),2006.
[9] Moha N, Guéhénéuc Y G, Meur A F L, et al.A domain analysis to specify design defects and generate detection algorithms[C].Budapest:11th International Conference on Fundamental Approaches to Software Engineering,2008.
[10] Moha N, Guéhénéuc Y G, Leduc P. Automatic generation of detection algorithms for design defects[C].Tokyo:21st IEEE International Conference on Automated Software Engineering, 2006.
[11] Moha N,Guéhénéuc Y, Duchien L,et al. DECOR: A method for the specification and detection of code and design smells[J].IEEE Transaction on Softw are, 2010,36(1): 20-36.
[12] Kessentini M,Sahraoui H,Boukadoum M, et al.Search-based design defects detection by example[C].Saarbrucken:14th European Joint Conferences on Theory and Practice of Software, 2011.
[13] Tsantalis N, Chatzigeorgiuo A.Identification of move method refactoring opportunities[J].IEEE Transactions on Software Engineering, 2009,35(3): 347-367.
[14] Dexun J,Peijun M,Xiaohon S, et al.Detecting bad smells with weight based distance metrics theory [C].Harbin:2012 Second International Conference on Instrumentation & Measurement, Computer, Communication and Control,2012.
[15] Daniel Grunwald. NRefactory [EB/OL]. (2012-08-11)[2015-08-08]http://www.codeproject.com/Articles/408663/Using-NRefactory-for- analyzing-Csharp-code.
[16] 藍(lán)雯飛,陳淑清,周俊.C#語言中的抽象類與接口的研究及應(yīng)用[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2005(5):71-73.
Detecting Analysis for Feature Envy and Code Refactoring
LIU Dandan,ZHAO Fengyu
(School of Optical-Electrical and Computer Engineering,University of Shanghai for Science and Technology,Shanghai 200093, China)
Feature envy is a kind of bad smells of codes, which occurs when a method of a class is more interested in some other classes than that in the class itself. Based on feature envy essential concepts, a definition for feature envy is proposed and its measuring method is provided. A feature envy detecting algorithm is introduced and a tool BADFeature is developed to detect feature envy and to refactory it. The experimental results show that BADFeature can detect feature envy and eliminate it through refactoring.
feature envy; bad smell; degree; detect; refactoring
2016- 01- 19
國家質(zhì)檢公益性行業(yè)科研專項(xiàng)基金資助項(xiàng)目(201310032-3)
劉丹丹(1990-),男,碩士研究生。研究方向:軟件工程。趙逢禹(1963-),男,博士,教授,碩士生導(dǎo)師。研究方向:計(jì)算機(jī)軟件與軟件系統(tǒng)安全,軟件工程。
10.16180/j.cnki.issn1007-7820.2016.11.021
TP
A