移动跨平台方案下的暗流

原文链接

作者 | Eyal Guthmann

来源 | Dropbox 官方博客,The (not so) hidden cost of sharing code between iOS and Android

直到最近,Dropbox 在移动开发策略上,依然还保持着使用 C++ 在 iOS 和 Android 之间共享代码的思路。这个策略背后的想法很简单 - 在 C++ 中编写代码一次,而不是在 Java 和 Objective-C 中编写两次。我们在 2013 年就开始采用这种策略了,当时我们的移动开发团队规模相对较小,却需要支持快速增长的业务需求。我们需要找到一种方法,让这个小团队在 Android 和 iOS 上能快速发布大量代码。

不过现在我们完全抛弃了这个策略,转而使用每个平台的 native 语言(主要是 Swift 和 Kotlin,那时它们都还不存在)。做这个决定是由于代码共享存在着一些隐藏成本。在下文中,我们会聊聊 Dropdox 在使用这种共享代码策略时遇到的问题。这些问题都来自同一个基本问题

通过以非标准方式编写代码,我们承担了很多在使用平台 naitve 语言开发时不必担心的开销。这种开销最终比仅编写代码两次更昂贵。

在详细说明我们遇到的所有不同类型的开销之前,我想澄清一下,实际上我们并没有实现大多数代码库用 C++ 来开发。使用 C++ 产生的开销实际上阻止了我们完全朝这个方向发展。

值得注意的是,像谷歌和 Facebook 这样的大公司多年来一直在开发可扩展的代码共享解决方案。到目前为止,这些解决方案的使用还是很有限。虽然您可以通过利用像 React Native 或 Flutter 这样的第三方跨平台解决方案来避免下面描述的一些开销,但仍有一些开销是无法避免的(至少在其中某一项技术完全成熟之前)。例如,Airbnb 因为遇到本文中描述的许多相同原因而停止使用 React Native。

我们可以将我们遇到的各种开销分为四大类:

自定义框架和库的开销

使用 C++ 最容易想到的开销是需要构建框架和库。这大致分为 2 个子类别:

• 允许我们与宿主环境交互以构建完整的移动应用程序的框架。例如:

○ Djinni,一种用于生成跨语言类型声明和接口绑定的工具
○ 用于在后台运行任务而不是在主线程(在平台 native 语言中执行简单任务)的框架。
复制代码

• 将替换我们本可以在平台 native 语言中使用的语言默认/开源标准库的库。例如:

○ json11 用于 JSON 序列化/反序列化
○ nn,C++ 的非可空指针。
复制代码

如果我们继续使用平台 native 语言,那么这些代码都不是必需的,而且我们对开源项目的贡献可能会使更多的使用平台 native 语言的开发人员受益。我们可以在利用开源 C++ 库方面做得更好,但 C++ 开发社区中的开源文化(仍然是?)并不像移动开发社区那样强大(特别是在几乎不存在的 C++ 移动社区中)。

请注意,这些成本在 C++ 中特别高(与其他可能的非 native 语言如 Python 或 C# 相比),因为它缺少单一的全功能标准库。话虽如此,C/C++ 是唯一被 Google 和 Apple 同时支持的编译型语言,因此使用另一种不同的语言会产生许多其他问题。

自定义开发环境的开销

移动生态系统中有许多工具可用于提高开发效率。移动 IDE 非常丰富,Google 和 Apple 投入了大量资源,使其开发工具成为开发人员在相应平台上的最佳选择。通过摆脱平台的默认选项,我们放弃了这些 IDE 的一些优势。最值得注意的是,使用平台默认的 IDE 调试相应 native 语言的调试体验通常优于调试 C++ 代码。

一个特别令人难忘的例子是一个在我们的后台线程框架中导致应用程序随机崩溃的 bug。即使使用了一个简单的标准技术栈,这些类型的错误也难以确定。因为这个问题涉及调试在 C++ 和 Java 之间来回运行的多线程代码,我们花费了几周的时间才确定!

除了丧失工具之外,我们还不得不花时间构建支持 C++ 代码共享的工具。 最重要的是,我们需要一个自定义构建系统,该系统创建包含 C++ 代码以及 Java 和 Objective-C 包装器的库,并且可以生成 Xcodebuild 和 Gradle 都能理解的 target。这个系统对我们的资源造成很大的拖累,因为它需要不断更新以支持两个构建系统的更新。

解决平台之间差异的开销

尽管 iOS 和 Android 应用程序都是“移动应用程序”,也会有很多相同的特性和功能,但平台本身也存在一些影响实现的差异。例如,应用程序在每个平台上执行后台任务的方式是不同的。采用这种跨平台策略时,可能有些事情开始时相同,但随着时间的推移也可能会大不相同(例如,与相机的交互)。

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

这使得只编写一次代码并不符合承诺的理论上的好处,从而大大降低了这种方法的好处。

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

最后,但绝对不是最不重要的,是培训和/或雇用开发人员在我们的自定义技术栈上工作的成本。当 Dropbox 开始使用这种移动开发策略时,我们拥有一批经验丰富的 C++ 开发人员。该小组启动了 C++ 项目,并在 Dropbox 公司培训其他移动开发人员如何为代码库做出贡献。

随着时间的推移,这些开发人员流动到其他团队和其他公司。留下的工程师没有足够的经验来填补空缺,而聘请具有相关 C++ 经验并且对移动开发感兴趣的高级工程师变得越来越难。

结果,我们最终缺乏维护 C++ 代码库的关键专业知识。重拾这种专业知识的唯一方法在于以下两种选择之一:

• 找到并雇用具有这种特定技能的候选人(我们试图雇用这个角色,但一年多了都没有成功)

• 在内部培训移动(或 C++)工程师,让他们掌握这些技能。而当您不再拥有具有所需技能的人员来开展培训时,这几乎是不可能的。甚至在核心小组开始异动之前,由于移动工程师通常对学习 C++ 不感兴趣,因此这样的培训也是一个大问题。

在招聘问题上,坚持我们自己的技术栈会产生另一个问题 - 移动开发人员根本不想在 C++ 项目上工作。这导致许多有才华的移动工程师离开项目,他们并不愿意死磕一个维护得很好的自定义技术栈。总的来说,移动开发社区中变化是常态 - 新技术和模式经常出现并被迅速采用。最好的开发人员总喜欢让他们的技能保持最新。

在具有标准技术栈的成熟产品环境中,跟上最新和最好的技术是一项挑战。 你为了稳定而牺牲了速度。当您将自己锁定在自定义技术栈中以及更广泛的移动生态系统之外时,这一挑战将被大大放大。

结论

尽管编写一次代码听起来很不错,但相关的开销使得这种方法的成本超过了收益(结果却比预期的要小)。最后,我们不再通过 C++(或任何其他非标准方式)来共享移动代码,而是以平台 native 语言来编写代码。

此外,我们希望我们的工程师能够获得愉快的体验,并能够回馈社区。这也是我们决定让我们的实践与行业标准保持一致的原因。

关注我们

欢迎关注我们的公众号:知识小集(ID: zsxjtip),也欢迎加入我们的群组讨论问题。可以加微信 coldlight_hh/wsy9871 进入我们的 iOS/flutter 微信群。

转载于:https://juejin.im/post/5d563bae5188250afc0e6bf7

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值