IT资讯 Dropbox 与 C++ 的“七年之痒”难跨越,跨平台真的是伪命题吗?

rudolph · 2019-08-19 10:00:06 · 热度: 10

Perl 语言创建者 Larry Wall 曾总结过好的 程序员 有 3 种美德:懒惰、急躁和傲慢(Laziness, Impatience and hubris)。因为懒惰,程序员绞尽脑汁地将大量的重复性劳动交由机器处理;因为懒惰,程序员希望通过“一次编写,处处运行”而实现“一劳永逸”的美好愿望。

“一次编写,处处运行” —— 简单来说就是跨平台。然而这个十分符合程序员思维,且承载着他们美好愿望的方案,在实际操作中往往不能如其所愿,甚至会适得其反。

Dropbox 工程师近日在其官方博客和大家分享了他们“弃暗投明”的经历 —— 放弃在其 iOS 和 Android 客户端之间共用同一套代码的策略,转而使用各自平台的原生语言进行开发。

Dropbox 与 C++ 的“七年之痒”难跨越,跨平台真的是伪命题吗?

工程师表示,Dropbox 在 2013 年开发 iOS 和 Android 平台的移动应用时,采用了通过 C++ 语言在两个平台之间共享同一套代码的策略。当时的想法十分简单,开发团队希望使用 C++ 编写一次代码即可,无需分别针对 iOS 和 Android 平台各使用 Objective-C 和 Java 编写两次代码。另外,当时负责移动应用开发的团队规模相对较小,为支持快速增长的移动应用,他们需要找到一种方法以通过这个小团队在 iOS 和 Android 平台上快速部署大量代码。

但现在 Dropbox 放弃了这个策略,转而使用各自平台的原生语言(主要是 Swift 和 Kotlin)。之所以做出这个决定,是因为在两个平台共用同一套代码的隐藏开销其实很高。他们从中总结到的经验就是:如果遵循广泛使用的平台默认标准,而不是以非标准方式编写代码,他们可以不用承担本应不必考虑的开销,这种开销最终比编写代码两次更昂贵。

Dropbox 工程师将这些隐藏开销归纳为四类,在介绍这些隐藏开销之前,工程师强调他们实际上从未达到大多数代码库均使用 C++ 开发的阶段,因为正是采用 C++ 带来的隐藏开销阻止了他们完全朝这个方向发展。

维护自研框架和库的开销

使用 C++ 首先面临的开销是需要自己构建框架和库,这大致分为 2 个子类别:

  • 支持与主机环境交互以构建完整的移动应用程序的框架。例如:
    • Djinni:用于生成跨语言类型声明和接口绑定的工具
    • 用于在后台运行任务与主线程的框架(使用平台原生语言执行简单任务)
  • 用于替代本可以在平台原生语言中使用的默认或者开源标准库。例如:
    • json11:用于 JSON 的 (反)序列化
    • nn:C++ 的非可空指针

Dropbox 工程师表示,如果采用平台原生语言,这些代码都不是必需的,而且他们对开源项目的贡献可能会使更多的开发者受益于平台原生语言。值得注意的是,上述的这些开销在 C++ 中尤其高(与其他非原生语言如 Python 和 C# 相比),因为它缺少单一的全功能标准库。话虽如此,C/C++ 是唯一包含受 Google 和 Apple 支持的编译器的语言,如果使用不同的语言会产生许多其他需要处理的问题。

维护自研开发环境的开销

移动生态系统有许多 工具 可帮助提升开发效率。其中用于移动开发的 IDE 也非常丰富,Google 和 Apple 为其投入了大量资源,让开发者在相应的平台上拥有最佳的开发体验。由于 Dropbox 没有使用平台的默认方案,他们自然无法享用这些便利。其中最值得注意的是调试体验,在平台的默认 IDE 中调试平台原生语言的体验通常优于调试 C++ 代码的体验。

Dropbox 工程师举了一个尤其令他们印象深刻的例子,在其后台线程框架中出现了导致应用程序随机崩溃的错误。为此他们使用了简单的标准堆栈,但是也难以定位这些类型的错误。因为这个问题涉及调试在 C++ 和 Java 之间来回运行的多线程代码,最终他们花费了几周的时间才定位了问题所在。

除了工具的缺失,工程师还需要花费时间构建支持共用同一套 C++ 代码的工具。最重要的是,他们需要一个自定义构建系统,该系统用于创建包含 C++ 代码以及封装 Java 和 Objective-C 代码的库,并且可以生成 Xcodebuild 和 Gradle 都能理解的对象。正是这个系统对 Dropbox 的资源造成巨大的拖累,因为它需要不断更新以支持两个构建系统的变更。

可以看到,大量的时间被耗费在造轮子 -> 补轮子的重复中。

解决不同平台之间的差异的开销

虽然 iOS 和 Android 应用程序都统称为“移动应用程序”,并且两者通常具有相同的特性和功能,但平台本身存在一些影响功能实现的差异。例如,应用程序在每个平台上执行后台任务的方式是不同的。即使刚开始采用这种跨平台策略时具有一定的相似之处,但随着时间的推移这些差异会大相径庭(例如,与系统相册的交互)。

因此,工程师甚至无法真正实现编写一次代码并让它在不同平台上开箱即用地运行。他们必须花费大量时间将代码集成到不同的平台,并编写特定于平台的代码。

所以这里的“只编写一次代码”并不能如愿以偿,大大降低了这种方法的便利性。

招聘、培训和留住开发者的开销

当 Dropbox 在其移动应用产品上采用这种策略时,他们拥有一批经验丰富的 C++ 开发者。这个团队启动了 C++ 项目,并对其他的开发者进行了培训以为项目贡献代码。

但随着时间的推移,这些有经验的开发者逐渐去了其他团队或者其他公司。剩下的开发者缺乏足够的经验来支撑和推进项目,而招聘具有相关 C++ 开发经验的高级工程师也变得越来越困难。

最后团队缺乏维护 C++ 代码库的关键专业知识,而要满足这一需求团队有以下两种选择:

  1. 找到并雇用具有这种特定技能的候选人(现实情况是招聘了一年仍未能找到合适的人选)
  2. 针对缺失的技能,在内部培训移动(或 C++)工程师。但现实情况是缺少拥有所需技能的人员来进行培训,所以这个目标也难以实现。甚至在培训前,就有移动工程师透露出对学习 C++ 不感兴趣。为此培训所需的开发者也是一大问题。

在招聘问题上,Dropbox 工程师发现许多移动开发者根本不想在 C++ 项目中工作,这也导致他们许多优秀的工程师离开项目。毕竟移动开发技术的更新非常快,这些开发者希望自己的技术栈能时刻跟上潮流。

结论

Dropbox 表示隐藏开销导致最终的成本超过了收益,还不如使用各自平台的 IDE 开发更为简单和便宜。所以最后他们不再通过 C++(或任何其他非标准方式)共用同一套移动端代码,而是使用各自平台的原生语言编写代码。

相关阅读
Airbnb 宣布放弃使用 React Native,回归使用原生技术
Airbnb 之后,Udacity 也加入弃用 React Native 队列

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册