开源依赖管理是一项平衡之术

409 位读者喜欢这篇文章。
A diagram of a bug.

Opensource.com

在我的职业生涯中,我花了很多时间打包别人的代码,编写自己的代码,以及从事大型软件框架的工作。我见过一些项目仍然没有发布稳定版本,始终没有达到 1.0,而另一些项目在开始开发后的几个月内就发布了 1.0 版本,然后迅速转向 2.0、3.0 等。这些发布周期差异很大,再加上维护大型项目,可能会使事情变得困难。

我将介绍我在我参与过的项目中面临的一些决策以及项目所承受的压力。一方面,用户希望拥有一个永不改变的稳定 API,以及不指定最低版本的依赖项,以便他们可以选择最适合自己的版本。另一方面,我们被推动使用最新的语言特性、硬件加速 API、编译器以及我们依赖的库。

你应该在第一天就使用这些,要求最新版本,还是给你的用户、发行版和其他用户时间来更新?当 API 更改成为必要时,你是立即更改它,还是等待并将更改批量放入主要版本中,并在其中给出适当的警告,从而降低 API 更改的频率?

开放化学与 C++11

当我们开始开发 开放化学项目 时,我们非常认真地考虑过要求使用 C++11,当时我们社区中的几个人劝阻了我。我们最终使用了 C++11 的一些小部分,这些部分可以设置为可选的,并回退到 Boost 实现/空宏定义。当时我认为这可能有点过于激进,但如果我可以回到过去,我会告诉过去的自己去尝试。该项目是新的,现有用户很少,主要针对桌面。此外,采用通常需要几年时间,并且支持旧编译器的成本也很高。

几个主要项目,例如 Qt,在去年才开始要求使用 C++11,还有更多项目将在 +/- 一年内开始要求。我现在认为很明显,优点大于成本,但要求非常新的编译器可能很难推销。随着微软发布了具有完整 C++11 支持的 Visual Studio 2015 社区版,这种情况变得更容易了,而 Linux 和 Mac 早就有了良好支持的 C++11 编译器。Linux 发行版的安全和长期支持版本仍然带来了一些挑战,但这在很大程度上现在已经是一个解决的问题了。

我已经让我们的其余依赖项与 Visual Studio 2015(仍然是最难让依赖项良好工作的平台)一起工作,并将很快删除我们的可选 Boost 回退代码。现在还有其他明显的优势,例如 PyBind11 项目,该项目为 C++ 提供了一个仅包含头文件的 Python 包装 API,除了 C++11 之外没有其他依赖项。语言更改还使一些本地实现变得无关紧要,并消除了使用线程、原子和其他新功能时对复杂回退的需求。C++14 的问题仍然迫在眉睫,我倾向于直接跳到 C++14,因为它看起来我们所有的平台现在都有良好的支持。C++14 看起来更像是一个错误修复版本,但它有一些很棒的修复!

第三方库

作为在 Gentoo Linux 上打包软件多年的开发者,如果你的项目捆绑了一堆第三方库,我会诅咒你的名字。但作为一名软件开发者,我完全理解为什么项目会这样做,以及这样做如何使启动和运行变得容易得多。如果项目行为良好,开发者会提出一个解决方案,默认构建捆绑库,并使打包者和其他人可以轻松使用系统库。

这依赖于第三方库的上游维护稳定的 API,下游项目坚持这些稳定的 API,以及下游项目快速使用定期发布版本。对于 Linux 发行版,安全修复理想情况下应该只在一个或两个地方应用,然后所有依赖项目要么重建,要么在下次重新加载时简单地链接到更新后的库。

当库的 API 发生更改,或者当项目的开发者不定期更新他们的第三方库(或者在 API 更改时更新过于频繁,迫使依赖项更新)时,情况会变得更加困难。理想的解决方案显然是使用具有定期发布周期的项目,快速集成他们的新版本,理想情况下维护一个稳定的 API,该 API 在可以使用的库版本中提供一定的灵活性。

在 Windows 和 Mac OS X 平台上,这些库在软件包安装后很少更新,因此跟踪上游并确保集成任何安全修复程序就更加重要。这样做具有挑战性,这也是我一直使用 CMake 的外部项目来构建依赖项的原因之一,这些依赖项提供了捆绑第三方库的许多优势,并且可以更简单地集成更新版本。

OpenGL 和科学可视化

大约两年前,我撰写了一篇论文,讨论了 可视化工具包 (VTK) 的渲染后端的重写。我认为这次重写早就应该进行了,并且作为一名在加入 Kitware 之前编写过渲染代码的人,我发现我们无法使用最新的 OpenGL 进展(或者至少是过去十年的某些进展)令人沮丧。我知道我感兴趣的几个渲染工作负载可以从更新中受益,而且这似乎是普遍的。

我开始研究我们如何进行一些增量更改,但问题是 OpenGL 的变化太大了,这很困难。其他人也同意需要重写,但认为需要更多资金来重写所有渲染代码。这是一项相当大的任务,而且今天仍然没有完成。已经取得了很大的进展,但是人们总是想要新的功能、优化以及正在编写的新的渲染驱动程序部分,以充分利用最新的显卡。

我们将新的渲染后端称为 OpenGL2,旧的渲染后端主要是 OpenGL 1.1,带有一些新功能的运行时检测。最初,我们的目标是在桌面上使用 OpenGL 2.1,在嵌入式系统上使用 OpenGL ES 2.0,这使得 OpenGL2 感觉非常贴切。此外,从我的许多研究中,我清楚地发现 OpenGL 2.1 和 OpenGL ES 2.0 有一个共同的 API 子集,被许多其他项目使用。随着项目的发展,人们希望使用更多来自 OpenGL 3.2 和 OpenGL ES 3.0 的功能——新的最低要求不断演变。

我们在一些我们想要部署的系统/芯片上遇到了问题,有时软件渲染也具有挑战性。总的来说,我们已经能够使事情正常运行。这归结为精细的平衡,极端的两端可能很清晰,但中间地带往往感觉更难定义。过度推向任何一个极端都有实际成本,我认为 VTK 由于使用非常旧的 API 而面临落后的危险,如果我们下周开始要求使用 OpenGL 4.4,我们将远远超出频谱的另一端。

Qt 3 vs. 4 vs. 5

在我的开发生涯中,我经历了 Qt 的三个主要版本,其中从 3 到 4 的过渡最具挑战性。这些更新中的每一个都涉及相当大的变化,但在 4 到 5 的过渡中变化要小得多。Avogadro 2 项目在几年前迁移到了 Qt 5,因为它更新(它始于 4,这是另一个事后看来我希望我们早点跳到 Qt 5 的案例)。在 Tomviz 项目中,我们重用了 ParaView,并在大约一年前使用了 Qt 4,那时我们完成了迁移到 Qt 5 的工作。

ParaView 项目本身仍然默认使用 Qt 4,并且在现代操作系统上支持 Qt 4 变得越来越困难。他们已经同时支持这两个版本一段时间了,但他们仍然有一些问题阻碍着他们。现代操作系统已经发生了重大变化,高分辨率显示器和用户界面的更新都导致与 Qt 4 目标产生显着差异。

他们还对 Qt 与主机操作系统的集成方式以及它与 OpenGL 的交互方式进行了重大更改。此外,还对线程模型进行了重大更改,并进行了更新以利用 C++11 及更高版本中的新功能,因此支持两个主要版本可能很困难。

Python 2 vs. 3

这个问题一直困扰着我,并且有几个项目不得不选择跳到哪一边,或者跨越两边,以便他们可以同时提供两者。在 VTK 项目中,我们的生成器代码必须更新,我们能够提供 Python 2 或 3,但尚未投入工作同时提供两者。ParaView 项目构建于 VTK 之上,最近更新了其代码以支持 Python 2 和 3,但 Python 3 支持在那里仍然非常实验性。我希望在未来一两个月内更新 Tomviz 以提供对 Python 3 的支持,这变得越来越重要,因为越来越多的 Python 模块只切换到 Python 3。

在 Web 方面,我参与了一个扩展 Girder 平台的项目,该平台本身使用 CherryPy、PyMongo 和许多其他模块。当我们启动该项目时,它仅支持 Python 2,但他们在不久之后添加了对 Python 3 的支持——使我们能够切换到 Python 3。在那里,我们决定不支持两者,因为它是一个新项目,而且我们知道它在短期内不太可能被广泛使用。在 Google 编程之夏导师峰会上,Python 社区中的几个人对这种情况表示沮丧,并表示他们对支持两者和放弃新语言特性的成本是否值得感到矛盾。

结束语

希望我们可以保持良好的中间立场,最好地服务于我们的用户,并意识到过于保守或过于激进的成本。大多数开发者都渴望使用最新的功能,并且知道有一种更好的方法但无法采用可能会非常令人沮丧。我认为过于保守会付出巨大的代价,但我见过其他一些项目更新和更改过于激进,从而失去了市场份额。

标签
Marcus D. Hanwell
Marcus D. Hanwell | Marcus 领导开放化学项目,开发用于化学、生物信息学和材料科学研究的开源工具。

2 条评论

人们为什么提供 API?大概是因为他们希望人们使用它们。他们提供什么来使 API 对其他人有用?当然是功能。但这只是使其有用的一个方面。稳定性必定是另一个方面。如果有人知道 API 的作者会不断更改它,谁愿意承诺使用特定的 API? API 的提供应该被视为带有维护稳定性的隐含承诺。

正如我在文章中所说,在理想的世界中,API 将永远稳定,但现实情况是这种情况很少发生。新技术被开发出来,批处理命令、组合数据等的更好方法。如果您不改进您的 API 以利用这些东西,那么人们通常会转向可以做到这一点的库,这就是为什么大多数库都使用版本号来表示可能发生的变化 - 主要版本可能是 API 更改,次要版本通常是 API 的添加,错误修复版本仅修复错误/问题。存在隐含的承诺,但也存在继续开发库、添加功能以及利用新技术/方法/想法的隐含承诺。

回复 作者: igoddard (未验证)

Creative Commons 许可协议本作品根据 Creative Commons 署名 4.0 国际许可协议获得许可。
© . All rights reserved.