張海銳 吳毅堅(jiān) 趙文耘
(復(fù)旦大學(xué)軟件學(xué)院 上海 201203) (上海市數(shù)據(jù)科學(xué)重點(diǎn)實(shí)驗(yàn)室 上海 201203)
隨著軟件技術(shù)的不斷發(fā)展,軟件的應(yīng)用領(lǐng)域在不斷擴(kuò)大,軟件的規(guī)模和復(fù)雜性不可避免地日益提升,軟件模塊的相互影響更加隱蔽和復(fù)雜,開發(fā)者難以做到既完成繁重的開發(fā)任務(wù),又保證軟件的可維護(hù)性。代碼設(shè)計(jì)質(zhì)量的不斷下降給軟件開發(fā)者的持續(xù)開發(fā)和維護(hù)帶來了很大的挑戰(zhàn)。人們開始重視軟件的質(zhì)量,并渴望采用一些可以評估軟件質(zhì)量的手段。軟件度量是其中一種重要的量化評估手段,量化結(jié)果能夠通過多種方式影響軟件過程和軟件產(chǎn)品。
目前已經(jīng)存在大量的軟件度量指標(biāo)和工具,它們基于多種軟件信息從不同角度描述軟件的設(shè)計(jì)特征。對度量指標(biāo)知識的缺失會阻礙開發(fā)者的實(shí)際應(yīng)用[22],但是度量指標(biāo)的數(shù)量眾多,了解所有指標(biāo)需要耗費(fèi)大量時(shí)間。即使用于度量同一軟件設(shè)計(jì)特征,不同指標(biāo)的度量結(jié)果也可能不同,開發(fā)者難以兼顧所有度量指標(biāo)結(jié)果。由于代碼設(shè)計(jì)質(zhì)量直接影響開發(fā)過程,開發(fā)者尤其關(guān)心與代碼設(shè)計(jì)質(zhì)量相關(guān)的指標(biāo),希望關(guān)注少量度量指標(biāo)就能夠快速定位可能存在質(zhì)量問題的類,而不需要了解所有指標(biāo)。
本文的貢獻(xiàn)主要包括兩方面。一方面是整理歸類了現(xiàn)有的軟件度量指標(biāo),將指標(biāo)分為規(guī)模、耦合、內(nèi)聚、封裝、繼承和多態(tài)等6方面。另一方面是分析了現(xiàn)有指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。本文收集開源項(xiàng)目的源代碼作為分析對象,計(jì)算每個(gè)類的指標(biāo)度量值,挑選出度量值為最大值或最小值的類,然后通過分析這些類的提交歷史判斷它們是否存在代碼設(shè)計(jì)質(zhì)量問題。指標(biāo)與代碼設(shè)計(jì)質(zhì)量問題越相關(guān),越多被挑選出的類會出現(xiàn)代碼設(shè)計(jì)質(zhì)量問題。
軟件度量學(xué)這一概念最早是由Rubey等[23]提出,在此之后,許多研究者在這一領(lǐng)域進(jìn)行了大量的研究。軟件度量方法主要可以分為面向過程和面向?qū)ο髢煞N類型[12]。結(jié)構(gòu)化設(shè)計(jì)是早期軟件的主要開發(fā)方法,那個(gè)時(shí)期經(jīng)典的度量方法包括基于代碼行數(shù)的度量、基于文本分析的度量[14]、McCabe復(fù)雜性度量法[16]以及軟件科學(xué)法[15]等。為了適應(yīng)大規(guī)模的、復(fù)雜的軟件開發(fā),20世紀(jì)80年代出現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)開發(fā)方式,該方式快速得到了廣泛應(yīng)用,針對面向?qū)ο蟮亩攘垦芯恳搽S之成為了一個(gè)研究熱點(diǎn)。Chidamber等[1]1994年提出了CK度量集,包括了6種面向?qū)ο蠖攘恐笜?biāo),可以度量繼承、復(fù)雜度和耦合等軟件特征。文獻(xiàn)[8-9,17-20]分別對CK度量集的指標(biāo)進(jìn)行了驗(yàn)證和改進(jìn)。Albreu等[2]提出了系統(tǒng)層次的面向?qū)ο蠖攘恐笜?biāo)集MOOD度量集,可以度量封裝、繼承、耦合和多態(tài)等軟件特征。Harrison等[24]對MOOD度量集進(jìn)行了詳細(xì)的論述。Lorenz等[3]提出的LK度量方法,包括規(guī)模、繼承、外在特征和內(nèi)在特征四種類型的類層次度量指標(biāo),其中內(nèi)在特征主要通過類的內(nèi)聚度度量,外在特征主要通過類的耦合度度量。Bansiya等[21]提出了一個(gè)四層質(zhì)量度量模型,通常被稱為QMOOD模型,其中面向?qū)ο笤O(shè)計(jì)指標(biāo)層提出了11種度量指標(biāo),將度量指標(biāo)分為數(shù)量、層次、抽象、封裝、耦合、內(nèi)聚、組合、繼承、多態(tài)、信息傳遞和復(fù)雜性等11種類型。董琳[6]綜合用例模型和面向?qū)ο蠖攘糠椒ㄌ岢隽讼到y(tǒng)對象點(diǎn)軟件度量方法,包括了6個(gè)系統(tǒng)層次的度量指標(biāo),用于評估項(xiàng)目的工作量。
目前存在多種關(guān)于軟件質(zhì)量的定義,上海計(jì)算機(jī)軟件技術(shù)開發(fā)中心參照McCall模型提出了SSC軟件質(zhì)量評價(jià)體系,定義6個(gè)軟件質(zhì)量特性為功能性、可靠性、易用性、效率、可維護(hù)性和可移植性[10]。面向?qū)ο蠖攘恐笜?biāo)集被提出后,學(xué)者常將這些度量指標(biāo)與軟件設(shè)計(jì)質(zhì)量建立聯(lián)系,使用度量指標(biāo)考察軟件系統(tǒng)的可維護(hù)性、可靠性,或者預(yù)測缺陷。Denaro等[13]的研究表明代碼度量值與代碼缺陷之間存在相關(guān)性。潘森等[11]通過代碼度量值和缺陷庫等軟件開發(fā)過程中的數(shù)據(jù)監(jiān)控軟件質(zhì)量的變化。冼偉成等[7]的研究發(fā)現(xiàn)面向?qū)ο蠖攘恳蜃又荡嬖陂L尾分布,認(rèn)為這些少數(shù)類的代碼質(zhì)量提升有利于提高軟件整體的質(zhì)量。
已有的研究文獻(xiàn)中提出了許多不同用途的度量指標(biāo),但是對于度量指標(biāo)的分類沒有形成共識。本文通過對文獻(xiàn)[1-3,5,21]的指標(biāo)類別進(jìn)行匯總,將度量指標(biāo)分為規(guī)模、耦合、內(nèi)聚、封裝、繼承和多態(tài)等6種類型。
“規(guī)?!泵枥L了類的規(guī)模大小。文獻(xiàn)[21]中數(shù)量類型的指標(biāo)反映了數(shù)據(jù)和方法的多少,復(fù)雜度類型的指標(biāo)反映了復(fù)雜程度,本文認(rèn)為它們都是表示規(guī)模大小的一個(gè)維度,相關(guān)指標(biāo)可以被合并到規(guī)模類型?!榜詈稀狈从沉祟惻c外部類的互相依賴程度?!皟?nèi)聚”反映了類內(nèi)部成員的關(guān)聯(lián)關(guān)系是否密切?!胺庋b”對應(yīng)于面向?qū)ο笤O(shè)計(jì)的封裝特性,主要涉及對屬性的封裝和隱藏、對方法的隱藏等。文獻(xiàn)[5]中信息隱藏類型的指標(biāo)就是用于度量封裝性,相關(guān)指標(biāo)可以合并到封裝類型?!袄^承”對應(yīng)于面向?qū)ο笤O(shè)計(jì)的繼承特性。文獻(xiàn)[5]中復(fù)用類型的指標(biāo)度量了子類對父類代碼的復(fù)用情況,而這種代碼復(fù)用依賴于繼承機(jī)制的實(shí)現(xiàn),本文將相關(guān)指標(biāo)合并到繼承類型?!岸鄳B(tài)”對應(yīng)于面向?qū)ο笤O(shè)計(jì)的多態(tài)特性,主要涉及方法重寫、抽象方法實(shí)現(xiàn)等。
表1 度量指標(biāo)分類
本節(jié)介紹了每種類型的各個(gè)度量指標(biāo)的定義,并分別建立了每種類型度量指標(biāo)的關(guān)系表。關(guān)系表中不帶下劃線的指標(biāo)表示它屬于類層次指標(biāo),帶下劃線的指標(biāo)表示它屬于系統(tǒng)層次指標(biāo)。如果兩個(gè)指標(biāo)等價(jià),它們的名稱會通過左斜杠相連,如NOC/NODD。如果指標(biāo)名稱后面有上升箭頭,表示它的度量值可能與代碼設(shè)計(jì)質(zhì)量有正相關(guān)關(guān)系。如果名稱后面是下降箭頭,則表示它的度量值可能與代碼設(shè)計(jì)質(zhì)量有負(fù)相關(guān)關(guān)系。例如,AC↑表示AC是一個(gè)類層次的度量指標(biāo),AC值越大的類越可能存在代碼設(shè)計(jì)質(zhì)量問題。
2.1.1耦合度量指標(biāo)
本節(jié)介紹了10個(gè)度量耦合的指標(biāo),該類型指標(biāo)為了判斷兩個(gè)類是否存在耦合關(guān)系,采用的方法主要是查看一個(gè)類是否訪問了另一個(gè)類的屬性或調(diào)用了另一個(gè)類的方法。耦合度量指標(biāo)的關(guān)系表如表2所示。
表2 耦合度量指標(biāo)關(guān)系表
Measure of Aggregation(MOA):聚合度量,等于指定類中屬性的數(shù)據(jù)類型個(gè)數(shù)(基本數(shù)據(jù)類型除外)。
Coupling Factor(COF):耦合因子,等于系統(tǒng)中耦合類對占總類對的比例。如果一個(gè)類A使用了另一個(gè)類B的方法或?qū)傩?,則它們組成一個(gè)耦合類對。
Direct Class Coupling(DCC):直接類耦合,等于與指定類直接相關(guān)的其他類的個(gè)數(shù)。如果指定類的屬性聲明或方法調(diào)用的參數(shù)中使用了其他類,則認(rèn)為它們直接相關(guān)。
Coupling between Objects(CBO):對象類之間耦合,表示指定類與多少類耦合。如果一個(gè)類的實(shí)例調(diào)用了其他類實(shí)例的方法或?qū)傩裕瑒t這兩個(gè)類存在耦合關(guān)系。
Changing Classes(CC):影響類數(shù),等于受指定類影響的其他類的個(gè)數(shù)。如果指定類A的方法被其他類B調(diào)用,并且A、B之間沒有血緣關(guān)系,則B受A的影響。
Afferent Coupling(AC):傳入耦合。計(jì)算方式與CC基本一致,當(dāng)類B與類A之間存在血緣關(guān)系時(shí),AC會統(tǒng)計(jì)B,CC不會。
Number of Called Classes(FANOUT):被調(diào)用類數(shù),表示指定類調(diào)用了多少個(gè)屬于無血緣關(guān)系類的方法或?qū)傩浴?/p>
Number of Coupled Classes(NCC):耦合類數(shù)。NCC表示指定類會被多少個(gè)無血緣關(guān)系類影響。對于被指定類使用的方法/屬性,如果它屬于與指定類無血緣關(guān)系的類,則NCC統(tǒng)計(jì)該類,同一個(gè)類只會被統(tǒng)計(jì)一次。文獻(xiàn)[26]將該指標(biāo)縮寫成CBO,為了區(qū)別于已有的CBO,本文寫為NCC。
Access To Foreign Data(ATFD):訪問的外部數(shù)據(jù)數(shù),表示對于指定類可以直接訪問或調(diào)用訪問器方法訪問的所有屬性,其中有多少個(gè)來自與指定類無血緣關(guān)系的類。
Foreign Data Providers(FDP):外部數(shù)據(jù)提供者數(shù),表示被ATFD統(tǒng)計(jì)的屬性屬于多少個(gè)與指定類無血緣關(guān)系的類。
2.1.2繼承度量指標(biāo)
本節(jié)介紹了13個(gè)繼承類型的度量指標(biāo),該類型指標(biāo)的計(jì)算方式主要分為基于繼承樹和基于子類對父類成員的復(fù)用兩種方式。繼承指標(biāo)的關(guān)系表如表3所示。
表3 繼承度量指標(biāo)關(guān)系表
Number of Children(NOC):孩子個(gè)數(shù),等于指定類的子類個(gè)數(shù)。
Number of Direct Descendants(NODD):直接后代個(gè)數(shù),等價(jià)于NOC。
Number of Descendants(NOD):后代個(gè)數(shù),等于指定類的所有后代類個(gè)數(shù)。
Depth of Inheritance(DIT):繼承樹深度,等于指定類在繼承樹中與根節(jié)點(diǎn)的距離。對于C++等多繼承的編程語言,DIT等于指定類與根節(jié)點(diǎn)的最長距離。
Number of Father(NOF):父親個(gè)數(shù),等于繼承樹中指定類的祖先節(jié)點(diǎn)個(gè)數(shù)。對于Java等單繼承的編程語言,NOF等價(jià)于DIT。
Method Inheritance Factor(MIF):方法繼承因子,等于系統(tǒng)中繼承的方法占所有方法的比例。
Attribute Inheritance Factor(AIF):屬性繼承因子,等于系統(tǒng)中繼承的屬性占所有屬性的比例。
Height of Inheritance(HIT):繼承樹高度,等于指定類在繼承樹中距離后代葉子節(jié)點(diǎn)的最長距離。
Inheritance Methods Per Class(IMPC):繼承方法,等于指定類中繼承的方法占所有方法的比例。
Measure of Functional Abstraction(MFA):方法抽象性度量,等價(jià)于IMPC。
Inheritance Attributes Per Class(IAPC):繼承屬性,等于指定類中繼承的屬性占所有屬性的比例。
Average Number of Ancestors(ANA):平均祖先類個(gè)數(shù),等于系統(tǒng)中所有類的祖先類個(gè)數(shù)的平均值。
Base Class Usage Ratio(BUR):復(fù)用父類比例,等于指定類使用的“遺產(chǎn)”占父類所有“遺產(chǎn)”的比例。“遺產(chǎn)”是指protected修飾的屬性和方法。如果子類訪問了父類的保護(hù)屬性、調(diào)用或重寫了父類的保護(hù)方法,則子類使用了該遺產(chǎn)。
2.1.3封裝度量指標(biāo)
本節(jié)介紹了6個(gè)封裝類型的度量指標(biāo)。一個(gè)類破壞封裝性的方式包括提供可以直接訪問的數(shù)據(jù)和操作。封裝指標(biāo)的關(guān)系表如表4所示。
表4 封裝度量指標(biāo)關(guān)系表
Method Hiding Factor(MHF):方法隱藏因子,等于隱藏方法占所有方法的比例。
Attribute Hiding Factor(AHF):屬性隱藏因子,等于隱藏屬性占所有屬性的比例。
Number of Public Attributes(NOPA):公共屬性個(gè)數(shù),等于指定類中公共屬性的數(shù)量。
Encapsulation Ratio(ER):封裝率。假設(shè)系統(tǒng)類總數(shù)為N,指定類的屬性和方法個(gè)數(shù)和為T。對于指定類的任意一個(gè)屬性或方法,分別統(tǒng)計(jì)項(xiàng)目中有多少個(gè)類無法訪問它,匯總求和得到M,則ER=M/T/(N-1)。
Data Access Metrics(DAM):數(shù)據(jù)訪問指標(biāo),等于指定類中私有屬性占所有屬性的比例。
Class Interface Size(CIS):類接口數(shù)量,等于指定類中公共方法的個(gè)數(shù)。
2.1.4規(guī)模度量指標(biāo)
本節(jié)介紹了8個(gè)規(guī)模類型的度量指標(biāo),這些指標(biāo)通過統(tǒng)計(jì)屬性的個(gè)數(shù)、復(fù)雜度,方法的個(gè)數(shù)、復(fù)雜度等方式評估類的規(guī)模。規(guī)模指標(biāo)的關(guān)系表如表5所示。
表5 規(guī)模度量指標(biāo)關(guān)系表
Response for a Class(RFC):類的響應(yīng)集合,等于指定類收到消息時(shí)調(diào)用的方法加上該類的所有方法。
Number of Attributes per Class(NOA):屬性個(gè)數(shù),等于指定類所有屬性的個(gè)數(shù)。
Number of Methods per Class(NOM):方法個(gè)數(shù),等于指定類所有方法的個(gè)數(shù)。
Weighted Methods per Class(WMC):類加權(quán)方法,等于指定類所有方法的復(fù)雜度之和。
Weighted Attribute Argument Complexity per Class(WACC):類加權(quán)屬性復(fù)雜性,等于指定類所有屬性的權(quán)重之和。屬性的權(quán)重等于它所屬數(shù)據(jù)類型的權(quán)重,每種數(shù)據(jù)類型都有一個(gè)自定義權(quán)重。
Weighted Method Argument Complexity per Class(WMACC):類加權(quán)方法參數(shù)復(fù)雜性,等于指定類所有方法的權(quán)重復(fù)雜度之和。一個(gè)方法的權(quán)重復(fù)雜度等于該方法所有參數(shù)的權(quán)重之和。參數(shù)的權(quán)重等于其所屬數(shù)據(jù)類型的權(quán)重,數(shù)據(jù)類型的權(quán)重設(shè)置與WACC一致。
Complexity Per Class(CPC):類復(fù)雜度,等于a×(NOA/NOT)+b×WMC,a、b建議設(shè)置為0.25、1。
Number of Data Type(NOT):數(shù)據(jù)類型個(gè)數(shù),等于指定類中屬性所屬的數(shù)據(jù)類型的個(gè)數(shù)。
2.1.5內(nèi)聚度量指標(biāo)
本節(jié)介紹了4個(gè)內(nèi)聚類型的指標(biāo),該類型指標(biāo)主要使用相似方法對來度量類的內(nèi)聚程度。判斷兩個(gè)方法是否相似主要通過查看它們是否使用了同一個(gè)屬性。內(nèi)聚指標(biāo)的關(guān)系表如表6所示。
表6 內(nèi)聚度量指標(biāo)關(guān)系表
Lack of Cohesion(LCOM):類的內(nèi)聚缺乏度,等于指定類內(nèi)非相似方法對數(shù)與相似方法對數(shù)的差值,如果差值為負(fù)數(shù),則LCOM為0。如果兩個(gè)方法中使用了同一個(gè)屬性,則它們組成一個(gè)相似方法對,否則組成一個(gè)非相似方法對。
Cohesion in Methods(CM):方法間內(nèi)聚?;贚COM中相似方法對的定義,P表示該類中個(gè)數(shù)非相似方法對數(shù),Q表示該類中相似方法對數(shù),CM=(P-Q)/(P+Q)。
Tight Class Cohesion(TCC):緊密方法內(nèi)聚?;贚COM中相似方法對的定義,TCC等于指定類中相似方法對占所有方法對的比例。
Loose Class Cohesion(LCC):松散方法內(nèi)聚,計(jì)算方式與TCC相同,但是LCC認(rèn)為間接使用同一個(gè)屬性的方法也可以組成相似方法對。
2.1.6多態(tài)度量指標(biāo)
本節(jié)介紹了3個(gè)多態(tài)類型的指標(biāo)。面向?qū)ο筌浖?,多態(tài)分為兩種情形:一個(gè)類中兩個(gè)方法具有相同方法名,但方法參數(shù)列表不同;子類重寫了父類中聲明的方法。多態(tài)度量指標(biāo)主要關(guān)注第二種情況。多態(tài)指標(biāo)的關(guān)系表如表7所示。
表7 多態(tài)度量指標(biāo)
Baseclass Overwriting Methods(BOvM):重寫方法個(gè)數(shù),等于被子類重寫的方法個(gè)數(shù)。
Polymorphism Factor(POF):多態(tài)因子,等于系統(tǒng)中被重寫的方法占所有方法的比例。
Number of Polymorphic Methods(NOP):支持多態(tài)方法個(gè)數(shù),等于指定類中可以支持多態(tài)的方法的個(gè)數(shù)。支持多態(tài)方法在C++語言中就是被virtual修飾的方法,而Java語言中所有非私有實(shí)例方法都是可以支持多態(tài)的方法。
不同類型的度量指標(biāo)描述了軟件的不同設(shè)計(jì)特征,不同的軟件特征與代碼設(shè)計(jì)質(zhì)量的關(guān)聯(lián)程度不同,可以分別進(jìn)行討論。本文提出了六個(gè)研究問題(RQ1~RQ6),與隨機(jī)挑選任意類的方式相比,每種類型的度量指標(biāo)能否有效找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切。
為了回答上述問題,對每種類型的度量指標(biāo),綜合同一類型指標(biāo)的關(guān)系表和常識判斷,本文會挑選部分指標(biāo)進(jìn)行實(shí)驗(yàn)驗(yàn)證。對于待驗(yàn)證的指標(biāo),如果指標(biāo)與代碼設(shè)計(jì)質(zhì)量存在正相關(guān)關(guān)系,選取度量值最高的前20個(gè)類;如果指標(biāo)與代碼設(shè)計(jì)質(zhì)量存在負(fù)相關(guān)關(guān)系,則選取度量值最低的前20個(gè)類。實(shí)驗(yàn)分析它們未來一個(gè)月的提交信息,如果提交信息中出現(xiàn)了單詞“fix”或“refactoring”,則認(rèn)為該類涉及缺陷修復(fù)或代碼重構(gòu),存在代碼設(shè)計(jì)質(zhì)量問題。被選取的20個(gè)類中存在代碼設(shè)計(jì)質(zhì)量問題的類數(shù)量越多,表示指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系越密切。
本文實(shí)驗(yàn)分析的項(xiàng)目是一個(gè)Java開源項(xiàng)目:dbeaver。dbeaver是一個(gè)通用的多平臺數(shù)據(jù)庫管理工具和SQL客戶端,支持幾乎所有常見的數(shù)據(jù)庫。dbeaver項(xiàng)目在GitHub上已獲得8 700個(gè)的星標(biāo)關(guān)注,開發(fā)團(tuán)隊(duì)主要成員都有超過20年的開發(fā)經(jīng)驗(yàn)。項(xiàng)目當(dāng)前仍處于活躍更新狀態(tài),社區(qū)活躍,提交歷史豐富。本文選取了該項(xiàng)目在GitHub上最早的發(fā)布版本(3.5.2)進(jìn)行指標(biāo)度量值計(jì)算,該版本包含了1 560個(gè)類,203 118行代碼,數(shù)量達(dá)到了一定的規(guī)模。由于dbeaver項(xiàng)目中版本發(fā)布的間隔約為一個(gè)月,本文只統(tǒng)計(jì)3.5.2版本發(fā)布后1個(gè)月之內(nèi)的提交記錄。項(xiàng)目中只有6.35%的類的提交歷史中涉及缺陷修復(fù),9.87%的類的提交歷史中涉及重構(gòu),即在項(xiàng)目中隨機(jī)挑選一個(gè)類,它有6.35%的概率與代碼缺陷有關(guān),9.87%的概率與代碼重構(gòu)有關(guān)。對于待驗(yàn)證指標(biāo)挑選出的20個(gè)類,本文分別統(tǒng)計(jì)并計(jì)算其中提交歷史涉及缺陷修復(fù)、涉及重構(gòu)或者兩種情況都不涉及的類的個(gè)數(shù)和所占比例。
1) RQ1:耦合度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,耦合類型的度量指標(biāo)能否有效找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
表8分別列出了FANOUT、NCC、CC、AC和CBO度量值最高的20個(gè)類中,存在代碼設(shè)計(jì)質(zhì)量問題的類統(tǒng)計(jì)數(shù)據(jù)。其中,每項(xiàng)指標(biāo)分別統(tǒng)計(jì)了涉及缺陷修復(fù)、涉及重構(gòu)以及兩者都不涉及的類的數(shù)量和占20個(gè)類的比例。與隨機(jī)挑選的概率相比,這些指標(biāo)挑選出來的類與代碼設(shè)計(jì)質(zhì)量問題相關(guān)的概率更大。NCC挑選出的類中涉及缺陷修復(fù)的比例最大,涉及重構(gòu)的比例最大,兩種情況都未涉及的比例最小,所以NCC挑選的類存在代碼設(shè)計(jì)質(zhì)量問題的概率最大。
表8 耦合度量指標(biāo)挑選類中存在質(zhì)量問題的數(shù)量統(tǒng)計(jì)
ResultSetUtils是項(xiàng)目中NCC值最高的類,NCC值為39,說明該類依賴39個(gè)無關(guān)類的服務(wù)。在未來的一個(gè)月中,它被修改了10次,其中4次與缺陷修復(fù)相關(guān),3次與重構(gòu)操作相關(guān)。ResultSetUtils依賴的數(shù)據(jù)處理器類更新后,原來的處理方式產(chǎn)生了bug,因此開發(fā)者在一次提交中對它進(jìn)行了缺陷修復(fù)。因?yàn)橐蕾囶悢?shù)量越多,被依賴類出現(xiàn)bug的概率越高,所以ResultSetUtils的缺陷修復(fù)提交較多,它的4次缺陷修復(fù)提交都來源于不同的依賴類變更。當(dāng)依賴的類發(fā)生重構(gòu)且服務(wù)方式發(fā)生變更時(shí),被依賴類也會隨著發(fā)生變更。例如ResultSetUtils需要調(diào)用DB2DataSource的方法,當(dāng)DB2DataSource因?yàn)橹貥?gòu)將部分功能轉(zhuǎn)移到DBUtils后,ResultSetUtils也會受到這次重構(gòu)的影響進(jìn)行相應(yīng)的修改。由于ResultSetUtils依賴的類較多,當(dāng)這些類發(fā)生重構(gòu)時(shí),ResultSetUtils也可能在這次重構(gòu)提交中被修改,所以ResultSetUtils會與較多的重構(gòu)操作相關(guān)。這也是NCC值高的類中與重構(gòu)相關(guān)的概率較高的原因。
CC/AC值越高意味著越多的外部類使用了該類的服務(wù),該類可能是一個(gè)基礎(chǔ)服務(wù)類。Log是CC/AC值(316)最高的類,在未來的一個(gè)月之內(nèi)發(fā)生了兩次修改,都是重構(gòu)相關(guān)的修改。Log是日志記錄類,提供了大量記錄日志的方法,功能比較獨(dú)立,只依賴兩個(gè)外部類。與ResultSetUtils不同,Log發(fā)生的重構(gòu)修改是自發(fā)的,而不是由依賴類引起的。在未來一個(gè)月中開發(fā)者通過提取代碼到新方法的方式對Log進(jìn)行了重構(gòu)。這種基礎(chǔ)服務(wù)類功能比較穩(wěn)定,需求變更很少,常見的缺陷也早被修復(fù)。同時(shí)由于較少依賴其他類,其他類的變化很少影響到它們。因此,CC/AC值高的類中總體上發(fā)生修改的類比例較少,發(fā)生重構(gòu)的類比例高于發(fā)生缺陷修復(fù)的類。
CBO可以認(rèn)為是AC/CC和FANOUT/NCC的數(shù)量匯總,但AC/CC的最高值(319)遠(yuǎn)大于NCC的最高值(39)。對于度量值較高的類,指定類受外界影響的類的個(gè)數(shù)遠(yuǎn)少于受指定類影響的類的個(gè)數(shù),所以CBO最高值的類往往也是AC/CC高的類,CBO的概率與AC/CC非常接近。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,耦合類型的度量指標(biāo)能夠有效地找到項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中耦合類數(shù)(NCC)與質(zhì)量問題關(guān)系最密切。
2) RQ2:繼承度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,繼承類型的度量指標(biāo)能否有效找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
表9分別列出了NOD值最高、HIT值最高、DIT值最高、BUR值最低的20個(gè)類中,存在代碼設(shè)計(jì)質(zhì)量問題的類統(tǒng)計(jì)數(shù)據(jù)。
表9 繼承度量指標(biāo)挑選類中存在質(zhì)量問題的數(shù)量統(tǒng)計(jì)
NOD、HIT挑選的類與代碼設(shè)計(jì)質(zhì)量問題相關(guān)的概率略高于隨機(jī)挑選的概率,DIT的概率低于隨機(jī)概率。NOD統(tǒng)計(jì)類的后代類個(gè)數(shù),HIT表示類在繼承樹中與葉子節(jié)點(diǎn)的最遠(yuǎn)距離。NOD值高的類一般是服務(wù)基礎(chǔ)類,并且開發(fā)者已經(jīng)基于這些基礎(chǔ)類創(chuàng)建了許多子類。由于dbeaver項(xiàng)目已經(jīng)發(fā)布了多個(gè)版本,可以認(rèn)為這些基礎(chǔ)類的功能和設(shè)計(jì)已經(jīng)比較穩(wěn)定,所以較少會發(fā)生修改。與NOD相比,HIT值高的類雖然也可能是基礎(chǔ)類,但是后代類個(gè)數(shù)可能不多,修改成本比較低,可能還不穩(wěn)定。例如ObjectListControl的HIT值為3,NOD值為9,在未來一個(gè)月中發(fā)生了兩次修改,其中一次是修復(fù)自身的缺陷。而NOD值(76)最高的類AbstractObjectCache沒有發(fā)生任何修改。
DIT度量值越高,表示類的繼承鏈越長,理解和維護(hù)該類的代價(jià)越高[1]。實(shí)驗(yàn)項(xiàng)目中DIT值高的類由于需要實(shí)現(xiàn)的額外功能較少,對外界的依賴也較少,出現(xiàn)缺陷或發(fā)生重構(gòu)的情況反而較少。例如DB2ReorgCheckTableDialog的DIT值最高,度量值為6,只依賴一個(gè)外部類,只定義了4個(gè)方法,且方法功能簡單,開發(fā)者在未來一個(gè)月沒有對它進(jìn)行任何修改。
保護(hù)成員只可以被其定義類的子類以及所在包的其他類使用。文獻(xiàn)[26]認(rèn)為如果子類沒有使用這些資源,可能意味著這個(gè)父子類設(shè)計(jì)存在問題。實(shí)驗(yàn)數(shù)據(jù)表明,項(xiàng)目中BUR為0的類不意味著父類的設(shè)計(jì)不合理,例如DB2TableColumnManager,父類的保護(hù)成員最多,數(shù)量為13個(gè),但是開發(fā)者在未來一個(gè)月很少修改它或者它的父類,尤其沒有針對繼承設(shè)計(jì)的修改,原因是雖然該子類沒有使用父類的任何保護(hù)成員,但是這些成員會被父類的其他子類使用,這些保護(hù)成員的設(shè)置是必要的。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,繼承類型的度量指標(biāo)找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類的效果較差,與隨機(jī)挑選的概率接近,其中繼承高度(HIT)的效果相對較好,高于隨機(jī)概率。
3) RQ3:封裝度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,封裝類型的度量指標(biāo)能否有效找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
封裝度量指標(biāo)包括DAM、NOPA、CIS和ER等4個(gè)指標(biāo),信息暴露越多的類可能產(chǎn)生越多的質(zhì)量問題。表10分別列出了NOPA值最高、DAM值最低、CIS值最高、ER值最低的20個(gè)類中,存在代碼設(shè)計(jì)質(zhì)量問題的類統(tǒng)計(jì)數(shù)據(jù)。挑選DAM值最低的類時(shí),所有類首先按照DAM值從低到高排序,然后按照屬性數(shù)量從大到小排序,因?yàn)镈AM是比例值,DAM值相同的情況下,總數(shù)多的類暴露的內(nèi)容越多。挑選ER值最小的類時(shí),所有類首先按照ER值從低到高排序,然后按照屬性和方法數(shù)之和從大到小排序,因?yàn)镋R最小值意味著類的所有屬性和方法都是公共的,它們的數(shù)量越多,類暴露的內(nèi)容越多。
表10 封裝度量指標(biāo)挑選類中存在質(zhì)量問題的數(shù)量統(tǒng)計(jì)
NOPA、DAM挑選的類出現(xiàn)代碼設(shè)計(jì)質(zhì)量問題的概率和隨機(jī)概率相近。NOPA和DAM只關(guān)注公共屬性,實(shí)驗(yàn)數(shù)據(jù)表明,一個(gè)類的公共屬性多不表示該類會出現(xiàn)質(zhì)量問題。例如CoreMessages是NOPA值(855)最高、DAM值(0)最低的類,它只有一個(gè)私有的空方法,855個(gè)公開靜態(tài)屬性和1個(gè)默認(rèn)可見靜態(tài)屬性。CoreMessages只提供信息存儲功能,任何類都能夠直接讀寫它的屬性。其他類對這些屬性的不正確讀寫可能會造成信息交互出錯(cuò),但是修復(fù)缺陷的操作不會影響CoreMessages,而是發(fā)生在它的調(diào)用者。由于CoreMessages結(jié)構(gòu)非常簡單,所以開發(fā)者也不會對它進(jìn)行重構(gòu)。因此開發(fā)者沒有對CoreMessages進(jìn)行任何修改。
ER挑選出的類的功能都比較簡單,出現(xiàn)缺陷或需要進(jìn)行重構(gòu)的概率很低。例如MySQLConstants的ER值為0,屬性和方法的總數(shù)是133,沒有聲明方法,只聲明了公共靜態(tài)屬性,屬性只允許讀。該類存儲了MySQL配置常量,開發(fā)者沒有修改它。與NOPA、DAM相比,ER選擇的類中包含了屬性個(gè)數(shù)不是很多的數(shù)據(jù)存儲類如DB2Constants,這些類可能還不穩(wěn)定,在未來會隨著業(yè)務(wù)的變化而被修改。當(dāng)項(xiàng)目中的XML處理器類變化后,DB2Constants的部分屬性也需要更新,否則會出現(xiàn)bug,這是ER挑選的類中涉及缺陷修復(fù)的比例更高的原因。
CIS挑選出的類與代碼設(shè)計(jì)質(zhì)量問題相關(guān)的概率最高,明顯高于隨機(jī)概率。公共方法數(shù)量多的類,提供的服務(wù)較多。為了提供不同類型的服務(wù),它們對外界的依賴可能較多,發(fā)生質(zhì)量問題的概率較高。由于服務(wù)類型多,當(dāng)服務(wù)需求發(fā)生變化時(shí),原有的代碼可能變成了bug。例如DriverDescriptor的CIS值為86,依賴31個(gè)外部類。當(dāng)這些依賴類發(fā)生變化時(shí),DriverDescriptor可能也需要修改。當(dāng)項(xiàng)目依賴庫發(fā)生變化時(shí),開發(fā)者通過缺陷修復(fù)的方式更新了該類的依賴解析功能。與NOPA、DAM、RER相比,CIS值高的類參與缺陷修復(fù)或代碼重構(gòu)工作的概率更高。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,與隨機(jī)挑選的概率相比,在封裝類型的度量指標(biāo)中,類接口數(shù)(CIS)能夠有效地找到項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,與質(zhì)量問題關(guān)系最密切。其他指標(biāo)的概率與隨機(jī)概率相近。
4) RQ4:規(guī)模度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,規(guī)模類型的度量指標(biāo)能否有效找出項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
規(guī)模度量指標(biāo)包括了NOA、NOM、WMC、CPC、WACC、WMACC、NOT等指標(biāo)。由于WMACC和WACC完全依賴于數(shù)據(jù)類型的權(quán)重設(shè)置,而相關(guān)文獻(xiàn)中數(shù)據(jù)類型都來源于C++,不能完全對應(yīng)Java項(xiàng)目的數(shù)據(jù)類型,本文不作分析。剩余指標(biāo)中CPC由NOA、NOT和WMC運(yùn)算得到,同時(shí)考慮了方法體和屬性。
本文選擇CPC進(jìn)行分析,度量值最高的20個(gè)類中發(fā)生了缺陷修復(fù)的類有7個(gè)(占35%),發(fā)生了重構(gòu)的類有7個(gè)(占35%),這兩種情況都沒有發(fā)生的類有9個(gè)(占45%)。相對于隨機(jī)挑選的概率,CPC挑選的類與代碼設(shè)計(jì)質(zhì)量問題相關(guān)的概率明顯更大。一個(gè)類的復(fù)雜度越高,與外界的交互越多,代碼的可讀性越低,出錯(cuò)的概率也越大。例如DBUtils的CPC值為324.42,在未來一個(gè)月內(nèi)被修改了14次,其中與缺陷修復(fù)相關(guān)的次數(shù)為2次,重構(gòu)相關(guān)的修改次數(shù)為5次。開發(fā)者在該類的開發(fā)和維護(hù)花費(fèi)了較多的時(shí)間和精力。出現(xiàn)bug的原因是代碼分支跳轉(zhuǎn)邏輯比較復(fù)雜,開發(fā)者忽略了跳轉(zhuǎn)語句的某些分支情況。復(fù)雜代碼的低可讀性會增大bug產(chǎn)生的概率,為了降低這種不良影響,開發(fā)者在缺陷修復(fù)的過程中增加了斷言語句并將長語句變成多條短語句。DBUtils對外部類依賴較多,數(shù)量達(dá)到56個(gè),這些類發(fā)生重構(gòu)時(shí)可能會導(dǎo)致DBUtils進(jìn)行相應(yīng)的修改,所以DBUtils的重構(gòu)相關(guān)提交較多。
CPC值高的類中缺陷修復(fù)和重構(gòu)都沒有發(fā)生的原因是被挑選的這些類整體復(fù)雜度高,但是成員并不復(fù)雜。例如JDBCResultSetImpl的CPC值為229.33,包含了210個(gè)方法,其中200個(gè)方法都是方法體代碼行數(shù)為1、2的簡單方法,沒有復(fù)雜度高的方法。這些簡單方法的復(fù)雜度為1,它們的復(fù)雜度之和提供了主要的復(fù)雜度。開發(fā)者沒有對它們進(jìn)行代碼修改。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,與隨機(jī)挑選相比,在規(guī)模類型的度量指標(biāo)中,類復(fù)雜度(CPC)能夠有效地找到項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,與質(zhì)量問題關(guān)系密切。
5) RQ5:內(nèi)聚度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,內(nèi)聚類型的度量指標(biāo)能否有效找出項(xiàng)目中存在質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
內(nèi)聚度量指標(biāo)包含了LCOM、CM、TCC和LCC。LCOM無法判斷相似方法對的數(shù)量是否遠(yuǎn)多于非相似方法對,CM改進(jìn)LCOM并解決這個(gè)缺陷。根據(jù)指標(biāo)定義,CM=1-2×TCC,可以認(rèn)為兩者本質(zhì)上相同。TCC=0、LCC=0代表內(nèi)聚度最差的類,根據(jù)指標(biāo)定義,TCC為0當(dāng)且僅當(dāng)LCC為0,所以在找出內(nèi)聚度最差的類方面,兩者完全等價(jià)。因此,本文只對TCC進(jìn)行分析。
挑選TCC值最低的類時(shí),首先將類按照TCC值從低到高排序,然后按照NCC值從高到低排序,選取最前面的20個(gè)類。這些類的TCC值都為0,其中涉及了缺陷修復(fù)的類有6個(gè)(占30%),涉及了重構(gòu)的類有7個(gè)(占35%),這兩種情況都沒有發(fā)生的類有11個(gè)(占55%)。TCC挑選的類與質(zhì)量問題有關(guān)的概率高于隨機(jī)概率。NCC值越高,類承擔(dān)的職能可能越復(fù)雜,越可能出現(xiàn)質(zhì)量問題。例如GenericMetaModel的NCC值是24,其中l(wèi)oadProcedures方法中調(diào)用的外部方法最多,它是職能最復(fù)雜的方法,開發(fā)者的缺陷修復(fù)發(fā)生在該方法。由于類依賴的外部類數(shù)量較多,當(dāng)這些類發(fā)生重構(gòu)變化時(shí),類也需要修改。
而NCC值低的類,它們的方法雖然互相獨(dú)立,但是方法的功能一般很簡單,類比較穩(wěn)定,所以修改較少。例如DB2TableColumn的方法基本都是訪問器方法,對外界依賴程度小,使用簡單,出錯(cuò)概率低。CommonUtils的所有方法都是靜態(tài)方法,每個(gè)方法完成一個(gè)小功能,提供對字符串、集合類、鏈表等類型數(shù)據(jù)的簡單操作。開發(fā)者對這些類的修改很少。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,與隨機(jī)挑選相比,在內(nèi)聚類型的度量指標(biāo)中,緊密方法內(nèi)聚(TCC)能夠有效地找到項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,與質(zhì)量問題關(guān)系密切。
6) RQ6:多態(tài)度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)系。
問題:與隨機(jī)挑選任意類的方式相比,多態(tài)類型的度量指標(biāo)能否有效找出項(xiàng)目中存在質(zhì)量問題的類,其中哪些指標(biāo)與質(zhì)量問題關(guān)系最密切?
類層次的多態(tài)度量指標(biāo)包括NOP和NMO/BOvM,NMO/BOvM是NOP的子集。NOP值最高的20個(gè)類中,涉及缺陷修復(fù)或重構(gòu)的類分別有4個(gè)(占20%)、5個(gè)(占25%),這兩種情況都沒有發(fā)生的類有13個(gè)(占65%)。NOP挑選的類與代碼設(shè)計(jì)質(zhì)量問題有關(guān)的概率高于隨機(jī)概率。對于實(shí)驗(yàn)項(xiàng)目,NOP等于非私有實(shí)例方法的個(gè)數(shù)。NOP值越高表示方法數(shù)量越多,需要完成的工作越多,對外界的依賴可能越多,類參與缺陷修復(fù)或代碼重構(gòu)的概率較高。例如DataSourceDescriptor的NOP值為80,依賴28個(gè)外部類,發(fā)生了4次修改,其中3次與重構(gòu)相關(guān)。由于依賴類發(fā)生了重構(gòu),它也隨之發(fā)生了修改。
結(jié)論:實(shí)驗(yàn)數(shù)據(jù)表明,與隨機(jī)挑選相比,在多態(tài)類型的度量指標(biāo)中,支持多態(tài)方法個(gè)數(shù)(NOP)能夠有效地找到項(xiàng)目中存在代碼設(shè)計(jì)質(zhì)量問題的類,與質(zhì)量問題關(guān)系密切。
內(nèi)部有效性:本文通過分析提交信息中是否包含單詞“fix”或“refactoring”來判斷該次提交是否與缺陷修復(fù)或重構(gòu)相關(guān)。如果開發(fā)者在某次提交中進(jìn)行了這兩項(xiàng)工作卻沒有在提交信息中提及,或者提交信息中沒有使用這兩個(gè)單詞,那么這次提交就會被認(rèn)為是一次普通的提交。本文的實(shí)驗(yàn)對象dbeaver項(xiàng)目的開發(fā)人員經(jīng)驗(yàn)豐富,遵循開發(fā)規(guī)范,提交信息中都會對本次提交的工作進(jìn)行總結(jié),而“fix”和“refactoring”是他們總結(jié)缺陷修復(fù)和重構(gòu)工作的常用詞,上述情形出現(xiàn)幾率較低。
外部有效性:本文的實(shí)驗(yàn)項(xiàng)目只包含了一個(gè)項(xiàng)目,分析數(shù)據(jù)相對較少,需要更多的項(xiàng)目數(shù)據(jù)支撐。不同類型的軟件可能由于存在不同的業(yè)務(wù)特點(diǎn),對不同的度量指標(biāo)敏感度不同,本文實(shí)驗(yàn)分析結(jié)果在不同類型的軟件上可能不適用。
本文將度量指標(biāo)分為規(guī)模、耦合、內(nèi)聚、封裝、繼承和多態(tài)等6種類型。對于不同度量指標(biāo),選取了20個(gè)度量值為最大值或最小值的類進(jìn)行分析,其中存在代碼設(shè)計(jì)質(zhì)量問題的類的數(shù)量多少代表了指標(biāo)與代碼設(shè)計(jì)質(zhì)量的關(guān)聯(lián)程度。實(shí)驗(yàn)分析發(fā)現(xiàn),耦合類數(shù)(NCC)、類接口數(shù)(CIS)、類復(fù)雜度(CPC)、緊密內(nèi)聚度(TCC)、支持多態(tài)方法數(shù)(NOP)、繼承樹高度(HIT)分別是耦合類型、封裝類型、規(guī)模類型、內(nèi)聚類型、多態(tài)類型、繼承類型的度量指標(biāo)與代碼設(shè)計(jì)質(zhì)量關(guān)系最密切的指標(biāo),可以更有效地找出存在代碼設(shè)計(jì)質(zhì)量問題的類。
在未來的工作中,可以把這些度量指標(biāo)應(yīng)用在不同類型的軟件上,觀察它們是否在不同軟件上都適用。不同類型的軟件可能由于存在不同的特征,對不同的度量指標(biāo)敏感度不同。這些度量指標(biāo)也可以被用于對項(xiàng)目質(zhì)量的持續(xù)監(jiān)控,結(jié)合項(xiàng)目的演化歷史分析,可以通過度量值的變化提醒開發(fā)者項(xiàng)目的質(zhì)量變化趨勢。