【AICon】 如何构建高效的 RAG 系统?RAG 技术在实际应用中遇到的挑战及应对策略?>>> 了解详情
写点什么

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

  • 2019-08-19
  • 本文字数:2843 字

    阅读完需:约 9 分钟

跨平台开发成本太高?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-08-19 08:4927280
用户头像

发布了 680 篇内容, 共 384.1 次阅读, 收获喜欢 1495 次。

关注

评论 2 条评论

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

架构师训练营作业1-食堂就餐卡系统设计

索隆

官方源、镜像源汇总

JackTian

镜像源 官网源

软件设计原则作业

qihuajun

你了解 SpringBoot java -jar 的启动原理吗?

猴哥一一 cium

面试 Spring Boot Fat-JAR JAR URL Java 25 周年

ARTS打卡计划_第二周

叫不醒装睡的人

ARTS 打卡计划

架构师训练营第一讲-学习总结

索隆

国内首个区块链电子档案平台上线

CECBC

区块链技术 防伪 溯源 电子档案

软件设计原则学习总结

qihuajun

程序员陪娃系列——叛逆小娃回归

孙苏勇

程序员 陪伴

原创 | TDD工具集:JUnit、AssertJ和Mockito (二十一)编写测试-动态测试

编程道与术

Java 编程 TDD 单元测试 JUnit

Flink 源码分析之写给大忙人看的 Flink Window原理

shengjk1

flink flink源码 flink window

编程基础

南山

利用工作日志提高效率

Janenesome

思考 工作方式

愚蠢写作术(4):怎么让写作从开始到放弃

史方远

读书笔记 个人成长 写作 随笔杂谈

架构训练营作业-20200614

caibird1984

个人编程技能全景图

南山

【在云端 001】欢迎来到云原生

Bora.Don

云计算 云原生

1. 版本管理工具及 Ruby 工具链环境

Edmond

rubygems CocoaPods VersionControl PackageManager Git Submodule

Shell的技巧小总结(MIT Missing Semester)

AndersonKim

Shell MIT 计算机 Computer Science 计算机工具

ARTS Week 3

时之虫

ARTS 打卡计划

硬核!30 张图解 HTTP 常见面试题

小林coding

https 计算机网络 计算机基础 HTTP

JVM学习笔记——JVM类加载机制

王海

Java 面试 JVM

为什么软件交付要快?因为要有赢的感觉!

刘华Kenneth

DevOps 敏捷 MVP 最小可用产品 持续交付

大话设计模式 | 2. 策略模式

Puran

C# 设计模式

GoF 23种设计模式

无心水

设计模式 GoF 23种设计模式

仓储控制系统(WCS)软件可靠性设计

申扬科技

仓储控制系统 WCS 可靠性设计 容错性 易恢复性

ARTS Week4

丽子

小师妹学JavaIO之:用Selector来发好人卡

程序那些事

io nio 「Java 25周年」 小师妹 selector

B端产品经理养成记(4):敏捷项目

涛哥 数字产品和业务架构

敏捷 产品经理

使用 Docker 镜像 | Docker 系列

AlwaysBeta

Docker 容器 虚拟私有云

推荐几款有意思的小众 App(06.13)

静陌

产品 App

跨平台开发成本太高?Dropbox最终宁愿将代码编写两次_语言 & 开发_Eyal Guthmann_InfoQ精选文章