在 GitHub 上對編程語言與軟件質量的一個大規模研究

我們檢測到 30 個不同的領域(換句話說,就是主題),並且評估了每個項目從屬於每個領域的概率。因為,這些自動檢測的領域包含了幾個具體項目的關鍵字,例如,facebook,很難去界定它的底層的常用功能。為了給每個領域分配一個有意義的名字,我們手動檢查了 30 個與項目名字無關的用於識別領域的領域識別關鍵字。我們手動重命名了所有的 30 個自動檢測的領域,並且找出了以下六個領域的大多數的項目:應用程序、數據庫、代碼分析、中間件、庫,和框架。我們也找出了不符合以上任何一個領域的一些項目,因此,我們把這個領域籠統地標記為 其它 。隨後,我們研究組的另一名成員檢查和確認了這種項目領域分類的方式。 表 4 彙總了這個過程識別到的領域結果。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

表 4 領域特徵

2.4 bug 分類

儘管修復軟件 bug 時,開發者經常會在提交日誌中留下關於這個 bug 的原始的重要信息;例如,為什麼會產生 bug,以及怎麼去修復 bug。我們利用很多信息去分類 bug,與 Tan 的 et al 類似。 13 , 24

首先,我們基於 bug 的 原因(Cause) 和 影響(Impact) 進行分類。_ 原因 _ 進一步分解為不相關的錯誤子類:算法方面的、併發方面的、內存方面的、普通編程錯誤,和未知的。bug 的 影響 也分成四個不相關的子類:安全、性能、失敗、和其它的未知類。因此,每個 bug 修復提交也包含原因和影響的類型。 表 5 展示了描述的每個 bug 分類。這個類別分別在兩個階段中被執行:

在 GitHub 上對編程語言與軟件質量的一個大規模研究

表 5 bug 分類和在整個數據集中的描述

(1) 關鍵字搜索 我們隨機選擇了 10% 的 bug 修復信息,並且使用一個基於關鍵字的搜索技術去對它們進行自動化分類,作為可能的 bug 類型。我們對這兩種類型(原因和影響)分別使用這個註釋。我們選擇了一個限定的關鍵字和習慣用語集,如 表 5 所展示的。像這種限定的關鍵字和習慣用語集可以幫我們降低誤報。

(2) 監督分類 我們使用前面步驟中的有註釋的 bug 修復日誌作為訓練數據,為監督學習分類技術,通過測試數據來矯正,去對剩餘的 bug 修復信息進行分類。我們首先轉換每個 bug 修復信息為一個詞袋(LCTT 譯註:bag-of-words,一種信息檢索模型)。然後,刪除在所有的 bug 修復信息中僅出現過一次的詞。這樣減少了具體項目的關鍵字。我們也使用標準的自然語言處理技術來解決這個問題。最終,我們使用支持向量機(LCTT 譯註:Support Vector Machine,縮寫為 SVM,在機器學習領域中,一種有監督的學習算法)去對測試數據進行分類。

為精確評估 bug 分類器,我們手動註釋了 180 個隨機選擇的 bug 修復,平均分佈在所有的分類中。然後,我們比較手動註釋的數據集在自動分類器中的結果。最終處理後的,表現出的精確度是可接受的,性能方面的精確度最低,是 70%,併發錯誤方面的精確度最高,是 100%,平均是 84%。再次運行,精確度從低到高是 69% 到 91%,平均精確度還是 84%。

我們的 bug 分類的結果展示在 表 5 中。大多數缺陷的原因都與普通編程錯誤相關。這個結果並不意外,因為,在這個分類中涉及了大量的編程錯誤,比如,類型錯誤、輸入錯誤、編寫錯誤、等等。我們的技術並不能將在任何(原因或影響)分類中佔比為 1.4% 的 bug 修復信息再次進行分類;我們將它歸類為未知。

2.5 統計方法

我們使用迴歸模型對軟件項目相關的其它因素中的有缺陷的提交數量進行了建模。所有的模型使用 負二項迴歸(negative binomial regression)(縮寫為 NBR)(LCTT 譯註:一種迴歸分析模型) 去對項目屬性計數進行建模,比如,提交數量。NBR 是一個廣義的線性模型,用於對非負整數進行響應建模。 4

在我們的模型中,我們對每個項目的編程語言,控制幾個可能影響最終結果的因素。因此,在我們的迴歸分析中,每個(語言/項目)對是一個行,並且可以視為來自流行的開源項目中的樣本。我們依據變量計數進行對象轉換,以使變量保持穩定,並且提升了模型的適用度。 4 我們通過使用 AIC 和 Vuong 對非嵌套模型的測試比較來驗證它們。

去檢查那些過度的多重共線性(LCTT 譯註:多重共線性是指,在線性迴歸模型中解釋變量之間由於存在精確相關關係或高度相關關係而使模型估計失真或難以估計準確。)並不是一個問題,我們在所有的模型中使用一個保守的最大值 5,去計算每個依賴的變量的膨脹因子的方差。 4 我們通過對每個模型的殘差和槓桿圖進行視覺檢查來移除高槓杆點,找出庫克距離(LCTT 譯註:一個統計學術語,用於診斷迴歸分析中是否存在異常數據)的分離值和最大值。

我們利用 效果 ,或者 差異 ,編碼到我們的研究中,以提高編程語言迴歸係數的表現。 4 加權的效果代碼允許我們將每種編程語言與所有編程語言的效果進行比較,同時彌補了跨項目使用編程語言的不均勻性。 23 去測試兩種變量因素之間的聯繫,我們使用一個獨立的卡方檢驗(LCTT 譯註:Chi-square,一種統計學上的假設檢驗方法)測試。 14 在證實一個依賴之後,我們使用 Cramer 的 V,它是與一個 r × c 等價的正常數據的 phi(φ) 係數,去建立一個效果數據。

3 結果

我們從簡單明瞭的問題開始,它非常直接地解決了人們堅信的一些核心問題,即:

問題 1:一些編程語言相比其它語言來說更易於出現缺陷嗎?

我們使用了迴歸分析模型,去比較每個編程語言對所有編程語言缺陷數量平均值的影響,以及對缺陷修復提交的影響(查看 表 6 )。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

表 6. 一些語言的缺陷要少於其它語言

我們包括了一些變量,作為對明確影響反應的控制因子。項目 年齡(age)也包括在內,因為,越老的項目生成的缺陷修復數量越大。 提交(commits)數量也會對項目反應有輕微的影響。另外,從事該項目的 開發人員(dev)的數量和項目的原始 大小(size),都會隨著項目的活躍而增長。

上述模型中估算係數的大小和符號(LCTT 譯註:指 “+”或者“-”)與結果的預測因子有關。初始的四種變量是控制變量,並且,我們對這些變量對最終結果的影響不感興趣,只是說它們都是積極的和有意義的。語言變量是指示變量,是每個項目的變化因子,該因子將每種編程語言與所有項目的編程語言的加權平均值進行比較。編程語言係數可以大體上分為三類。第一類是,那些在統計學上無關緊要的係數,並且在建模過程中這些係數不能從 0 中區分出來。這些編程語言的表現與平均值相似,或者它們也可能有更大的方差。剩餘的係數是非常明顯的,要麼是正的,要麼是負的。對於那些正的係數,我們猜測可能與這個編程語言有大量的缺陷修復相關。這些語言包括 C、C++、Objective-C、Php,以及 Python。所有的有一個負的係數的編程語言,比如 Clojure、Haskell、Ruby,和 Scala,暗示這些語言的缺陷修復提交可能小於平均值。

應該注意的是,雖然,從統計學的角度觀察到編程語言與缺陷之間有明顯的聯繫,但是,大家不要過高估計編程語言對於缺陷的影響,因為,這種影響效應是非常小的。異常分析的結果顯示,這種影響小於總異常的 1%。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

ut1.jpg

我們可以這樣去理解模型的係數,它代表一個預測因子在所有其它預測因子保持不變的情況下,這個預測因子一個 單位(unit)的變化,所反應出的預期的響應的對數變化;換句話說,對於一個係數 βi ,在 βi 中一個單位的變化,產生一個預期的 eβi 響應的變化。對於可變因子,這個預期的變化是與所有編程語言的平均值進行比較。因此,如果對於一定數量的提交,用一個處於平均值的編程語言開發的特定項目有四個缺陷提交,那麼,如果選擇使用 C++ 來開發,意味著我們預計應該有一個額外的(LCTT 譯註:相對於平均值 4,多 1 個)缺陷提交,因為 e0.18 × 4 = 4.79。對於相同的項目,如果選擇使用 Haskell 來開發,意味著我們預計應該少一個(LCTT 譯註:同上,相對於平均值 4)缺陷提交。因為, e−0.26 × 4 = 3.08。預測的精確度取決於剩餘的其它因子都保持不變,除了那些微不足道的項目之外,所有的這些都是一個極具挑戰性的命題。所有觀察性研究都面臨類似的侷限性;我們將在第 5 節中詳細解決這些事情。

結論 1:一些編程語言相比其它編程語言有更高的缺陷相關度,不過,影響非常小。

在這篇文章的剩餘部分,我們會在基本結論的基礎上詳細闡述,通過考慮不同種類的應用程序、缺陷、和編程語言,可以進一步深入瞭解編程語言和缺陷傾向之間的關係。

軟件 bug 通常落進兩種寬泛的分類中:

  1. 特定領域的 bug :特定於項目功能,並且不依賴於底層編程語言。
  2. 普通 bug :大多數的普通 bug 是天生的,並且與項目功能無關,比如,輸入錯誤,併發錯誤、等等。

因此,在一個項目中,應用程序領域和編程語言相互作用可能會影響缺陷的數量,這一結論被認為是合理的。因為一些編程語言被認為在一些任務上相比其它語言表現更突出,例如,C 對於低級別的(底層)工作,或者,Java 對於用戶應用程序,對於編程語言的一個不合適的選擇,可能會帶來更多的缺陷。為研究這種情況,我們將理想化地忽略領域特定的 bug,因為,普通 bug 更依賴於編程語言的特性。但是,因為一個領域特定的 bug 也可能出現在一個普通的編程錯誤中,這兩者是很難區分的。一個可能的變通辦法是在控制領域的同時去研究編程語言。從統計的角度來看,雖然,使用 17 種編程語言跨 7 個領域,在給定的樣本數量中,理解大量的術語將是一個極大的挑戰。

鑑於這種情況,我們首先考慮在一個項目中測試領域和編程語言使用之間的依賴關係,獨立使用一個 卡方檢驗(Chi-square)測試。在 119 個單元中,是 46 個,也就是說是 39%,它在我們設定的保守值 5 以上,它太高了。這個數字不能超過 20%,應該低於 5。 14 我們在這裡包含了完整有值; d 但是,通過 Cramer 的 V 測試的值是 0.191,是低相關度的,表明任何編程語言和領域之間的相關度是非常小的,並且,在迴歸模型中包含領域並不會產生有意義的結果。

去解決這種情況的一個選擇是,去移除編程語言,或者混合領域,但是,我們現有的數據沒有進行完全挑選。或者,我們混合編程語言;這個選擇導致一個相關但略有不同的問題。

問題 2: 哪些編程語言特性與缺陷相關?

我們按編程語言類別聚合它們,而不是考慮單獨的編程語言,正如在第 2.2 節所描述的那樣,然後去分析與缺陷的關係。總體上說,這些屬性中的每一個都將編程語言按照在上下文中經常討論的錯誤、用戶辯論驅動、或者按以前工作主題來劃分的。因此,單獨的屬性是高度相關的,我們創建了六個模型因子,將所有的單獨因子綜合到我們的研究中。然後,我們對六個不同的因子對缺陷數量的影響進行建模,同時控制我們在 問題 1節中使用的模型中的相同的基本協變量(LCTT 譯註:協變量是指在實驗中不能被人為操縱的獨立變量)。

關於使用的編程語言(在前面的 表 6 中),我們使用跨所有語言類的平均反應來比較編程語言 類 。這個模型在 表 7 中表達了出來。很明顯,Script-Dynamic-Explicit-Managed 類有最小的量級係數。這個係數是微不足道的,換句話說,對這個係數的 Z 校驗(z-test)(LCTT 譯註:統計學上的一種平均值差異校驗的方法) 並不能把它從 0 中區分出來。鑑於標準錯誤的量級,我們可以假設,在這個類別中的編程語言的行為是非常接近於所有編程語言行為的平均值。我們可以通過使用 Proc-Static-Implicit-Unmanaged 作為基本級並用於處理,或者使用基本級來虛假編碼比較每個語言類,來證明這一點。在這種情況下,Script-Dynamic-Explicit-Managed 是明顯不同於 p = 0.00044 的。注意,雖然我們在這是選擇了不同的編碼方法,影響了係數和 Z 值,這個方法和所有其它的方面都是一樣的。當我們改變了編碼,我們調整係數去反應我們希望生成的對比。 4 將其它類的編程語言與總體平均數進行比較,Proc-Static-Implicit-Unmanaged 類編程語言更容易引起缺陷。這意味著與其它過程類編程語言相比,隱式類型轉換或者管理內存會導致更多的缺陷傾向。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

表 7. 函數式語言與缺陷的關聯度和其它類語言相比要低,而過程類語言則大於或接近於平均值。

在腳本類編程語言中,我們觀察到類似於允許與不允許隱式類型轉換的編程語言之間的關係,它們提供的一些證據表明,隱式類型轉換(與顯式類型轉換相比)才是導致這種差異的原因,而不是內存管理。鑑於各種因素之間的相關性,我們並不能得出這個結論。但是,當它們與平均值進行比較時,作為一個組,那些不允許隱式類型轉換的編程語言出現錯誤的傾向更低一些,而那些出現錯誤傾向更高的編程語言,出現錯誤的機率則相對更高。在函數式編程語言中靜態和動態類型之間的差異也很明顯。

函數式語言作為一個組展示了與平均值的很明顯的差異。靜態類型語言的係數要小很多,但是函數式語言類都有同樣的標準錯誤。函數式靜態編程語言出現錯誤的傾向要小於函數式動態編程語言,這是一個強有力的證據,儘管如此,Z 校驗僅僅是檢驗係數是否能從 0 中區分出來。為了強化這個推論,我們使用處理編碼,重新編碼了上面的模型,並且觀察到,Functional-Static-Explicit-Managed 編程語言類的錯誤傾向是明顯小於 Functional-Dynamic-Explicit-Managed 編程語言類的 p = 0.034。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

ut2.jpg

與編程語言和缺陷一樣,編程語言類與缺陷之間關係的影響是非常小的。解釋類編程語言的這種差異也是相似的,雖然很小,解釋類編程語言的這種差異小於 1%。

我們現在重新回到應用領域這個問題。應用領域是否與語言類相互影響?怎麼選擇?例如,一個函數化編程語言,對特定的領域有一定的優勢?與上面一樣,對於這些因素和項目領域之間的關係做一個卡方檢驗,它的值是 99.05, df = 30, p = 2.622e–09,我們拒絕無意義假設,Cramer 的 V 產生的值是 0.133,表示一個弱關聯。因此,雖然領域和編程語言之間有一些關聯,但在這裡應用領域和編程語言類之間僅僅是一個非常弱的關聯。

結論 2:在編程語言類與缺陷之間有一個很小但是很明顯的關係。函數式語言與過程式或者腳本式語言相比,缺陷要少。

這個結論有些不太令人滿意的地方,因為,我們並沒有一個強有力的證據去證明,在一個項目中編程語言或者語言類和應用領域之間的關聯性。一個替代方法是,基於全部的編程語言和應用領域,忽略項目和缺陷總數,而去查看相同的數據。因為,這樣不再產生不相關的樣本,我們沒有從統計學的角度去嘗試分析它,而是使用一個描述式的、基於可視化的方法。

我們定義了 缺陷傾向(Defect Proneness) 作為 bug 修復提交與每語言每領域總提交的比率。 圖 1 使用了一個熱力圖展示了應用領域與編程語言之間的相互作用,從亮到暗表示缺陷傾向在增加。我們研究了哪些編程語言因素影響了跨多種語言寫的項目的缺陷修復提交。它引出了下面的研究問題:

在 GitHub 上對編程語言與軟件質量的一個大規模研究

圖 1. 編程語言的缺陷傾向與應用領域之間的相互作用。對於一個給定的領域(列底部),熱力圖中的每個格子表示了一個編程語言的缺陷傾向(行頭部)。“整體”列表示一個編程語言基於所有領域的缺陷傾向。用白色十字線標記的格子代表一個 null 值,換句話說,就是在那個格子裡沒有符合的提交。

問題 3: 編程語言的錯誤傾向是否取決於應用領域?

為了回答這個問題,我們首先在我們的迴歸模型中,以高槓杆點過濾掉認為是異常的項目,這種方法在這裡是必要的,儘管這是一個非統計學的方法,一些關係可能影響可視化。例如,我們找到一個簡單的項目,Google 的 v8,一個 JavaScript 項目,負責中間件中的所有錯誤。這對我們來說是一個驚喜,因為 JavaScript 通常不用於中間件。這個模式一直在其它應用領域中不停地重複著,因此,我們過濾出的項目的缺陷度都低於 10% 和高於 90%。這個結果在 圖 1 中。

我們看到在這個熱力圖中僅有一個很小的差異,正如在問題 1 節中看到的那樣,這個結果僅表示編程語言固有的錯誤傾向。為驗證這個推論,我們測量了編程語言對每個應用領域和對全部應用領域的缺陷傾向。對於除了數據庫以外的全部領域,關聯性都是正向的,並且 p 值是有意義的(<0.01)。因此,關於缺陷傾向,在每個領域的語言排序與全部領域的語言排序是基本相同的。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

ut3.jpg

結論 3: 應用領域和編程語言缺陷傾向之間總體上沒有聯繫。

我們證明了不同的語言產生了大量的缺陷,並且,這個關係不僅與特定的語言相關,也適用於一般的語言類;然而,我們發現,項目類型並不能在一定程度上協調這種關係。現在,我們轉變我們的注意力到反應分類上,我想去了解,編程語言與特定種類的缺陷之間有什麼聯繫,以及這種關係怎麼與我們觀察到的更普通的關係去比較。我們將缺陷分為不同的類別,如 表 5 所描述的那樣,然後提出以下的問題:

問題 4:編程語言與 bug 分類之間有什麼關係?

我們使用了一個類似於問題 3 中所用的方法,去了解編程語言與 bug 分類之間的關係。首先,我們研究了 bug 分類和編程語言類之間的關係。一個熱力圖( 圖 2 )展示了在編程語言類和 bug 類型之上的總缺陷數。去理解 bug 分類和語言之間的相互作用,我們對每個類別使用一個 NBR 迴歸模型。對於每個模型,我們使用了與問題 1 中相同的控制因素,以及使用加權效應編碼後的語言,去預測缺陷修復提交。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

圖 2. bug 類別與編程語言類之間的關係。每個格子表示每語言類(行頭部)每 bug 類別(列底部)的 bug 修復提交佔全部 bug 修復提交的百分比。這個值是按列規範化的。

結果和編程語言的方差分析值展示在 表 8 中。每個模型的整體異常是非常小的,並且對於特定的缺陷類型,通過語言所展示的比例在大多數類別中的量級是類似的。我們解釋這種關係為,編程語言對於特定的 bug 類別的影響要大於總體的影響。儘管我們結論概括了全部的類別,但是,在接下來的一節中,我們對 表 5 中反應出來的 bug 數較多的 bug 類別做進一步研究。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

表 8. 雖然編程語言對缺陷的影響因缺陷類別而不同,但是,編程語言對特定的類別的影響要大於一般的類別。

編程錯誤 普通的編程錯誤佔所有 bug 修復提交的 88.53% 左右,並且在所有的編程語言類中都有。因此,迴歸分析給出了一個與問題 1 中類似的結論(查看 表 6 )。所有的編程語言都會導致這種編程錯誤,比如,處理錯誤、定義錯誤、輸入錯誤、等等。

內存錯誤 內存錯誤佔所有 bug 修復提交的 5.44%。熱力圖 圖 2 證明了在 Proc-Static-Implicit-Unmanaged 類和內存錯誤之間存在著非常緊密的聯繫。非管理內存的編程語言出現內存 bug,這是預料之中的。 表 8 也證明了這一點,例如,C、C++、和 Objective-C 引發了很多的內存錯誤。在管理內存的語言中 Java 引發了更多的內存錯誤,儘管它少於非管理內存的編程語言。雖然 Java 自己做內存回收,但是,它出現內存洩露一點也不奇怪,因為對象引用經常阻止內存回收。 11 在我們的數據中,Java 的所有內存錯誤中,28.89% 是內存洩漏造成的。就數量而言,編程語言中內存缺陷相比其它類別的 原因 造成的影響要大很多。

併發錯誤 在總的 bug 修復提交中,併發錯誤相關的修復提交佔 1.99%。熱力圖顯示,Proc-Static-Implicit-Unmanaged 是主要的錯誤類型。在這種錯誤中,C 和 C++ 分別佔 19.15% 和 7.89%,並且它們分佈在各個項目中。

在 GitHub 上對編程語言與軟件質量的一個大規模研究

ut4.jpg

屬於 Static-Strong-Managed 語言類的編程語言都被證實處於熱力圖中的暗區中,普通的靜態語言相比其它語言產生更多的併發錯誤。在動態語言中,僅僅有 Erlang 有更多的併發錯誤傾向,或許與使用這種語言開發的併發應用程序非常多有關係。同樣地,在 表 8 中的負的係數表明,用諸如 Ruby 和 `Php 這樣的動態編程語言寫的項目,併發錯誤要少一些。請注意,某些語言,如 JavaScript、CoffeeScript 和 TypeScript 是不支持併發的,在傳統的慣例中,雖然 Php 具有有限的併發支持(取決於它的實現)。這些語言在我們的數據中引入了虛假的 0,因此,在 表 8 中這些語言的併發模型的係數,不能像其它的語言那樣去解釋。因為存在這些虛假的 0,所以在這個模型中所有語言的平均數非常小,它可能影響係數的大小,因此,她們給 w.r.t. 一個平均數,但是,這並不影響他們之間的相對關係,因為我們只關注它們的相對關係。

基於 bug 修復消息中高頻詞的文本分析表明,大多數的併發錯誤發生在一個條件爭用、死鎖、或者不正確的同步上,正如上面表中所示。遍歷所有語言,條件爭用是併發錯誤出現最多的原因,例如,在 Go 中佔 92%。在 Go 中條件爭用錯誤的改進,或許是因為使用了一個爭用檢測工具幫助開發者去定位爭用。同步錯誤主要與消息傳遞接口(MPI)或者共享內存操作(SHM)相關。Erlang 和 Go 對線程間通訊使用 MPI e ,這就是為什麼這兩種語言沒有發生任何 SHM 相關的錯誤的原因,比如共享鎖、互斥鎖等等。相比之下,為線程間通訊使用早期的 SHM 技術的語言寫的項目,就可能存在鎖相關的錯誤。

安全和其它衝突錯誤 在所有的 bug 修復提交中,與 衝突(Impact)錯誤相關的提交佔了 7.33% 左右。其中,Erlang、C++、Python 與安全相關的錯誤要高於平均值( 表 8 )。Clojure 項目相關的安全錯誤較少( 圖 2 )。從熱力圖上我們也可以看出來,靜態語言一般更易於發生失敗和性能錯誤,緊隨其後的是 Functional-Dynamic-Explicit-Managed 語言,比如 Erlang。對異常結果的分析表明,編程語言與衝突失敗密切相關。雖然安全錯誤在這個類別中是弱相關的,與殘差相比,解釋類語言的差異仍然比較大。

結論 4: 缺陷類型與編程語言強相關;一些缺陷類型比如內存錯誤和併發錯誤也取決於早期的語言(所使用的技術)。對於特定類別,編程語言所引起的錯誤比整體更多。

4. 相關工作

在編程語言比較之前做的工作分為以下三類:

(1) 受控實驗

對於一個給定的任務,開發者使用不同的語言進行編程時受到監視。研究然後比較結果,比如,開發成果和代碼質量。Hanenberg 7 通過開發一個解析程序,對 48 位程序員監視了 27 小時,去比較了靜態與動態類型。他發現這兩者在代碼質量方面沒有顯著的差異,但是,基於動態類型的語言花費了更短的開發時間。他們的研究是在一個實驗室中,使用本科學生,設置了定製的語言和 IDE 來進行的。我們的研究正好相反,是一個實際的流行軟件應用的研究。雖然我們只能夠通過使用迴歸模型間接(和 事後 )控制混雜因素,我們的優勢是樣本數量大,並且更真實、使用更廣泛的軟件。我們發現在相同的條件下,靜態化類型的語言比動態化類型的語言更少出現錯誤傾向,並且不允許隱式類型轉換的語言要好於允許隱式類型轉換的語言,其對結果的影響是非常小的。這是合理的,因為樣本量非常大,所以這種非常小的影響在這個研究中可以看得到。

Harrison et al. 8 比較了 C++ 與 SML,一個是過程化編程語言,一個是函數化編程語言,在總的錯誤數量上沒有找到顯著的差異,不過 SML 相比 C++ 有更高的缺陷密集度。SML 在我們的數據中並沒有體現出來,不過,認為函數式編程語言相比過程化編程語言更少出現缺陷。另一個重點工作是比較跨不同語言的開發工作。12 , 20 不過,他們並不分析編程語言的缺陷傾向。

(2) 調查

Meyerovich 和 Rabkin 16 調查了開發者對編程語言的觀點,去研究為什麼一些編程語言比其它的語言更流行。他們的報告指出,非編程語言的因素影響非常大:先前的編程語言技能、可用的開源工具、以及現有的老式系統。我們的研究也證明,可利用的外部工具也影響軟件質量;例如,在 Go 中的併發 bug(請查看問題 4 節內容)。

(3) 對軟件倉庫的挖掘

Bhattacharya 和 Neamtiu 1 研究了用 C 和 C++ 開發的四個項目,並且發現在 C++ 中開發的組件一般比在 C 中開發的組件更可靠。我們發現 C 和 C++ 的錯誤傾向要高於全部編程語言的平均值。但是,對於某些 bug 類型,像併發錯誤,C 的缺陷傾向要高於 C++(請查看第 3 節中的問題 4)。

5. 有效的風險

我們認為,我們的報告的結論幾乎沒有風險。首先,在識別 bug 修復提交方面,我們依賴的關鍵字是開發者經常用於表示 bug 修復的關鍵字。我們的選擇是經過認真考慮的。在一個持續的開發過程中,我們去捕獲那些開發者一直面對的問題,而不是他們報告的 bug。不過,這種選擇存在過高估計的風險。我們對領域分類是為了去解釋缺陷的傾向,而且,我們研究組中另外的成員驗證過分類。此外,我們花費精力去對 bug 修復提交進行分類,也可能有被最初選擇的關鍵字所汙染的風險。每個項目在提交日誌的描述上也不相同。為了緩解這些風險,我們像 2.4 節中描述的那樣,利用手工註釋評估了我們的類別。

我們判斷文件所屬的編程語言是基於文件的擴展名。如果使用不同的編程語言寫的文件使用了我們研究的通用的編程語言文件的擴展名,這種情況下也容易出現錯誤傾向。為減少這種錯誤,我們使用一個隨機樣本文件集手工驗證了我們的語言分類。

根據我們的數據集所顯示的情形,2.2 節中的解釋類編程語言,我們依據編程語言屬性的主要用途作了一些假設。例如,我們將 Objective-C 分到非管理內存類型中,而不是混合類型。同樣,我們將 Scala 註釋為函數式編程語言,將 C# 作為過程化的編程語言,雖然,它們在設計的選擇上兩者都支持。 19 , 21 在這項研究工作中,我們沒有從過程化編程語言中分離出面向對象的編程語言(OOP),因為,它們沒有清晰的區別,主要差異在於編程類型。我們將 C++ 分到允許隱式類型轉換的類別中是因為,某些類型的內存區域可以通過使用指針操作被進行不同的處理, 22 並且我們注意到大多數 C++ 編譯器可以在編譯時檢測類型錯誤。

最後,我們將缺陷修復提交關聯到編程語言屬性上,它們可以反應出報告的風格或者其它開發者的屬性。可用的外部工具或者 庫(library)也可以影響一個相關的編程語言的 bug 數量。

6. 總結

我們對編程語言和使用進行了大規模的研究,因為它涉及到軟件質量。我們使用的 Github 上的數據,具有很高的複雜性和多個維度上的差異的特性。我們的樣本數量允許我們對編程語言效果以及在控制一些混雜因素的情況下,對編程語言、應用領域和缺陷類型之間的相互作用,進行一個混合方法的研究。研究數據顯示,函數式語言是好於過程化語言的;不允許隱式類型轉換的語言是好於允許隱式類型轉換的語言的;靜態類型的語言是好於動態類型的語言的;管理內存的語言是好於非管理的語言的。進一步講,編程語言的缺陷傾向與軟件應用領域並沒有關聯。另外,每個編程語言更多是與特定的 bug 類別有關聯,而不是與全部 bug。

另一方面,即便是很大規模的數據集,它們被多種方法同時進行分割後,也變得很小且不全面。因此,隨著依賴的變量越來越多,很難去回答某個變量所產生的影響有多大這種問題,尤其是在變量之間相互作用的情況下。因此,我們無法去量化編程語言在使用中的特定的效果。其它的方法,比如調查,可能對此有幫助。我們將在以後的工作中來解決這些挑戰。

致謝

  1. Bhattacharya, P., Neamtiu, I. Assessing programming language impact on development and maintenance: A study on C and C++. In Proceedings of the 33rd International Conference on Software Engineering, ICSE'11 (New York, NY USA, 2011). ACM, 171–180.
  2. Bird, C., Nagappan, N., Murphy, B., Gall, H., Devanbu, P. Don't touch my code! Examining the effects of ownership on software quality. In Proceedings of the 19th ACM SIGSOFT Symposium and the 13th European Conference on Foundations of Software Engineering (2011). ACM, 4–14.
  3. Blei, D.M. Probabilistic topic models. Commun. ACM 55 , 4 (2012), 77–84.
  4. Cohen, J. Applied Multiple Regression/Correlation Analysis for the Behavioral Sciences.Lawrence Erlbaum, 2003.
  5. Easterbrook, S., Singer, J., Storey, M.-A., Damian, D. Selecting empirical methods for software engineering research. In Guide to Advanced Empirical Software Engineering (2008). Springer, 285–311.
  6. El Emam, K., Benlarbi, S., Goel, N., Rai, S.N. The confounding effect of class size on the validity of object-oriented metrics. IEEE Trans. Softw. Eng. 27 , 7 (2001), 630–650.
  7. Hanenberg, S. An experiment about static and dynamic type systems: Doubts about the positive impact of static type systems on development time. In Proceedings of the ACM International Conference on Object Oriented Programming Systems Languages and Applications, OOPSLA'10 (New York, NY, USA, 2010). ACM, 22–35.
  8. Harrison, R., Smaraweera, L., Dobie, M., Lewis, P. Comparing programming paradigms: An evaluation of functional and object-oriented programs. Softw. Eng. J. 11 , 4 (1996), 247–254.
  9. Harter, D.E., Krishnan, M.S., Slaughter, S.A. Effects of process maturity on quality, cycle time, and effort in software product development. Manage. Sci. 46 4 (2000), 451–466.
  10. Hindley, R. The principal type-scheme of an object in combinatory logic. Trans. Am. Math. Soc. (1969), 29–60.
  11. Jump, M., McKinley, K.S. Cork: Dynamic memory leak detection for garbage-collected languages. In ACM SIGPLAN Notices , Volume 42 (2007). ACM, 31–38.
  12. Kleinschmager, S., Hanenberg, S., Robbes, R., Tanter, É., Stefik, A. Do static type systems improve the maintainability of software systems? An empirical study. In 2012 IEEE 20th International Conference on Program Comprehension (ICPC) (2012). IEEE, 153–162.
  13. Li, Z., Tan, L., Wang, X., Lu, S., Zhou, Y., Zhai, C. Have things changed now? An empirical study of bug characteristics in modern open source software. In ASID'06: Proceedings of the 1st Workshop on Architectural and System Support for Improving Software Dependability (October 2006).
  14. Marques De Sá, J.P. Applied Statistics Using SPSS, Statistica and Matlab , 2003.
  15. Mayer, C., Hanenberg, S., Robbes, R., Tanter, É., Stefik, A. An empirical study of the influence of static type systems on the usability of undocumented software. In ACM SIGPLAN Notices , Volume 47 (2012). ACM, 683–702.
  16. Meyerovich, L.A., Rabkin, A.S. Empirical analysis of programming language adoption. In Proceedings of the 2013 ACM SIGPLAN International Conference on Object Oriented Programming Systems Languages & Applications (2013). ACM, 1–18.
  17. Milner, R. A theory of type polymorphism in programming. J. Comput. Syst. Sci. 17 , 3 (1978), 348–375.
  18. Mockus, A., Votta, L.G. Identifying reasons for software changes using historic databases. In ICSM'00. Proceedings of the International Conference on Software Maintenance (2000). IEEE Computer Society, 120.
  19. Odersky, M., Spoon, L., Venners, B. Programming in Scala. Artima Inc, 2008.
  20. Pankratius, V., Schmidt, F., Garretón, G. Combining functional and imperative programming for multicore software: An empirical study evaluating scala and java. In Proceedings of the 2012 International Conference on Software Engineering (2012). IEEE Press, 123–133.
  21. Petricek, T., Skeet, J. Real World Functional Programming: With Examples in F# and C#.Manning Publications Co., 2009.
  22. Pierce, B.C. Types and Programming Languages. MIT Press, 2002.
  23. Posnett, D., Bird, C., Dévanbu, P. An empirical study on the influence of pattern roles on change-proneness. Emp. Softw. Eng. 16 , 3 (2011), 396–423.
  24. Tan, L., Liu, C., Li, Z., Wang, X., Zhou, Y., Zhai, C. Bug characteristics in open source software. Emp. Softw. Eng. (2013).

作者

Baishakhi Ray ( [email protected] ), Department of Computer Science, University of Virginia, Charlottesville, VA.

Daryl Posnett ( [email protected] ), Department of Computer Science, University of California, Davis, CA.

Premkumar Devanbu ( [email protected] ), Department of Computer Science, University of California, Davis, CA.

Vladimir Filkov ( [email protected] ), Department of Computer Science, University of California, Davis, CA.

腳註

  • a. Wikipedia's article on type conversion, https://en.wikipedia.org/wiki/Type_conversion , has more examples of unintended behavior in C.
  • b. This Apple developer article describes the usage of "id" http://tinyurl.com/jkl7cby .
  • c. Some examples can be found here http://dobegin.com/objc-id-type/ and here http://tinyurl.com/hxv8kvg .
  • d. Chi-squared value of 243.6 with 96 df. and p = 8.394e–15
  • e. MPI does not require locking of shared resources.

via: https://cacm.acm.org/magazines/2017/10/221326-a-large-scale-study-of-programming-languages-and-code-quality-in-github/fulltext?imm_mid=0f7103&cmp=em-prog-na-na-newsltr_20171007


分享到:


相關文章: