游戏人物模型叫什么建好以后,是如何用编程语言控制的?也就是说模型如何与编程交互。

R语言编程学习之函数与模型:VAR与SVAR囷爬虫(图)
SVAR模型与VAR模型在模型设定形式上的区别是VAR模型只包含变量的滞后项,而SVAR模型还包含了变量的当期项SVAR模型还可以避免联立方程模型可能产生的偏倚问题。因此我们今天给出SVAR在R软件中的使用说明需要特别说明的是,今天我们并非给出一个新的函数以简化SVAR参数设萣因为我们所使用的vars包中VAR()函数和SVAR函数的参数设定已经十分简洁了。

}

编程语言对软件质量的影响是什麼这个问题在很长一段时间内成为一个引起了大量辩论的主题。在这项研究中我们从 GitHub 上收集了大量的数据(728 个项目,6300 万行源代码29000 位莋者,150 万个提交17 种编程语言),尝试在这个问题上提供一些实证这个还算比较大的样本数量允许我们去使用一个混合的方法,结合多種可视化的回归模型和文本分析去研究语言特性的影响,比如在软件质量上,静态与动态类型和允许混淆与不允许混淆的类型通过從不同的方法作三角测量研究(LCTT 译注:一种测量研究的方法),并且去控制引起混淆的因素比如,团队大小、项目大小和项目历史我們的报告显示,语言设计确实(对很多方面)有很大的影响但是,在软件质量方面语言的影响是非常有限的。最明显的似乎是不允許混淆的类型比允许混淆的类型要稍微好一些,并且在函数式语言中,静态类型也比动态类型好一些值得注意的是,这些由语言设计所引起的轻微影响绝大多数是由过程因素所主导的,比如项目大小、团队大小和提交数量。但是我们需要提示读者,即便是这些不起眼的轻微影响也是由其它的无形的过程因素所造成的,例如对某些函数类型、以及不允许类型混淆的静态语言的偏爱。

在给定的编程语言是否是“适合这个工作的正确工具”的讨论期间紧接着又发生了多种辩论。虽然一些辩论出现了带有宗教般狂热的色彩但是大蔀分人都一致认为,编程语言的选择能够对编码过程和由此生成的结果都有影响

主张强静态类型的人,倾向于认为静态方法能够在早期捕获到缺陷;他们认为一点点的预防胜过大量的矫正。动态类型拥护者主张保守的静态类型检查无论怎样都是非常浪费开发者资源的,并且最好是依赖强动态类型检查来捕获错误类型。然而这些辩论,大多数都是“纸上谈兵”只靠“传说中”的证据去支持。

这些“传说”也许并不是没有道理的;考虑到影响软件工程结果的大量其它因素获取这种经验性的证据支持是一项极具挑战性的任务,比如代码质量、语言特征,以及应用领域比如软件质量,考虑到它有大量的众所周知的影响因素比如,代码数量

受控实验是检验语言選择在面对如此令人气馁的混淆影响时的一种方法,然而由于成本的原因,这种研究通常会引入一种它们自己的混淆也就是说,限制叻范围在这种研究中,完整的任务是必须要受限制的并且不能去模拟 真实的世界 中的开发。这里有几个最近的这种大学本科生使用的研究或者,通过一个实验因素去比较静态或动态类型的语言

幸运的是,现在我们可以基于大量的真实世界中的软件项目去研究这些问题GitHub 包含了多种语言的大量的项目,并且在大小、年龄、和开发者数量上有很大的差别每个项目的仓库都提供一个详细的记录,包含贡献历史、项目大小、作者身份以及缺陷修复然后,我们使用多种工具去研究语言特性对缺陷发生的影响对我们的研究方法的最佳描述应该是“混合方法”,或者是三角测量法; 我们使用文本分析、聚簇和可视化去证实和支持量化回归研究的结果这个以经验为根据嘚方法,帮助我们去了解编程语言对软件质量的具体影响因为,他们是被开发者非正式使用的

我们的方法是软件工程中典型的大范围觀察研究法。我们首先大量的使用自动化方法从几种数据源采集数据。然后使用预构建的统计分析模型对数据进行过滤和清洗过滤器嘚选择是由一系列的因素共同驱动的,这些因素包括我们研究的问题的本质、数据质量和认为最适合这项统计分析研究的数据尤其是,GitHub 包含了由大量的编程语言所写的非常多的项目对于这项研究,我们花费大量的精力专注于收集那些用大多数的主流编程语言写的流行项目的数据我们选择合适的方法来评估计数数据上的影响因素。

我们选择了 GitHub 上的排名前 19 的编程语言剔除了 CSS、Shell 脚本、和 Vim 脚本,因为它们不昰通用的编程语言我们包含了 Typescript,它是 JavaScript 的超集然后,对每个被研究的编程语言我们检索出以它为主要编程语言的前 50 个项目。我们总共汾析了 17 种不同的语言共计 850 个项目。

我们的编程语言和项目的数据是从 GitHub Archive 中提取的这是一个记录所有活跃的公共 GitHub 项目的数据库。它记录了 18 種不同的 GitHub 事件包括新提交、fork 事件、PR(拉取请求)、开发者信息和以每小时为基础的所有开源 GitHub 项目的问题跟踪。打包后的数据上传到 Google BigQuery 提供嘚交互式数据分析接口上

识别编程语言排名榜单 

我们基于它们的主要编程语言分类合计项目。然后我们选择大多数的项目进行进一步汾析,如  所示一个项目可能使用多种编程语言;将它确定成单一的编程语言是很困难的。Github Archive 保存的信息是从 GitHub Linguist 上采集的它使用项目仓库中源文件的扩展名来确定项目的发布语言是什么。源文件中使用数量最多的编程语言被确定为这个项目的

表 1 每个编程语言排名前三的项目

检索流行的项目 

对于每个选定的编程语言我们先根据项目所使用的主要编程语言来选出项目,然后根据每个项目的相关 的数量排出项目嘚流行度 的数量表示了有多少人主动表达对这个项目感兴趣,并且它是流行度的一个合适的代表指标因此,在 C 语言中排名前三的项目是 linux、git、php-src;而对于 C++它们则是

为确保每个项目有足够长的开发历史,我们剔除了少于 28 个提交的项目(28 是候选项目的第一个四分位值数)這样我们还剩下 728 个项目。 展示了每个编程语言的前三个项目

检索项目演进历史 

对于 728 个项目中的每一个项目,我们下载了它们的非合并提茭、提交记录、作者数据、作者使用 git 的名字我们从每个文件的添加和删除的行数中计算代码改动和每个提交的修改文件数量。我们以每個提交中修改的文件的扩展名所代表的编程语言来检索出所使用的编程语言(一个提交可能有多个编程语言标签)。对于每个提交我們通过它的提交日期减去这个项目的第一个提交的日期,来计算它的 我们也计算其它的项目相关的统计数据,包括项目的最大提交年龄囷开发者总数用于我们的回归分析模型的控制变量,它在第三节中会讨论到我们通过在提交记录中搜索与错误相关的关键字,比如errorbugfixissuemistakeincorrectfaultdefectflaw,来识别 bug 修复提交这一点与以前的研究类似。

 汇总了我们的数据集因为一个项目可能使用多个编程语言,表的第二列展示了使用某种编程语言的项目的总数量我们进一步排除了项目中该编程语言少于 20 个提交的那些编程语言。因为 20 是每个编程语言的每個项目的提交总数的第一个四分位值例如,我们在 C 语言中共找到 220 项目的提交数量多于 20 个这确保了每个“编程语言 – 项目”对有足够的活跃度。

总而言之我们研究了最近 18 年以来,用了 17 种编程语言开发的总共 728 个项目。总共包括了 29,000 个不同的开发者157 万个提交,和 564,625 个 bug 修复提茭

我们基于影响语言质量的几种编程语言特性定义了语言类别,

编程范式Programming Paradigm 表示项目是以命令方式、脚本方式、还是函数语言所写的在本文的下面部分,我们分别使用 命令procedural脚本scripting 这两个术语去代表命令方式和脚本方式

表 3. 语言分类的不同类型

 代表静态或者动态类型。茬静态类型语言中在编译时进行类型检查,并且变量名是绑定到一个值和一个类型的另外,(包含变量的)表达式是根据运行时它們可能产生的值所符合的类型来分类的。在动态类型语言中类型检查发生在运行时。因此在动态类型语言中,它可能出现在同一个程序中一个变量名可能会绑定到不同类型的对象上的情形。

隐式类型转换Implicit Type Conversion 允许一个类型为 T1 的操作数作为另一个不同的类型 T2 来访问,而无需进行显式的类型转换这样的隐式类型转换在一些情况下可能会带来类型混淆,尤其是当它表示一个明确的 T1 类型的操作数时把它再作為另一个不同的 T2 类型的情况下。因为并不是所有的隐式类型转换都会立即出现问题,通过我们识别出的允许进行隐式类型转换的所有编程语言中可能发生隐式类型转换混淆的例子来展示我们的定义。例如在像 Perl、 JavaScript、CoffeeScript 这样的编程语言中,一个字符和一个数字相加是允许的(比如"5" + 2 结果是 "52")。但是在 Php 中相同的操作,结果是 7像这种操作在一些编程语言中是不允许的,比如 Java 和 Python因为,它们不允许隐式转换茬强数据类型的 C 和 C++ 中,这种操作的结果是不可预料的例如,int x; float y; y=3.5; x=y;是合法的 C 代码并且对于 xy 其结果是不同的值,具体是哪一个值取决于含义,这可能在后面会产生问题 在 Objective-C 中,数据类型 id 是一个通用对象指针它可以被用于任何数据类型的对象,而不管分类是什么 像这种通用数据类型提供了很好的灵活性,它可能导致隐式的类型转换并且也会出现不可预料的结果。 因此我们根据它的编译器是否 允许  或鍺  不允许  如上所述的隐式类型转换,对编程语言进行分类;而不允许隐式类型转换的编程语言会显式检测类型混淆,并报告类型不匹配嘚错误

不允许隐式类型转换的编程语言,使用一个类型判断算法比如,Hindley 或者在运行时上使用一个动态类型检查器,可以在一个编译器(比如使用 Java)中判断静态类型的结果。相比之下一个类型混淆可能会悄无声息地发生,因为它可能因为没有检测到,也可能是没囿报告出来无论是哪种方式,允许隐式类型转换在提供了灵活性的同时最终也可能会出现很难确定原因的错误。为了简单起见我们將用 隐含implicit 代表允许隐式类型转换的编程语言,而不允许隐式类型转换的语言我们用 明确explicit 代表。

内存分类Memory Class  表示是否要求开发者去管理内存尽管 Objective-C 遵循了一个混合模式,我们仍将它放在非管理的分类中来对待因为,我们在它的代码库中观察到很多的内存错误在第 3 节的 RQ4 中会討论到。

请注意我们之所以使用这种方式对编程语言来分类和研究,是因为这种方式在一个“真实的世界”中被大量的开发人员非正式使用。例如TypeScript 被有意地分到静态编程语言的分类中,它不允许隐式类型转换然而,在实践中我们注意到,开发者经常(有 50% 的变量並且跨 TypeScript —— 在我们的数据集中使用的项目)使用 any 类型,这是一个笼统的联合类型并且,因此在实践中TypeScript 允许动态地、隐式类型转换。为減少混淆我们从我们的编程语言分类和相关的模型中排除了 TypeScript(查看  和 )。

我们基于编程语言的特性和功能使用一个自动加手动的混合技术,将研究的项目分类到不同的领域在 GitHub 上,项目使用 project descriptions 和 README 文件来描述它们的特性我们使用一种文档主题生成模型(Latent Dirichlet Allocation,缩写为:LDA) 去分析这些文本提供一组文档给它,LDA 将生成不同的关键字然后来识别可能的主题。对于每个文档LDA 也估算每个主题分配的文档的概率。

我們检测到 30 个不同的领域(换句话说就是主题),并且评估了每个项目从属于每个领域的概率因为,这些自动检测的领域包含了几个具體项目的关键字例如,facebook很难去界定它的底层的常用功能。为了给每个领域分配一个有意义的名字我们手动检查了 30 个与项目名字无关嘚用于识别领域的领域识别关键字。我们手动重命名了所有的 30 个自动检测的领域并且找出了以下六个领域的大多数的项目:应用程序、數据库、代码分析、中间件、库,和框架我们也找出了不符合以上任何一个领域的一些项目,因此我们把这个领域笼统地标记为 其它 。随后我们研究组的另一名成员检查和确认了这种项目领域分类的方式。 汇总了这个过程识别到的领域结果

尽管修复软件 bug 时,开发者經常会在提交日志中留下关于这个 bug 的原始的重要信息;例如为什么会产生 bug,以及怎么去修复 bug我们利用很多信息去分类 bug,与 Tan 的 et al 类似

艏先我们基于 bug 的 原因Cause影响Impact 进行分类。_ 原因 _ 进一步分解为不相关的错误子类:算法方面的、并发方面的、内存方面的、普通编程错误囷未知的。bug 的 影响  也分成四个不相关的子类:安全、性能、失败、和其它的未知类因此,每个 bug 修复提交也包含原因和影响的类型 展示叻描述的每个 bug 分类。这个类别分别在两个阶段中被执行:

表 5 bug 分类和在整个数据集中的描述

(1) 关键字搜索 我们随机选择了 10% 的 bug 修复信息并且使鼡一个基于关键字的搜索技术去对它们进行自动化分类,作为可能的 bug 类型我们对这两种类型(原因和影响)分别使用这个注释。我们选擇了一个限定的关键字和习惯用语集如 所展示的。像这种限定的关键字和习惯用语集可以帮我们降低误报

(2) 监督分类 我们使用前面步骤Φ的有注释的 bug 修复日志作为训练数据,为监督学习分类技术通过测试数据来矫正,去对剩余的 bug 修复信息进行分类我们首先转换每个 bug 修複信息为一个词袋(LCTT 译注:bag-of-words,一种信息检索模型)然后,删除在所有的 bug 修复信息中仅出现过一次的词这样减少了具体项目的关键字。峩们也使用标准的自然语言处理技术来解决这个问题最终,我们使用支持向量机(LCTT 译注:Support Vector Machine缩写为 SVM,在机器学习领域中一种有监督的學习算法)去对测试数据进行分类。

为精确评估 bug 分类器我们手动注释了 180 个随机选择的 bug 修复,平均分布在所有的分类中然后,我们比较掱动注释的数据集在自动分类器中的结果最终处理后的,表现出的精确度是可接受的性能方面的精确度最低,是 70%并发错误方面的精確度最高,是 100%平均是 84%。再次运行精确度从低到高是 69% 到 91%,平均精确度还是 84%

中。大多数缺陷的原因都与普通编程错误相关这个结果并鈈意外,因为在这个分类中涉及了大量的编程错误,比如类型错误、输入错误、编写错误、等等。我们的技术并不能将在任何(原因戓影响)分类中占比为 1.4% 的 bug 修复信息再次进行分类;我们将它归类为未知

我们使用回归模型对软件项目相关的其它因素中的有缺陷的提交數量进行了建模。所有的模型使用负二项回归negative binomial regression(缩写为 NBR)(LCTT 译注:一种回归分析模型) 去对项目属性计数进行建模比如,提交数量NBR 是┅个广义的线性模型,用于对非负整数进行响应建模

在我们的模型中,我们对每个项目的编程语言控制几个可能影响最终结果的因素。因此在我们的回归分析中,每个(语言/项目)对是一个行并且可以视为来自流行的开源项目中的样本。我们依据变量计数进行对象轉换以使变量保持稳定,并且提升了模型的适用度 我们通过使用 AIC 和 Vuong 对非嵌套模型的测试比较来验证它们。

去检查那些过度的多重共线性(LCTT 译注:多重共线性是指在线性回归模型中解释变量之间由于存在精确相关关系或高度相关关系而使模型估计失真或难以估计准确。)并不是一个问题我们在所有的模型中使用一个保守的最大值 5,去计算每个依赖的变量的膨胀因子的方差 我们通过对每个模型的残差囷杠杆图进行视觉检查来移除高杠杆点,找出库克距离(LCTT 译注:一个统计学术语用于诊断回归分析中是否存在异常数据)的分离值和最夶值。

我们利用 效果 或者 差异 ,编码到我们的研究中以提高编程语言回归系数的表现。 加权的效果代码允许我们将每种编程语言与所囿编程语言的效果进行比较同时弥补了跨项目使用编程语言的不均匀性。 去测试两种变量因素之间的联系我们使用一个独立的卡方检驗(LCTT 译注:Chi-square,一种统计学上的假设检验方法)测试 在证实一个依赖之后,我们使用

我们从简单明了的问题开始它非常直接地解决了人們坚信的一些核心问题,即:

问题 1:一些编程语言相比其它语言来说更易于出现缺陷吗

我们使用了回归分析模型,去比较每个编程语言對所有编程语言缺陷数量平均值的影响以及对缺陷修复提交的影响(查看 )。

表 6. 一些语言的缺陷要少于其它语言

我们包括了一些变量莋为对明确影响反应的控制因子。项目年龄age也包括在内因为,越老的项目生成的缺陷修复数量越大提交commits数量也会对项目反应有轻微的影响。另外从事该项目的开发人员dev的数量和项目的原始大小size,都会随着项目的活跃而增长

上述模型中估算系数的大小和符号(LCTT 译注:指 “+”或者“-”)与结果的预测因子有关。初始的四种变量是控制变量并且,我们对这些变量对最终结果的影响不感兴趣只是说它们嘟是积极的和有意义的。语言变量是指示变量是每个项目的变化因子,该因子将每种编程语言与所有项目的编程语言的加权平均值进行仳较编程语言系数可以大体上分为三类。第一类是那些在统计学上无关紧要的系数,并且在建模过程中这些系数不能从 0 中区分出来這些编程语言的表现与平均值相似,或者它们也可能有更大的方差剩余的系数是非常明显的,要么是正的要么是负的。对于那些正的系数我们猜测可能与这个编程语言有大量的缺陷修复相关。这些语言包括 C、C++、Objective-C、Php以及 Python。所有的有一个负的系数的编程语言比如

应该紸意的是,虽然从统计学的角度观察到编程语言与缺陷之间有明显的联系,但是大家不要过高估计编程语言对于缺陷的影响,因为這种影响效应是非常小的。异常分析的结果显示这种影响小于总异常的 1%。

我们可以这样去理解模型的系数它代表一个预测因子在所有其它预测因子保持不变的情况下,这个预测因子一个单位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 我们在这里包含了完整有值; 但是,通过 Cramer 的 V 测试的值是 0.191是低相关度的,表明任何编程语言和领域之间的相关度是非常小的并且,在回归模型中包含领域并不会产生有意义的结果

去解决这种情况的一个选擇是,去移除编程语言或者混合领域,但是我们现有的数据没有进行完全挑选。或者我们混合编程语言;这个选择导致一个相关但畧有不同的问题。

问题 2: 哪些编程语言特性与缺陷相关

我们按编程语言类别聚合它们,而不是考虑单独的编程语言正如在第 2.2 节所描述嘚那样,然后去分析与缺陷的关系总体上说,这些属性中的每一个都将编程语言按照在上下文中经常讨论的错误、用户辩论驱动、或者按以前工作主题来划分的因此,单独的属性是高度相关的我们创建了六个模型因子,将所有的单独因子综合到我们的研究中然后,峩们对六个不同的因子对缺陷数量的影响进行建模同时控制我们在 问题 1 节中使用的模型中的相同的基本协变量(LCTT 译注:协变量是指在实驗中不能被人为操纵的独立变量)。

关于使用的编程语言(在前面的 中)我们使用跨所有语言类的平均反应来比较编程语言 。这个模型在 中表达了出来很明显,Script-Dynamic-Explicit-Managed 类有最小的量级系数这个系数是微不足道的,换句话说对这个系数的 Z 校验z-test(LCTT 译注:统计学上的一种平均徝差异校验的方法) 并不能把它从 0 中区分出来。鉴于标准错误的量级我们可以假设,在这个类别中的编程语言的行为是非常接近于所有編程语言行为的平均值我们可以通过使用 Proc-Static-Implicit-Unmanaged 作为基本级并用于处理,或者使用基本级来虚假编码比较每个语言类来证明这一点。在这种凊况下Script-Dynamic-Explicit-Managed 是明显不同于 p  = 0.00044 的。注意虽然我们在这是选择了不同的编码方法,影响了系数和 Z 值这个方法和所有其它的方面都是一样的。当峩们改变了编码我们调整系数去反应我们希望生成的对比。 将其它类的编程语言与总体平均数进行比较Proc-Static-Implicit-Unmanaged 类编程语言更容易引起缺陷。這意味着与其它过程类编程语言相比隐式类型转换或者管理内存会导致更多的缺陷倾向。

表 7. 函数式语言与缺陷的关联度和其它类语言相仳要低而过程类语言则大于或接近于平均值。

在脚本类编程语言中我们观察到类似于允许与不允许隐式类型转换的编程语言之间的关系,它们提供的一些证据表明隐式类型转换(与显式类型转换相比)才是导致这种差异的原因,而不是内存管理鉴于各种因素之间的楿关性,我们并不能得出这个结论但是,当它们与平均值进行比较时作为一个组,那些不允许隐式类型转换的编程语言出现错误的倾姠更低一些而那些出现错误倾向更高的编程语言,出现错误的机率则相对更高在函数式编程语言中静态和动态类型之间的差异也很明顯。

函数式语言作为一个组展示了与平均值的很明显的差异静态类型语言的系数要小很多,但是函数式语言类都有同样的标准错误函數式静态编程语言出现错误的倾向要小于函数式动态编程语言,这是一个强有力的证据尽管如此,Z 校验仅仅是检验系数是否能从 0

与编程語言和缺陷一样编程语言类与缺陷之间关系的影响是非常小的。解释类编程语言的这种差异也是相似的虽然很小,解释类编程语言的這种差异小于 1%

我们现在重新回到应用领域这个问题。应用领域是否与语言类相互影响怎么选择?例如一个函数化编程语言,对特定嘚领域有一定的优势与上面一样,对于这些因素和项目领域之间的关系做一个卡方检验它的值是 99.05, df  = 30 p  = 2.622e–09,我们拒绝无意义假设Cramer 的 V 产苼的值是 0.133,表示一个弱关联因此,虽然领域和编程语言之间有一些关联但在这里应用领域和编程语言类之间仅仅是一个非常弱的关联。

结论 2:在编程语言类与缺陷之间有一个很小但是很明显的关系函数式语言与过程式或者脚本式语言相比,缺陷要少

这个结论有些不呔令人满意的地方,因为我们并没有一个强有力的证据去证明,在一个项目中编程语言或者语言类和应用领域之间的关联性一个替代方法是,基于全部的编程语言和应用领域忽略项目和缺陷总数,而去查看相同的数据因为,这样不再产生不相关的样本我们没有从統计学的角度去尝试分析它,而是使用一个描述式的、基于可视化的方法

我们定义了 缺陷倾向Defect Proneness 作为 bug 修复提交与每语言每领域总提交的比率。 使用了一个热力图展示了应用领域与编程语言之间的相互作用从亮到暗表示缺陷倾向在增加。我们研究了哪些编程语言因素影响了跨多种语言写的项目的缺陷修复提交它引出了下面的研究问题:

图 1. 编程语言的缺陷倾向与应用领域之间的相互作用。对于一个给定的领域(列底部)热力图中的每个格子表示了一个编程语言的缺陷倾向(行头部)。“整体”列表示一个编程语言基于所有领域的缺陷倾向用白色十字线标记的格子代表一个 null 值,换句话说就是在那个格子里没有符合的提交。

问题 3: 编程语言的错误倾向是否取决于应用领域

为了回答这个问题,我们首先在我们的回归模型中以高杠杆点过滤掉认为是异常的项目,这种方法在这里是必要的尽管这是一个非統计学的方法,一些关系可能影响可视化例如,我们找到一个简单的项目Google 的 v8,一个 JavaScript 项目负责中间件中的所有错误。这对我们来说是┅个惊喜因为 JavaScript 通常不用于中间件。这个模式一直在其它应用领域中不停地重复着因此,我们过滤出的项目的缺陷度都低于 10% 和高于 90%这個结果在 中。

我们看到在这个热力图中仅有一个很小的差异正如在问题 1 节中看到的那样,这个结果仅表示编程语言固有的错误倾向为驗证这个推论,我们测量了编程语言对每个应用领域和对全部应用领域的缺陷倾向对于除了数据库以外的全部领域,关联性都是正向的并且 p 值是有意义的(<0.01)。因此关于缺陷倾向,在每个领域的语言排序与全部领域的语言排序是基本相同的

结论 3: 应用领域和编程语訁缺陷倾向之间总体上没有联系。

我们证明了不同的语言产生了大量的缺陷并且,这个关系不仅与特定的语言相关也适用于一般的语訁类;然而,我们发现项目类型并不能在一定程度上协调这种关系。现在我们转变我们的注意力到反应分类上,我想去了解编程语訁与特定种类的缺陷之间有什么联系,以及这种关系怎么与我们观察到的更普通的关系去比较我们将缺陷分为不同的类别,如  所描述的那样然后提出以下的问题:

问题 4:编程语言与 bug 分类之间有什么关系?

我们使用了一个类似于问题 3 中所用的方法去了解编程语言与 bug 分类の间的关系。首先我们研究了 bug 分类和编程语言类之间的关系。一个热力图()展示了在编程语言类和 bug 类型之上的总缺陷数去理解 bug 分类囷语言之间的相互作用,我们对每个类别使用一个 NBR 回归模型对于每个模型,我们使用了与问题 1 中相同的控制因素以及使用加权效应编碼后的语言,去预测缺陷修复提交

图 2. bug 类别与编程语言类之间的关系。每个格子表示每语言类(行头部)每 bug 类别(列底部)的 bug 修复提交占铨部 bug 修复提交的百分比这个值是按列规范化的。

结果和编程语言的方差分析值展示在  中每个模型的整体异常是非常小的,并且对于特萣的缺陷类型通过语言所展示的比例在大多数类别中的量级是类似的。我们解释这种关系为编程语言对于特定的 bug 类别的影响要大于总體的影响。尽管我们结论概括了全部的类别但是,在接下来的一节中我们对 中反应出来的 bug 数较多的 bug 类别做进一步研究。

表 8. 虽然编程语訁对缺陷的影响因缺陷类别而不同但是,编程语言对特定的类别的影响要大于一般的类别

编程错误 普通的编程错误占所有 bug 修复提交的 88.53% 咗右,并且在所有的编程语言类中都有因此,回归分析给出了一个与问题 1 中类似的结论(查看 )所有的编程语言都会导致这种编程错誤,比如处理错误、定义错误、输入错误、等等。

也证明了这一点例如,C、C++、和 Objective-C 引发了很多的内存错误在管理内存的语言中 Java 引发了哽多的内存错误,尽管它少于非管理内存的编程语言虽然 Java 自己做内存回收,但是它出现内存泄露一点也不奇怪,因为对象引用经常阻圵内存回收 在我们的数据中,Java 的所有内存错误中28.89% 是内存泄漏造成的。就数量而言编程语言中内存缺陷相比其它类别的 原因 造成的影響要大很多。

属于 Static-Strong-Managed 语言类的编程语言都被证实处于热力图中的暗区中普通的静态语言相比其它语言产生更多的并发错误。在动态语言中仅仅有 Erlang 有更多的并发错误倾向,或许与使用这种语言开发的并发应用程序非常多有关系同样地,在  中的负的系数表明用诸如 Ruby 和 `Php 这样嘚动态编程语言写的项目,并发错误要少一些请注意,某些语言如 JavaScript、CoffeeScript 和 TypeScript 是不支持并发的,在传统的惯例中虽然 Php 具有有限的并发支持(取决于它的实现)。这些语言在我们的数据中引入了虚假的 0因此,在 中这些语言的并发模型的系数不能像其它的语言那样去解释。洇为存在这些虚假的 0所以在这个模型中所有语言的平均数非常小,它可能影响系数的大小因此,她们给 w.r.t. 一个平均数但是,这并不影響他们之间的相对关系因为我们只关注它们的相对关系。

基于 bug 修复消息中高频词的文本分析表明大多数的并发错误发生在一个条件争鼡、死锁、或者不正确的同步上,正如上面表中所示遍历所有语言,条件争用是并发错误出现最多的原因例如,在 Go 中占 92%在 Go 中条件争鼡错误的改进,或许是因为使用了一个争用检测工具帮助开发者去定位争用同步错误主要与消息传递接口(MPI)或者共享内存操作(SHM)相關。Erlang 和 Go 对线程间通讯使用 MPI 这就是为什么这两种语言没有发生任何 SHM 相关的错误的原因,比如共享锁、互斥锁等等相比之下,为线程间通訊使用早期的 SHM 技术的语言写的项目就可能存在锁相关的错误。

安全和其它冲突错误 在所有的 bug 修复提交中与冲突Impact错误相关的提交占了 7.33% 左祐。其中Erlang、C++、Python 与安全相关的错误要高于平均值()。Clojure 项目相关的安全错误较少()从热力图上我们也可以看出来,静态语言一般更易於发生失败和性能错误紧随其后的是 Functional-Dynamic-Explicit-Managed 语言,比如 Erlang对异常结果的分析表明,编程语言与冲突失败密切相关虽然安全错误在这个类别中昰弱相关的,与残差相比解释类语言的差异仍然比较大。

结论 4: 缺陷类型与编程语言强相关;一些缺陷类型比如内存错误和并发错误也取决于早期的语言(所使用的技术)对于特定类别,编程语言所引起的错误比整体更多

在编程语言比较之前做的工作分为以下三类:

對于一个给定的任务,开发者使用不同的语言进行编程时受到监视研究然后比较结果,比如开发成果和代码质量。Hanenberg 通过开发一个解析程序对 48 位程序员监视了 27 小时,去比较了静态与动态类型他发现这两者在代码质量方面没有显著的差异,但是基于动态类型的语言花費了更短的开发时间。他们的研究是在一个实验室中使用本科学生,设置了定制的语言和 IDE 来进行的我们的研究正好相反,是一个实际嘚流行软件应用的研究虽然我们只能够通过使用回归模型间接(和 事后 )控制混杂因素,我们的优势是样本数量大并且更真实、使用哽广泛的软件。我们发现在相同的条件下静态化类型的语言比动态化类型的语言更少出现错误倾向,并且不允许隐式类型转换的语言要恏于允许隐式类型转换的语言其对结果的影响是非常小的。这是合理的因为样本量非常大,所以这种非常小的影响在这个研究中可以看得到

比较了 C++ 与 SML,一个是过程化编程语言一个是函数化编程语言,在总的错误数量上没有找到显著的差异不过 SML 相比 C++ 有更高的缺陷密集度。SML 在我们的数据中并没有体现出来不过,认为函数式编程语言相比过程化编程语言更少出现缺陷另一个重点工作是比较跨不同语訁的开发工作。 不过,他们并不分析编程语言的缺陷倾向

调查了开发者对编程语言的观点,去研究为什么一些编程语言比其它的语言哽流行他们的报告指出,非编程语言的因素影响非常大:先前的编程语言技能、可用的开源工具、以及现有的老式系统我们的研究也證明,可利用的外部工具也影响软件质量;例如在 Go 中的并发 bug(请查看问题 4 节内容)。

研究了用 C 和 C++ 开发的四个项目并且发现在 C++ 中开发的組件一般比在 C 中开发的组件更可靠。我们发现 C 和 C++ 的错误倾向要高于全部编程语言的平均值但是,对于某些 bug 类型像并发错误,C 的缺陷倾姠要高于 C++(请查看第 3 节中的问题 4)

我们认为,我们的报告的结论几乎没有风险首先,在识别 bug 修复提交方面我们依赖的关键字是开发鍺经常用于表示 bug 修复的关键字。我们的选择是经过认真考虑的在一个持续的开发过程中,我们去捕获那些开发者一直面对的问题而不昰他们报告的 bug。不过这种选择存在过高估计的风险。我们对领域分类是为了去解释缺陷的倾向而且,我们研究组中另外的成员验证过汾类此外,我们花费精力去对 bug 修复提交进行分类也可能有被最初选择的关键字所污染的风险。每个项目在提交日志的描述上也不相同为了缓解这些风险,我们像 2.4 节中描述的那样利用手工注释评估了我们的类别。

我们判断文件所属的编程语言是基于文件的扩展名如果使用不同的编程语言写的文件使用了我们研究的通用的编程语言文件的扩展名,这种情况下也容易出现错误倾向为减少这种错误,我們使用一个随机样本文件集手工验证了我们的语言分类

根据我们的数据集所显示的情形,2.2 节中的解释类编程语言我们依据编程语言属性的主要用途作了一些假设。例如我们将 Objective-C 分到非管理内存类型中,而不是混合类型同样,我们将 Scala 注释为函数式编程语言将 C# 作为过程囮的编程语言,虽然它们在设计的选择上两者都支持。 在这项研究工作中,我们没有从过程化编程语言中分离出面向对象的编程语言(OOP)因为,它们没有清晰的区别主要差异在于编程类型。我们将 C++ 分到允许隐式类型转换的类别中是因为某些类型的内存区域可以通過使用指针操作被进行不同的处理, 并且我们注意到大多数 C++ 编译器可以在编译时检测类型错误

最后,我们将缺陷修复提交关联到编程语訁属性上它们可以反应出报告的风格或者其它开发者的属性。可用的外部工具或者library也可以影响一个相关的编程语言的 bug 数量

我们对编程语言和使用进行了大规模的研究,因为它涉及到软件质量我们使用的 Github 上的数据,具有很高的复杂性和多个维度上的差异的特性我们嘚样本数量允许我们对编程语言效果以及在控制一些混杂因素的情况下,对编程语言、应用领域和缺陷类型之间的相互作用进行一个混匼方法的研究。研究数据显示函数式语言是好于过程化语言的;不允许隐式类型转换的语言是好于允许隐式类型转换的语言的;静态类型的语言是好于动态类型的语言的;管理内存的语言是好于非管理的语言的。进一步讲编程语言的缺陷倾向与软件应用领域并没有关联。另外每个编程语言更多是与特定的 bug 类别有关联,而不是与全部 bug

另一方面,即便是很大规模的数据集它们被多种方法同时进行分割後,也变得很小且不全面因此,随着依赖的变量越来越多很难去回答某个变量所产生的影响有多大这种问题,尤其是在变量之间相互莋用的情况下因此,我们无法去量化编程语言在使用中的特定的效果其它的方法,比如调查可能对此有帮助。我们将在以后的工作Φ来解决这些挑战

这个材料是在美国国家科学基金会(NSF)以及美国空军科学研究办公室(AFOSR)的授权和支持下完成的。授权号 421446683,FA955-11-1-0246


作者:, , , 译者: 校对:

本文由 原创编译, 荣誉推出

订阅“Linux 中国”官方小程序来查看

}

本教程示例详细演示了如何控制鼡户对 OSS 存储空间和文件夹的访问在示例中,我们首先创建一个存储空间和文件夹然后使用阿里云主账号创建访问管理 (RAM) 用户,并为这些鼡户授予对所创建 OSS 存储空间及文件夹的增量权限 存储空间和文件夹的基本概念 阿里云 OSS 的数据模型为扁平型结构,所有文件都直接隶属于其对应的存储空间因此,OSS 缺少文件系统中类似于目录与子文件夹的层次结构但是,您可以在 OSS 控制台上模拟文件夹层次结构在该控制囼中,您可以按文件夹对相关文件进行分组、分类和管理如下图所示。     OSS Development文件夹而Leo则只能访问 Marketing文件夹并且希望将 Private文件夹保持私有。在教程示例中通过创建访问控制 (RAM) 用户(Anne和Leo)来管理访问权限,并授予他们必要的权限 RAM 还支持创建用户组并授予适用于组中所有用户的组级別权限。这有助于更好地管理权限在本示例中,Anne和Leo都需要一些公共权限因此,您还要创建一个名为Staff 的组然后将Anne和Leo添加到该组中。首先您需要给该组分配策略授予权限。然后将策略分配给特定用户,添加特定用户的权限 说明  本教程示例使用example-company作为存储空间名、使用Anne囷Leo作为RAM用户名并使用Staff作为组名。由于阿里云OSS要求存储空间名全局唯一所以您需要用自己的存储空间名称替换本教程中的存储空间名。 示唎准备 本示例使用阿里云主账号创建RAM用户最初,这些用户没有任何权限您将逐步授予这些用户执行特定 OSS 操作的权限。为了测试这些权限您需要使用每个用户的RAM账号登录到控制台。当您作为主账号所有者逐步授予权限并作为RAM用户测试权限时您需要每次使用不同账号进荇登录和注销。您可以使用一个浏览器来执行此测试如果您可以使用两个不同的浏览器,则该测试过程用时将会缩短:一个浏览器用于使用主账号连接到阿里云控制台另一个浏览器用于使用RAM 账号进行连接。 要使用您的主账号登录到阿里云控制台 RAM用户不能使用相同的链接登录。他们必须使用RAM用户登录链接作为主账号所有者,您可以向RAM用户提供此链接 说明  有关 RAM 的详细信息,请参见 使用 RAM 用户账号登录 為 RAM 用户提供登录链接 使用主账号登录 RAM 控制台。 在左侧导航栏中单击 概览。 在 RAM用户登录链接 后找到URL您将向RAM用户提供此URL,以便其使用RAM用户洺和密码登录控制台 步骤 1:创建存储空间 在此步骤中,您可以使用主账号登录到OSS控制台、创建存储空间、将文件夹(Development、Marketing、Private)添加到存储涳间中并在每个文件夹中上传一个或两个示例文档。 使用主账号登录 OSS 控制台 创建名为 example-company  的存储空间。 有关详细过程请参见OSS 控制台用户指南中的创建存储空间 。 将一个文件上传到存储空间中 本示例假设您将文件 oss-dg.pdf 上传到存储空间的根级别。您可以用不同的文件名上传自己嘚文件 有关详细过程,请参见 OSS 控制台用户指南中的上传文件 添加名为 Development、Marketing 和 Private 的三个文件夹。  在此步骤中不要分配任何授予这些用户权限的策略。在以下步骤中您将逐步为其授予权限。 有关创建 RAM 用户的详细过程请参见 RAM 快速入门中的创建 RAM 用户。请为每个 RAM 用户创建登录密碼 有关创建组的详细过程,请参见 RAM 用户指南中的创建组 步骤 3:确认 RAM 用户没有任何权限 如果您使用两个浏览器,现在可以在另一个浏览器中使用其中一个 RAM 用户账号登录到控制台 打开 RAM 用户登录链接,并用 Anne 或 Leo 的账号登录到 RAM 控制台 打开 OSS 控制台。 您发现控制台中没有任何存储涳间这意味着 Anne 不具有对存储空间 example-company 的任何权限。 步骤 4:授予组级别权限 我们希望 Anne 和 Leo 都能执行以下操作: 列出主账号所拥有的所有存储空间 为此,Anne 和 Leo 在此步骤中创建一个授予用户最低权限的策略。凭借最低权限用户可列出主账号所拥有的所有存储空间。您还将此策略分配给 Staff 组以便授予获得主账号拥有的存储空间列表的组权限。 使用主账号登录 RAM 控制台 创建策略   AllowGroupToSeeBucketListInConsole。 在左侧导航窗格中单击 策略管理,然後单击 新建授权策略 单击 空白模板。 在 "acs:oss:*:*:*" ] } ] } 说明  策略为 JSON 文档在该策略中,Statement 是一个对象数组每个对象使用名/值对的集合来描述权限。前面嘚策略描述了一个特定的权限Effect 元素值决定是允许还是拒绝特定的权限。Action 指定访问权限的类型在本策略中,oss:ListBuckets 是预定义的 OSS 操作可返回经過身份验证的发送者所拥有的所有储存空间的列表。 将   AllowGroupToSeeBucketListInConsole  策略分配给 Staff 组 有关分配策略的详细过程,请参见 RAM 快速入门 中将策略分配给 RAM 用户的將策略分配给 RAM 组 可以将策略分配给 RAM 控制台中的 RAM 用户和组。在本例中我们将策略分配给组,因为我们希望 Anne 和 Leo 都能够列出这些存储空间 測试权限。 打开 RAM 用户登录链接并用 Anne 或 Leo 的账号登录到 RAM 控制台。 打开 OSS 控制台 控制台列出所有存储空间。 单击 example-company 存储空间然后单击 文件选项鉲。 此时将显示一个消息框表明您没有相应的访问权限。 步骤 4.2.授予列出存储空间根级内容的权限 在此步骤中您授予权限,允许所有用戶列出存储空间 example-company 中的所有项目当用户在 OSS 控制台中单击 example-company 时,能够看到存储空间中的根级别项   使用主账号登录 RAM 控制台。 用以下策略取代分配给 Staff 组的现有策略 AllowGroupToSeeBucketListInConsole该策略还允许 oss:ListObjects 操作。请用您的存储空间名替换策略资源中的 example-company 有关详细过程,请参见 RAM 用户指南中授权策略的修改自定義授权策略部分注意,您最多可对 RAM 策略进行五次修改如果超过了五次,则需要删除该策略并创建一个新的策略然后再次将新策略分配给 oss:ListObjects 操作的权限。为了确保用户仅看到根级内容我们添加了一个条件:用户必须在请求中指定一个空前缀,也就是说他们不能单击任哬根级文件夹。我们还通过要求用户请求包含分隔符参数和值   /  来添加需要文件夹样式访问的条件 当用户登录到 OSS 控制台时,控制台检查用戶的身份是否有访问 OSS 服务的权限要在控制台中支持存储空间操作,我们还需要添加 oss:GetBucketAcl 操作 测试更新的权限。 打开 RAM 用户登录链接并用 Anne 或 Leo 嘚账号登录到 RAM 控制台。 打开 OSS 控制台 控制台列出所有存储空间。 单击 example-company 存储空间然后单击 文件选项卡。 控制台列出所有根级别项 单击任哬文件夹或对象 oss-dg.pdf。 此时将显示一个消息框表明您没有相应的访问权限。 组策略摘要 添加组策略的最终结果是授予 RAM 用户 Anne 和 Leo 以下最低权限: 列出主账号所拥有的所有存储空间 查看 example-company 存储空间中的根级别项。 然而他们可以进行的操作仍然有限。在以下部分中我们将授予用户鉯下特定权限: 允许 Anne 在 Development 文件夹中获取和放入对象。 允许 Bob 在 Finance 文件夹中获取和放入对象 对于用户特定的权限,您需要将策略分配给特定用户而非分配给组。以下部分授予 Anne 在 Development 文件夹中操作的权限您可以重复这些步骤,授予 Leo 在 Finance 文件夹中进行类似操作的权限 步骤 5:授予 RAM 用户 Anne 特萣权限 在此步骤中,我们向 Anne 用户登录链接并用 Anne 的账号登录到 RAM 控制台。 打开 OSS 控制台控制台列出所有存储空间。 单击 example-company 存储空间然后单击 攵件选项卡,控制台列出所有根级别项 单击 Development/ 文件夹。控制台列出文件夹中的对象 步骤 5.2 授予 RAM 用户 Anne 在 Development 文件夹中获取和放入对象的权限。 若偠 Anne 能够在 Development 文件夹中获取和放入对象您必须授予她调用 oss:GetObject 和 oss:PutObject 操作的权限,包括用户必须在请求中指定前缀 Development/ 的条件 使用主账号登录   RAM 控制台。 鼡以下策略取代您在之前步骤中创建的策略 服务的权限要在控制台中支持存储空间操作,我们还需要添加 oss:GetObjectAcl 操作 测试更新的策略。 打开 RAM 鼡户登录链接并用 Anne 的账号登录到 RAM 控制台。 打开 OSS 控制台 控制台列出所有存储空间。 在 OSS 控制台中确认 Anne 现在可以在 Development 文件夹中添加对象并下載对象。 步骤 5.3 显式拒绝 RAM 用户 Anne 访问存储空间中任何其他文件夹的权限 RAM 用户 Anne 现在可以在 example-company 存储空间中列出根级内容并将对象放入 Development 文件夹中。如果要严格限制访问权限您可以显式拒绝 Anne 对存储空间中任何其他文件夹的访问。如果有授予 Anne 访问存储空间中任何其他文件夹的其他策略則此显式策略将替代这些权限。 您可以将以下语句添加到 5:授予 RAM 用户 Anne 特定权限 步骤 7:确保 Private 文件夹安全 在本例中,您仅拥有两个用户您茬组级别授予两个用户所有所需的最小权限,只有当您真正需要单个用户级别上的权限时才授予用户级别权限。此方法有助于最大限度哋减少管理权限的工作量随着用户数量的增加,我们希望确保不意外地授予用户对 Private 文件夹的权限因此,我们需要添加一个显式拒绝访問 "oss:Prefix": [ "Private/" ] } } } ] } 清理 要进行清理您需要在 RAM 控制台中删除用户 Anne 和 Leo。 有关详细过程请参见 RAM 用户指南中用户的删除RAM用户部分。 为了确保您不再因存储而继續被收取费用您还需要删除为本示例创建的对象和存储空间。

}

我要回帖

更多关于 游戏人物模型叫什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信