写点什么

跨平台开发成本太高?Dropbox 最终宁愿将代码编写两次

2019 年 8 月 19 日

跨平台开发成本太高?Dropbox最终宁愿将代码编写两次

直到最近,Dropbox 都在使用一个通过 C++在 iOS 和 Android 之间共享代码的移动技术策略。这个策略背后的想法很简单:用 C++编写一次代码,而不是用 Java 和 Objective C 编写两次代码。现在,Dropbox 已经完全放弃了这个策略,转而使用每个平台的原生语言。这个决定是由于与代码共享相关的隐藏成本太高。



正文

直到最近,Dropbox 都在使用一个通过 C++在 iOS 和 Android 之间共享代码的移动技术策略。这个策略背后的想法很简单:用 C++编写一次代码,而不是用 Java 和 Objective C 编写两次代码。早在 2013 年,我们就采用了这个策略。当时,我们的移动工程团队相对还比较小,但需要支持快速增长的移动路线图。我们需要找到一种方法,使这个小团队可以快速交付大量的 Android 和 iOS 代码。


现在,我们已经完全放弃了这个策略,转而使用每个平台的原生语言(主要是 Swift 和 Kotlin,这两种语言在我们刚开始制定移动策略时还不存在)。这个决定是由于代码共享相关的隐藏成本太高。下面是我们作为一个公司在有效共享代码的成本方面学到的一些东西。它们都源于同一个基本问题:


以非标准的方式编写代码,使我们承担了一些开销,而如果我们采用广泛使用的平台默认选项,我们就不必担心这些开销。这种开销最终比只编写两次代码要昂贵得多。


在详细介绍我们遇到的所有不同类型的开销之前,我想澄清一下,我们实际上从来没有达到用 C++开发大部分代码库的地步。采用 C++的开销实际上阻止了我们完全朝着这个方向前进。


同样值得注意的是,像谷歌和 Facebook 这样的大公司多年来一直在开发可扩展的代码共享解决方案。到目前为止,这些解决方案只获得了有限的采用。虽然你可以利用第三方代码共享解决方案(如 React Native 或 Flutter)来避免下面描述的一些开销,但有一些仍会存在(至少在其中一项技术获得支持并成熟之前)。例如,Airbnb放弃React Native的原因与本文中描述的许多相同。


我们可以把我们面临的不同类型的开销分为四大类。


自定义框架和库的开销

关于使用 C++,最容易预见的开销是需要构建框架和库。这大致可以分为两大类:


  • 框架,让我们可以与主机环境交互,构建一个功能齐全的移动应用程序。例如:

  • Djinni:一个可以生成跨语言的类型声明和接口绑定的工具;

  • 用于在后台和主线程中运行任务的框架(在平台原生语言中,这是一个很简单的任务)。

  • 这些库将取代我们本可以在平台原生语言中使用的默认语言/开源标准。例如:

  • 用于 JSON(反)序列化的json11

  • C++非可空指针nn


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


注意,这些成本在 C++中特别高(与 Python 或 C#等其他可能的非原生语言相比),因为它缺少一个功能齐全的标准库。虽说如此,C/C++是唯一一种编译器同时受到谷歌和苹果支持的语言,因此,使用另一种语言将会产生一系列其他需要处理的问题。


自定义开发环境的开销

移动生态系统有许多工具可用来提高开发效率。移动 IDE 非常丰富,谷歌和苹果投入了大量的资源,力争在各自的平台上为开发人员提供最佳的开发体验。我们远离了这些平台的默认选项,也就放弃了其中的一些好处。最值得注意的是,使用平台原生语言的调试体验通常优于在平台的默认 IDE 中使用 C++代码的调试体验。


一个特别令人难忘的例子是一个 Bug,它在我们的后台线程框架中导致了死锁,使得应用程序随时都会崩溃。即使是在处理简单的标准栈时,也很难确定这些类型的 Bug。因为这个问题涉及到调试在 C++和 Java 之间来回运行的多线程代码,所以花了几周的时间才确定下来!


除了失去工具,我们还必须投入时间构建支持 C++代码共享的工具。最重要的是,我们需要一个定制的构建系统,它创建了包含 C++代码以及 Java 和 Objective-C 封装器的库,并且能够生成 Xcodebuild 和 Gradle 都能识别的目标文件。这个系统对我们的资源是一个很大的拖累,因为它需要不断地更新以支持两个构建系统中的更改。


处理不同平台差异的开销

尽管 iOS 和 Android 应用程序都是“移动应用程序”,通常都具有相同的特性和功能,但平台本身存在一些影响实现的差异。例如,应用程序在每个平台上执行后台任务的方式不同。即使在我们开始采用跨平台策略时非常相似的东西,随着时间的推移也会产生很大的差异(例如,与相机相册的交互)。


因此,你甚至不能真正地编写一次代码就在不同的平台上运行。你必须花费大量的时间将代码集成到不同的平台中,并编写特定于平台的代码(有时这些代码就位于 C++层本身!)。


这使得只编写一次代码理论上的好处没有达到预期的效果,从而大大降低了这种方法的好处。


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

最后,但同样重要的是,培训和/或招聘将在我们定制程度非常高的技术栈上进行开发的开发人员的成本。当 Dropbox 开始采用这种移动策略时,我们有一个由经验丰富的 C++开发人员组成的核心团队。这个小组启动了 C++项目,并在 Dropbox 培训其他移动开发者如何为代码库做贡献。


随着时间的推移,这些开发人员转向其他团队和其他公司。留下来的工程师没有足够的经验来填补技术领导的空缺,并且越来越难招聘到具有相关 C++经验、对移动开发感兴趣的高级工程师来替代他们。


因此,我们最终失去了维护 C++代码库的关键专业知识。重新获得这种专业知识的唯一方法是大量投资于以下两个选择之一:


  1. 寻找并招聘具备这种特殊技能的求职者(我们曾尝试招聘这个职位超过一年,但没有成功);

  2. 针对内部移动(或 C++)工程师缺少的技能集对他们进行培训,当你没有所期望技能集的人员来执行培训时,这实际上是不可能做到的。即使在核心团队离开之前,移动工程师通常也对学习 C++不感兴趣,所以找人来接受培训也是一个大问题。


除了招聘问题,我们自己的技术栈也导致留住开发人员成为一个问题——移动开发者根本不想从事 C++项目开发。这导致许多有才华的移动工程师离开了这个项目,而不是费力地使用一个维护得不是很好的自定义技术栈。总的来说,移动开发社区非常有活力——新技术和新模式层出不穷,并且被迅速采用。最好的开发人员喜欢让他们的技能保持最新。


在具有标准技术栈的成熟产品环境中,跟上最新最好的技术潮流是一个挑战。为了稳定性,你牺牲了采用速度。当你把自己锁在一个自定义技术栈中,并置身于更广泛的移动生态系统之外时,这一挑战将被极大地放大。


小结

尽管编写一次代码听起来很划算,但是相关的开销使这种方法的成本超过了所能获得的好处(结果证明,这种好处比预期的要小)。最后,我们不再通过 C++(或任何其他非标准方式)共享移动代码,而是用平台的原生语言编写代码。


此外,我们希望我们的工程师有一个愉快的经历,能够为社会作出贡献。这就是为什么我们决定使我们的实践与行业标准保持一致。


查看英文原文:The (not so) hidden cost of sharing code between iOS and Android


2019 年 8 月 19 日 08:4926397
用户头像

发布了 362 篇内容, 共 158.1 次阅读, 收获喜欢 814 次。

关注

评论 2 条评论

发布
用户头像
的确如此,跨平台是个伪命题,忽略了平台特性带来的差异化处理成本
2019 年 08 月 19 日 13:04
回复
感谢观点分享~
2019 年 08 月 19 日 13:05
回复
没有更多了
发现更多内容

数据库事务与锁详解

阿骆麦迪

MySQL 事务 六月日更

运维大佬嘲笑我,这个你都不知道?

我是阿沐

redis 运维自动化 面试大厂真题

腾讯云大神亲码“redis深度笔记”,不讲一句废话,肝就完事了

神奇小汤圆

Java redis 程序员 架构 面试

如果把四个消息队列都拉到一个群里,他们会聊些什么?

悟空聊架构

故事 消息队列 群聊 6 月日更 悟空聊架构

JavaScript 学习(四)

空城机

JavaScript 前端 6月日更

MySQL基础之十五:索引

打工人!

MySQL 6 月日更

「SQL数据分析系列」6. 使用集合

gongyouliu

sql 集合

并发王者课-铂金2:豁然开朗-“晦涩难懂”的ReadWriteLock竟如此妙不可言

秦二爷

Java 多线程 并发

Kubernetes手记(14)- 用户权限系统

雪雷

k8s 六月日更

涨薪50%,从小厂逆袭,坐上美团L8技术专家(面经+心得)

神奇小汤圆

Java 程序员 架构 面试

校外培训行业迎来强监管,“教育+区块链”新模式试图解决行业痼疾

CECBC区块链专委会

SpringCloud Gateway 动态路由

中原银行

微服务 SpringCloud Gateway 中原银行

宝,我今天注入了,注入的想你的液[SQL注入之sqli-labs(Less1-6)]

Machine Gun

sql 运维 网络安全 信息安全 渗透测试

Low-Code能否威胁到专业的程序员?| 话题

三掌柜

试用期 签约计划 人气作者 TOP10

C++友元的概念和使用的一些介绍

良知犹存

c++

想要年薪20W+吗?看完Github上分享的Java并发题,面试大厂稳了

java专业爱好者

Java Java并发

爆场预警!百度大脑开放日-AI赋能软硬件产品创新

百度大脑

百度大脑开放日

SpringCloud Gateway 路由数量对性能的影响研究

中原银行

微服务 SpringCloud Gateway 中原银行

前端 JavaScript 之『防抖』的简单代码实现

编程三昧

JavaScript 编程 前端 防抖 函数节流

Flink State 和 Fault Tolerance

Alex🐒

flink 翻译 flink1.13

Nebula 基于 ElasticSearch 的全文搜索引擎的文本搜索

Nebula Graph

elasticsearch 索引 图数据库

优雅编程 | 7 个你应该掌握的 JavaScript 编码技巧

devpoint

JavaScrip 6 月日更

成为一个面霸需要面试多少回?

escray

极客时间 六月日更

为什么中间件协议对区块链生态系统至关重要?

CECBC区块链专委会

【21-10】PowerShell 日期和时间

耳东

PowerShell 6月日更

Taro3无埋点的探索与实践

GrowingIO技术专栏

taro AST sdk 无埋点 babel

很多小伙伴问我推荐什么书籍和网课,这次把私藏很久的资料都贡献了(上)

C语言与CPP编程

c++ C语言 数据结构与算法 Java· #python

SpringCloud Gateway 路由转发性能优化

中原银行

微服务 SpringCloud Gateway 中原银行

数字人民币是央行数字货币还是法定数字货币?

CECBC区块链专委会

🌏【架构师指南】分布式ID生成算法技术总结

李浩宇/Alex

分布式ID 6月日更 6 月日更

5分钟速读之Rust权威指南(二十四)Box

码生笔谈

rust

Leader修炼指“北”:管理路上的大小Boss

Leader修炼指“北”:管理路上的大小Boss

跨平台开发成本太高?Dropbox最终宁愿将代码编写两次-InfoQ