摘要
随着开源软件和软件包托管平台的兴起,重用第 3 方库已成为一种普遍做法。
由于软件演进过程中的各种失败,一个项目可能会移除一个使用过的库并用另一个库替换它,我们称之为库迁移(library migration)。
尽管对依赖管理进行了大量研究,但仍然缺乏对库迁移如何以及为何发生的理解。 实现这种理解可以帮助从业者优化他们的库选择标准,开发自动化方法来监控依赖关系,并为他们的库或软件项目提供迁移建议。
在本文中,通过对 19,652 个 Java GitHub 项目的细粒度提交级别分析,我们提取了迄今为止最大的迁移数据集(1,194 条迁移规则,3,163 条迁移提交)。我们表明,8,065 (41.04%) 个项目至少有一个 库移除,1,564(7.96%,下限)到 5,004(25.46%,上限)项目至少有一次迁移,一个有迁移的中位项目总共有 2 到 4 次迁移。我们发现库迁移由几个主导 域(日志记录、JSON、测试和 Web 服务)呈现长尾分布。 此外,迁移是高度单向的,因为我们的项目语料库中的库要么大部分被放弃,要么大部分被选择。 对相关提交消息、问题和拉取请求的主题分析确定了 14 个经常提到的迁移原因(例如,缺乏维护、可用性、集成等),其中 7 个在以前的工作中没有讨论。 我们的发现可以为包托管平台、项目维护人员和库开发人员提供可操作的见解。
我们在 https://doi.org/10.5281/zenodo.4816752 提供了一个复制包。
1. INTRODUCTION
重用现有的具有即用功能的第三方库长期以来一直是软件开发中的常见做法,这可以提高软件质量和开发效率 。 尽管如此,直到最近十年开源软件的兴起和中央托管平台(例如 Maven、NPM、PyPI 等)的可用性,软件重用才变得如此容易。 Maven Central 上新发布的 JAR 数量从 2010 年的 86,161 个增加到 2015 年的 364,218 个和 2020 年的 1,435,600 个。 因此,第三方库在开源和专有软件项目中被广泛采用,一个非平凡的软件项目通常会重用数十甚至数百个现有库。
同时,采用第三方库在整个软件生命周期中带来了独特的挑战。
首先,鉴于可用库的范围很广,甚至为特定目的选择正确库的任务也变得非常重要,其中需要考虑复杂的社会技术因素 。
其次,人们越来越担心使用过时的库的风险,因为它们可能包含安全漏洞和未解决的问题
- 因此,研究人员研究了库更新的特征、原因和驱动因素 ,从业者提出了行业解决方案(例如 Synk [45]、WhiteSource [64] 和 GitHub Advisories [32]),旨在使库保持最新且无漏洞。 但是,与库的故障或错位不可避免地发生,并且可能无法通过更新其版本来解决。 在这种情况下,必须完全删除库并替换为另一个库,这在文献中称为库迁移(library migration)。
虽然进行了大量现有研究来表征和理解 library adoption 和 library updates ,library migration 的研究仍然是碎片化和不完整的。
- How Does Library Migration Impact Software Quality and Comprehension? An Empirical Study. In Reuse in Emerging Software Engineering Practices ICSR 2020 [2]
- Swing to SWT and back: Patterns for APImigration by wrapping ICSM 2010 [5]
- Study of an API Migration for Two XML APIs SLE 2009 [6]
- Logging library migrations: A case study for the Apache Software Foundation projects MSR 2016 [37]
- Mining Library Migration Graphs WCRE 2012, [69]
- A study of library migrations in Java Softw. Evol. Process. 2014 [71]
更具体地说,我们缺乏理解:
- how a large number of projects migrate their dependencies
- what factors drive such migrations
作为 library adoption failures 的最终后果,这种理解将成为开发人员、决策者和利益相关者的宝贵信息来源。 它可以帮助他们优化库选择标准,开发自动化方法来监控依赖关系,并为其库或软件项目提供迁移建议。 为了弥合这一知识差距,我们寻求对大规模开源数据进行描述性混合方法研究,以全面了解 library migration 的发生方式和原因。
更具体地说,我们提出以下研究问题:
- RQ1: How common are library migrations?
- RQ2: How do migrations happen between libraries?
- RQ3: What are the frequently mentioned reasons when developers conduct a library migration?
2. BACKGROUND
迁移是软件维护过程中的常见现象,它可能是指源于各种动机的不同开发活动。 常见的迁移案例包括:
version 迁移
- Do developers update their library dependencies? An empirical study on the impact of security advisories on library migration. Empir. Softw. Eng 2018 [43]
API 迁移
- On the use of information retrieval to automate the detection of third-party Java library migration at the method level. ICPC 2019 [4]
programming language 迁移
- Mining API mapping for language migration. ICSE 2010 [85]
platform 迁移
- GUI Migration using MDE from GWT to Angular 6: An Industrial Case. SANER 2019 [79]
library 迁移
- A Multi-Metric Ranking Approach for Library Migration Recommendations. SANER 2021 [36]
- Logging library migrations: A case study for the Apache Software Foundation projects. MSR 2016 [37]
- Mining Library Migration Graph. WCRE 2012 [69]
- A study of library migrations in Java. J. Softw. Evol. Process. 2014 [71]
library 迁移 通常需要三个步骤:
- 证明迁移的必要性
- 找到最佳目标库
- 修改代码以使用新库。
对于开源项目,前两个步骤通常通过 issue trackers 中的公开讨论来促进,其中的收益和成本由开发人员评估 。 如果未达成共识或预期收益不超过成本,此类讨论可能不会导致迁移。
成本主要来自第三步,众所周知,这一步很乏味、容易出错,而且有时很困难。有一些研究工作旨在提高第三步开发效率的努力,通过使用 API 包装器 、挖掘 API 映射,或直接编辑代码以使用新的 API。 研究还表明,library 迁移 可能会提高代码质量,但很少能提高性能。
在本文中,我们根据现有研究 [37、69、71](表 1),重点了解库迁移的前两个步骤。
文章[69] 提出了 migration graph 的概念和一种从软件版本中挖掘 migration graph 的方法,他们从现实世界的例子中得到了 80 条迁移规则和三个原因。
文章[71]中,作者对 15,168 个项目的提交历史使用了一种改进的方法,并获得了 329 条迁移规则、1,198 条迁移和 26 条提及迁移原因的提交消息。
文章[37] 分析了开发人员对 Apache 软件基金会 (ASF) 项目中日志库迁移的讨论,他们确定了 49 次迁移尝试和五个主要原因。
然而,现有的研究 [37, 69, 71] 有几个局限性。
[69] 只获得了少量的迁移
[69, 71] 没有坚实的方法论基础,难以复制。 根据他们的定义,如果两个具有相似功能的库共存并且一个在项目历史中被删除,就会发生库迁移。 其概念是模棱两可的,根据这个定义,library migrations 可能是高估了。 他们也没有提供关于他们手动识别标准的足够详细信息,也没有分享他们的图书馆迁移数据集。
[71] 仅使用源代码分析来识别库,这可能会错过仅修改配置文件的迁移
[37] 侧重于日志库迁移。因此,[37] 中的发现不能反映一般趋势,也可能无法推广到其他类型的 library。
在本文的研究中,作者挖掘了大规模历史数据,以全面概述在大量 projects 和 library 之间发生 library migrations 的方式和原因。
3. DATA COLLECTION
3.1 Collecting Projects and Libraries
我们从最新的 Libraries.io 数据集 [38](2020 年 1 月发布)开展 Java 项目的研究,该数据集广泛用于相关研究。
然后,为了检索这些项目的版本控制数据,我们使用 World of Code 数据库 [46](R 版,于 2020 年 4 月构建)。 为了简化依赖提取的任务,我们专注于使用 Maven [30] 进行构建和依赖管理的项目。
最后,我们得到 4,022 个 library。我们对 94 个 library(置信水平 = 95%,置信区间 = 10)进行抽样,并通过在 Maven Central 中检查它们的描述并在 Web 上搜索它们来确定它们是否符合。 94 个样本中的 93 个 (98.93%) 包含表明其重用适当性的公开信息(例如,库、框架、平台、规范等术语),这证明了我们的选择标准是合理的。
3.2 Computing Dependency Changes
收集项目和库后,我们的下一个任务是从项目提交历史中提取依赖项更改,因为这些依赖项更改可能表明库迁移。 但是,对于给定的 pom.xml 文件,简单地按时间对所有版本进行排序和比较会产生过多的误报,因为一个项目可能有许多并行分支,这些分支可能会或可能不会合并,从而有效地形成有向无环图 [9] (directed acyclic graph,DAG ,见图 1)。
为了将 DAG 考虑在内,我们将每个 dependency change 建模为一次提交中的 event,这可以是 adoption, a removal, or a version change 。 该 event 是通过与父提交中的先前 pom.xml 文件版本进行比较来计算的。 更准确地说,让 commit 𝑐1 是 commit 𝑐1 的父级,𝐿1 是commit 𝑐1 的pom.xml 文件𝑓 中的依赖项集合,同理 𝐿2 。
因此有
对于图 1 中的 𝑐2,
我们忽略合并提交是基于合并提交很少用于解决冲突以外的新更改的假设。
为了验证这个假设,我们从所有存储库中收集了带有 pom.xml 的合并提交(总共 207,553,占所有合并提交的 8.2%),并发现只有 6,801 (3%) 有新的 dependency change 。 通过对所有项目的所有提交差异进行迭代,我们从 302,774 次提交中获得了 2,629,992 次依赖项更改。
3.3 Identifying Library Migrations
数据集统计如下
4. RQ1: HOWCOMMON ARE LIBRARY MIGRATIONS?
4.1 RQ1.1: Removal Frequency Analysis
在具有依赖项的项目中,44.07% 至少删除了一个库。 对于这些项目,中位数项目每 139 次提交删除一次(相比之下,每 167 次提交一次版本更改)。 对于具有更多提交和依赖项的项目,更有可能发生删除。
4.2 RQ1.2: Migration Frequency Analysis
在所研究的项目语料中,8.98% 到 28.72% 至少经历过一次库迁移。 对于这些项目,大多数迁移不超过五个。 对于具有大量提交和依赖项的项目,进行库迁移的可能性会显着增加
5. RQ2: HOWDO MIGRATIONS HAPPEN BETWEEN LIBRARIES
5.1 Methodology
5.2 Results
来自 53 个域中的四个域(日志记录、测试、JSON 和 Web 服务)的库迁移主导了数据集,呈现出长尾分布。 此外,库迁移是高度单向的,因为大多数库要么大部分被采用,要么大部分被放弃。
6. RQ3: WHAT ARE THE FREQUENTLY MENTIONED REASONS WHEN DEVELOPERS CONDUCT A LIBRARY MIGRATION?
6.1 Methodology
6.2 Results
项目从源库、目标库和项目本身出于 14 种不同原因进行库迁移。 最常见的原因是:
- 源库缺乏维护
- 目标库中的特性/可用性
- 与项目上下文的集成
- 依赖关系的简化