PRF:20171007 A Large-Scale Study of Programming Languages and Code Quality in GitHub.md

部分
This commit is contained in:
Xingyu.Wang 2018-06-27 08:48:47 +08:00
parent 04b7699f80
commit f3eaddce1e

View File

@ -4,60 +4,63 @@
![A Large-Scale Study of Programming Languages, illustration](https://cacm.acm.org/system/assets/0002/8759/092117_Getty_Large-Scale-Study1.large.jpg?1506007488&1506007487 "A Large-Scale Study of Programming Languages, illustration")
编程语言对软件质量的影响是什么?这个问题在很长一段时间内成为一个引起了大量辩论的主题。在这项研究中,我们从 GitHub 上收集了大量的数据728 个项目6300 万行源代码29000 位作者150 万个提交17 种编程语言),尝试在这个问题上提供一些实证。这个还算比较大的样本数量允许我们去使用一个混合的方法,结合多种可视化的回归模型和文本分析,去研究语言特性的影响,比如,在软件质量上,静态与动态类型和允许混淆与不允许混淆的类型。通过从不同的方法作三角测量研究(译者注:一种测量研究的方法),并且去控制引起混淆的因素,比如,团队大小、项目大小、和项目历史,我们的报告显示,语言设计确实有很大的影响,但是,在软件质量方面,语言的影响是非常有限的。最明显的似乎是,不允许混淆的类型比允许混淆的类型要稍微好一些,并且,在函数式语言中,静态类型也比动态类型好一些。值得注意的是,这些由语言设计所引起的轻微影响,绝大多数是由过程因素所主导的,比如,项目大小,团队大小,和提交数量。但是,我们警告读者,即便是这些不起眼的轻微影响,也是由其它的无形的过程因素所造成的,例如,对某些函数类型、以及不允许类型混淆的静态语言的偏爱。
[Back to Top][46]
编程语言对软件质量的影响是什么?这个问题在很长一段时间内成为一个引起了大量辩论的主题。在这项研究中,我们从 GitHub 上收集了大量的数据728 个项目6300 万行源代码29000 位作者150 万个提交17 种编程语言尝试在这个问题上提供一些实证。这个还算比较大的样本数量允许我们去使用一个混合的方法结合多种可视化的回归模型和文本分析去研究语言特性的影响比如在软件质量上静态与动态类型和允许混淆与不允许混淆的类型。通过从不同的方法作三角测量研究LCTT 译注:一种测量研究的方法),并且去控制引起混淆的因素,比如,团队大小、项目大小和项目历史,我们的报告显示,语言设计确实(对很多方面)有很大的影响,但是,在软件质量方面,语言的影响是非常有限的。最明显的似乎是,不允许混淆的类型比允许混淆的类型要稍微好一些,并且,在函数式语言中,静态类型也比动态类型好一些。值得注意的是,这些由语言设计所引起的轻微影响,绝大多数是由过程因素所主导的,比如,项目大小、团队大小和提交数量。但是,我们需要提示读者,即便是这些不起眼的轻微影响,也是由其它的无形的过程因素所造成的,例如,对某些函数类型、以及不允许类型混淆的静态语言的偏爱。
### 1 序言
在给定的编程语言是否是“适合这个工作的正确工具”的讨论期间,紧接着又发生了多种辩论。虽然一些辩论出现了带有宗教般狂热的色彩,但是大部分人都一致认为,编程语言的选择能够对编码过程和由此生成的结果都有影响。
主张强静态类型的人,倾向于认为静态方法能够在早期捕获到缺陷;他们认为,一点点的预防胜过大量的矫正。动态类型拥护者主张,保守的静态类型检查无论怎样都是非常浪费开发者资源的,并且,最好是依赖强动态类型检查来捕获错误类型。然而,这些辩论,大多数都是“纸上谈兵”,只靠“传说中”的证据去支持。
主张强静态类型的人,倾向于认为静态方法能够在早期捕获到缺陷;他们认为,一点点的预防胜过大量的矫正。动态类型拥护者主张,保守的静态类型检查无论怎样都是非常浪费开发者资源的,并且,最好是依赖强动态类型检查来捕获错误类型。然而,这些辩论,大多数都是“纸上谈兵”,只靠“传说中”的证据去支持。
这些“传说”也许并不是没有道理的;考虑到影响软件工程结果的大量其它因素,获取这种经验性的证据支持是一项极具挑战性的任务,比如,代码质量语言特征,以及应用领域。比如软件质量,考虑到它有大量的众所周知的影响因素,比如,代码数量,[6][1] 团队大小,[2][2]和年龄/熟练程度[9][3]。
这些“传说”也许并不是没有道理的;考虑到影响软件工程结果的大量其它因素,获取这种经验性的证据支持是一项极具挑战性的任务,比如,代码质量语言特征,以及应用领域。比如软件质量,考虑到它有大量的众所周知的影响因素,比如,代码数量, ^[6][1] 团队大小, ^[2][2] 和年龄/熟练程度。 ^[9][3]
受控实验是检验语言选择在面对如此令人气馁的混淆影响时的一种方法,然而,由于成本的原因,这种研究通常会引入一种它们自己的混淆,也就是说,限制了范围。在这种研究中,完整的任务是必须要受限制的,并且不能去模拟 _真实的世界_ 中的开发。这里有几个最近的这种大学本科生使用的研究,或者,通过一个实验因素去比较静态或动态类型的语言。[7][4][12][5][15][6]
受控实验是检验语言选择在面对如此令人气馁的混淆影响时的一种方法,然而,由于成本的原因,这种研究通常会引入一种它们自己的混淆,也就是说,限制了范围。在这种研究中,完整的任务是必须要受限制的,并且不能去模拟 _真实的世界_ 中的开发。这里有几个最近的这种大学本科生使用的研究,或者,通过一个实验因素去比较静态或动态类型的语言。^[7][4][12][5][15][6]
幸运的是现在我们可以基于大量的真实世界中的软件项目去研究这些问题。GitHub 包含了多种语言的大量的项目,并且在大小、年龄、和开发者数量上有很大的差别。每个项目的仓库都提供一个详细的记录,包含贡献历史、项目大小、作者身份、以及缺陷修复。然后,我们使用多种工具去研究语言特性对缺陷发生的影响。对我们的研究方法的最佳描述应该是“混合方法”,或者是三角测量法 [5][7];我们使用文本分析、聚簇、和可视化去证实和支持量化回归研究的结果。这个以经验为根据的方法,帮助我们去了解编程语言对软件质量的具体影响,因为,他们是被开发者非正式使用的。
[Back to Top][47]
幸运的是现在我们可以基于大量的真实世界中的软件项目去研究这些问题。GitHub 包含了多种语言的大量的项目,并且在大小、年龄、和开发者数量上有很大的差别。每个项目的仓库都提供一个详细的记录,包含贡献历史、项目大小、作者身份以及缺陷修复。然后,我们使用多种工具去研究语言特性对缺陷发生的影响。对我们的研究方法的最佳描述应该是“混合方法”,或者是三角测量法 ^[5][7];我们使用文本分析、聚簇和可视化去证实和支持量化回归研究的结果。这个以经验为根据的方法,帮助我们去了解编程语言对软件质量的具体影响,因为,他们是被开发者非正式使用的。
### 2 方法
我们的方法是软件工程中典型的大范围观察研究法。我们首先大量的使用自动化方法从几种数据源采集数据。然后使用预构建的统计分析模型对数据进行过滤和清洗。过滤器的选择是由一系列的因素共同驱动的这些因素包括我们研究的问题的本质、数据质量和认为最适合这项统计分析研究的数据。尤其是GitHub 包含了由大量的编程语言所写的非常多的项目。对于这项研究,我们花费大量的精力专注于收集那些用大多数的主流编程语言写的流行项目的数据。我们选择合适的方法来评估计数数据上的影响因素。
我们的方法是软件工程中典型的大范围观察研究法。我们首先大量的使用自动化方法从几种数据源采集数据。然后使用预构建的统计分析模型对数据进行过滤和清洗。过滤器的选择是由一系列的因素共同驱动的这些因素包括我们研究的问题的本质、数据质量和认为最适合这项统计分析研究的数据。尤其是GitHub 包含了由大量的编程语言所写的非常多的项目。对于这项研究,我们花费大量的精力专注于收集那些用大多数的主流编程语言写的流行项目的数据。我们选择合适的方法来评估计数数据上的影响因素。
![*](http://dl.acm.org/images/bullet.gif)
 **2.1 数据收集**
#### 2.1 数据收集
我们选择了 GitHub 上的排名前 19 的编程语言。剔除了 CSS、Shell script、和 Vim script,因为它们不是通用的编程语言。我们包含了 `Typescript`,它是 `JavaScript` 的超集。然后,对每个被研究的编程语言,我们检索出以它为主要编程语言的前 50 个项目。我们总共分析了 17 种不同的语言,共计 850 个项目。
我们选择了 GitHub 上的排名前 19 的编程语言。剔除了 CSS、Shell 脚本、和 Vim 脚本,因为它们不是通用的编程语言。我们包含了 `Typescript`,它是 `JavaScript` 的超集。然后,对每个被研究的编程语言,我们检索出以它为主要编程语言的前 50 个项目。我们总共分析了 17 种不同的语言,共计 850 个项目。
我们的编程语言和项目的数据是从 _GitHub Archive_ 中提取的,这是一个记录所有活跃的公共 GitHub 项目的数据库。它记录了 18 种不同的 GitHub 事件,包括新提交new commits、fork 事件、PR(pull request)、开发者信息、和以每小时为基础的所有开源 GitHub 项目的问题跟踪issue tracking。打包后的数据上传到 Google BigQuery 提供的交互式数据分析接口上。
我们的编程语言和项目的数据是从 _GitHub Archive_ 中提取的,这是一个记录所有活跃的公共 GitHub 项目的数据库。它记录了 18 种不同的 GitHub 事件,包括新提交、fork 事件、PR拉取请求、开发者信息和以每小时为基础的所有开源 GitHub 项目的问题跟踪。打包后的数据上传到 Google BigQuery 提供的交互式数据分析接口上。
**识别编程语言排名榜单** 我们基于它们的主要编程语言分类合计项目。然后,我们选择大多数的项目进行进一步分析,如 [表 1][48] 所示。一个项目可能使用多种编程语言将它确定成单一的编程语言是很困难的。Github 包保存的信息是从 GitHub Linguist 上采集的,它使用项目仓库中源文件的扩展名来确定项目的发布语言是什么。源文件中使用数量最多的编程语言被确定为这个项目的 _主要编程语言_
**识别编程语言排名榜单** 
我们基于它们的主要编程语言分类合计项目。然后,我们选择大多数的项目进行进一步分析,如 [表 1][48] 所示。一个项目可能使用多种编程语言将它确定成单一的编程语言是很困难的。Github Archive 保存的信息是从 GitHub Linguist 上采集的,它使用项目仓库中源文件的扩展名来确定项目的发布语言是什么。源文件中使用数量最多的编程语言被确定为这个项目的 _主要编程语言_
[![t1.jpg](http://deliveryimages.acm.org/10.1145/3130000/3126905/t1.jpg)][49]
**表 1 每个编程语言排名前三的项目**
*表 1 每个编程语言排名前三的项目*
**检索流行的项目** 对于每个选定的编程语言,我们先根据项目所使用的主要编程语言来选出项目,然后根据每个项目的相关 _星stars_ 的数量排出项目的流行度。 _星_ 的数量表示了在这个项目上有多少感兴趣的人在表达自己的意见,并且它是流行度的一个合适的代表指标。因此,在 C 语言中排名前三的项目是 _linux、git、php-src_ ;而对于 C++,它们则是 _node-webkit、phantomjs、mongo_ ;对于 `Java`,它们则是 _storm、elasticsearch、ActionBarSherlock_ 。每个编程语言,我们总共选了 50 个项目。
**检索流行的项目** 
为确保每个项目有足够长的开发历史,我们剔除了少于 28 个提交的项目28 是每个候选项目的第一个四分位值数)。这样我们还剩下 728 个项目。[表 1][50] 展示了每个编程语言的前三个项目。
对于每个选定的编程语言,我们先根据项目所使用的主要编程语言来选出项目,然后根据每个项目的相关 _星_ 的数量排出项目的流行度。 _星_ 的数量表示了有多少人主动表达对这个项目感兴趣,并且它是流行度的一个合适的代表指标。因此,在 C 语言中排名前三的项目是 _linux、git、php-src_ ;而对于 C++,它们则是 _node-webkit、phantomjs、mongo_ ;对于 `Java`,它们则是 _storm、elasticsearch、ActionBarSherlock_ 。每个编程语言,我们各选了 50 个项目。
**检索项目演进历史** 对于 728 个项目中的每一个项目,我们下载了它们的非合并提交、提交记录、作者数据、作者使用的 _git_ 名字。我们从每个文件的添加和删除的行数中计算代码改动和每个提交的修改文件数量。我们以每个提交中修改的文件的扩展名所代表的编程语言,来检索出所使用的编程语言(一个提交可能有多个编程语言标签)。对于每个提交,我们通过它的提交日期减去这个项目的第一个提交的日期,来计算它的 _commit age_ 。我们也计算其它的项目相关的统计数据,包括项目的最大 commit age 和开发者总数,用于我们的回归分析模型的控制变量,它在第三节中会讨论到。我们通过在提交记录中搜索与错误相关的关键字,比如,"error"、"bug"、"fix"、"issue"、"mistake"、"incorrect"、"fault"、"defect"、"flaw",来识别 bug 修复提交。这一点与以前的研究类似。[18][8]
为确保每个项目有足够长的开发历史,我们剔除了少于 28 个提交的项目28 是候选项目的第一个四分位值数)。这样我们还剩下 728 个项目。[表 1][50] 展示了每个编程语言的前三个项目。
[表 2][51] 汇总了我们的数据集。因为一个项目可能使用多个编程语言,表的第二列展示了使用某种编程语言的项目的总数量。我们进一步排除了该编程语言的项目中少于 20 个提交的那些编程语言。因为 20 是每个编程语言的每个项目的提交总数的第一个四分位值。例如,我们在 C 语言中共找到 220 项目的提交数量多于 20 个。这确保了每个“编程语言 项目”对有足够的活跃度。
**检索项目演进历史** 
对于 728 个项目中的每一个项目,我们下载了它们的非合并提交、提交记录、作者数据、作者使用 _git_ 的名字。我们从每个文件的添加和删除的行数中计算代码改动和每个提交的修改文件数量。我们以每个提交中修改的文件的扩展名所代表的编程语言,来检索出所使用的编程语言(一个提交可能有多个编程语言标签)。对于每个提交,我们通过它的提交日期减去这个项目的第一个提交的日期,来计算它的 _提交年龄_ 。我们也计算其它的项目相关的统计数据,包括项目的最大提交年龄和开发者总数,用于我们的回归分析模型的控制变量,它在第三节中会讨论到。我们通过在提交记录中搜索与错误相关的关键字,比如,`error`、`bug`、`fix`、`issue`、`mistake`、`incorrect`、`fault`、`defect`、`flaw`,来识别 bug 修复提交。这一点与以前的研究类似。^[18][8]
[表 2][51] 汇总了我们的数据集。因为一个项目可能使用多个编程语言,表的第二列展示了使用某种编程语言的项目的总数量。我们进一步排除了项目中该编程语言少于 20 个提交的那些编程语言。因为 20 是每个编程语言的每个项目的提交总数的第一个四分位值。例如,我们在 C 语言中共找到 220 项目的提交数量多于 20 个。这确保了每个“编程语言 项目”对有足够的活跃度。
[![t2.jpg](http://deliveryimages.acm.org/10.1145/3130000/3126905/t2.jpg)][52]
**表 2 研究主题**
*表 2 研究主题*
总而言之,我们研究了最近 18 年以来,用了 17 种编程语言开发的,总共 728 个项目。总共包括了 29,000 个不同的开发者157 万个提交,和 564,625 个 bug 修复提交。
![*](http://dl.acm.org/images/bullet.gif)
 **2.2 语言分类**
#### 2.2 语言分类
我们基于影响语言质量的几种编程语言特性定义了语言类别,[7][9][8][10][12][11],如 [表 3][53] 所示。 _编程范式_ 表示项目是否是以命令方式、脚本方式、或者函数语言所写的。在本文的下面部分,我们分别使用 _命令__脚本_ 这两个术语去代表命令方式和脚本方式。
我们基于影响语言质量的几种编程语言特性定义了语言类别,^[7][9][8][10][12][11] ,如 [表 3][53] 所示。 _编程范式_ 表示项目是以命令方式、脚本方式、还是函数语言所写的。在本文的下面部分,我们分别使用 _命令__脚本_ 这两个术语去代表命令方式和脚本方式。
[![t3.jpg](http://deliveryimages.acm.org/10.1145/3130000/3126905/t3.jpg)][54]
**表 3. 语言分类的不同类型**
*表 3. 语言分类的不同类型*
_类型检查_  代表静态或者动态类型。在静态类型语言中,在编译时进行类型检查,并且变量名是绑定到一个值和一个类型的。另外,(包含变量的)表达式是根据运行时,它们可能产生的值所符合的类型来分类的。在动态类型语言中,类型检查发生在运行时。因此,在动态类型语言中,它可能出现在同一个程序中,一个变量名可能会绑定到不同类型的对象上的情形。
@ -69,7 +72,7 @@
请注意,我们之所以使用这种方式对编程语言来分类和研究,是因为,这种方式在一个“真实的世界”中被大量的开发人员非正式使用。例如,`TypeScript` 被有意地分到静态编程语言的分类中,它不允许隐式类型转换。然而,在实践中,我们注意到,开发者经常(有 50% 可变化,并且跨 `TypeScript` - 在我们的数据集中使用的项目)使用 `any` 类型,一个笼统的联合类型,并且,因此在实践中,`TypeScript` 允许动态地、隐式类型转换。为减少混淆,我们从我们的编程语言分类和相关的模型中排除了 `TypeScript`(查看 [表 3][55] 和 [7][56])。
![*](http://dl.acm.org/images/bullet.gif)
 **2.3 识别项目领域**
我们基于编程语言的特性和功能,使用一个自动和手动的混合技术,将研究的项目分类到不同的领域。在 GitHub 上,项目使用 `project descriptions` 和 README 文件来描述它们的特性。我们使用文档主题生成模型Latent Dirichlet Allocation缩写为LDA[3][17] 去分析这些文本。提供一组文档给它LDA 将生成不同的关键字然后来识别可能的主题。对于每个文档LDA 也估算每个主题分配的文档的概率。
@ -79,7 +82,7 @@
[![t4.jpg](http://deliveryimages.acm.org/10.1145/3130000/3126905/t4.jpg)][58]
**表 4 领域特征**
![*](http://dl.acm.org/images/bullet.gif)
 **2.4 bugs 分类**
尽管修复软件 bugs 时,开发者经常会在提交日志中留下关于这个 bugs 的原始的重要信息;例如,为什么会产生 bugs以及怎么去修复 bugs。我们利用很多信息去分类 bugs与 Tan _et al_ 类似 [13][18][24][19]。
@ -97,7 +100,7 @@
我们的 bug 分类的结果展示在 [表 5][62] 中。大多数缺陷的原因都与普通编程错误相关。这个结果并不意外,因为,在这个分类中涉及了大量的编程错误,比如,类型错误、输入错误、编写错误、等等。我们的技术并不能将在任何(原因或影响)分类中占比为 1.4% 的 bug 修复信息再次进行分类;我们将它归类为 Unknown。
![*](http://dl.acm.org/images/bullet.gif)
 **2.5 统计方法**
我们使用回归模型对软件项目相关的其它因素中的有缺陷的提交数量进行了建模。所有的模型使用 _负二项回归译者注negative binomial regression缩写为NBR一种回归分析模型)_ 去对项目属性计数进行建模比如提交数量。NBR 是一个广义的线性模型,用于对非负整数进行响应建模。[4][20]