版权所有,转载请注明出处。
最近在前端圈大名鼎鼎的 Airbnb(爱彼迎)团队宣布放弃 React Native。他们在自己的博客的中写了一系列文章详细介绍了使用 React Native 的开发经历,解释了放弃使用 RN 的原因。本文就是对这些博文的整理和翻译。
由于篇幅较长,我拆分成了上下两部分,以下是下篇:
打造跨平台的移动开发团队
通过对 React Native 的深入实践,我们深切地意识到它对一个大规模的开发团队意味着什么,而不仅仅是 React Native 本身众多的优点和缺点。将一个新的库或者开发模式引入到现有的平台中是比较简单的,但是从中剥离出一个来要复杂得多,这样做会带来很多组织级别的难题。这些难题不像是我们每天遇到并解决的普通技术问题,它们难以察觉、修正或者从中恢复。幸好 Airbnb 有健康的团队文化,但是关于 React Native,我们仍然有许多需要考虑的东西。
对 React Native 评价的两极化
我们发现,在对 React Native 作简单了解后工程师们对它的评价非常两极化:一部分工程师认为 React Native 就是解决 Android,iOS 和 web 跨平台开发问题的“银弹”,另一部分则认为它糟透了,并且抗拒在他们的团队中推广。在深入使用 React Native 后这样的分歧仍然存在,有些人觉得基于 React Native 开发体验不错,而另一拨则非常后悔使用它,强烈要求回滚到原生开发模式。
难以定位问题的根源
使用 React Native 开发时,会遇到很多常见的bug,异常和性能问题。但是也会有不确定的因素:
- React Native 本身的更新十分频繁。
- 我们在同时开发业务和基于 RN 的基础架构。
- 所有的工程师都要从头一起去学习 React Native,几乎没有人有相关的经验。
- 我们关于如何在开发或者生产环境调试的文档常常和实际不一致,阅读起来很困难。
由于这些问题,我们经常难以定位一个问题的根源。有时候,我们不知道一个异常应该分配给哪个团队,或者确定是不是 React Native 本身的 bug。
React Native 仍然是原生的
一个对 React Native 很大的误解是它可以让我们彻底摆脱原生编程,但是至少目前来看还不现实。React Native 使用的原生组件仍然扮演着非常重要的角色。比如说,text 在不同的平台上渲染效果有细微的差别,键盘的行为也不一样,在 Android 上,页面每次进行重力旋转都会被重新创建。良好的 React Native 开发过程必须在不同的平台上达到一定的平衡,考虑到同时熟悉 iOS,Android 和 Web 三个技术栈对工程师要求很高,因此基于 React Navtive 同时做到多个平台高质量的持续交付是非常难的。
跨平台的 Debugging
大多数开发只对一两个平台比较熟悉,同时对 Android,iOS,和 React 都熟练的工程师更是少之又少了。尽管在一个成熟的 React Native 项目中,大部分工作都是使用 JavaScript 和 React 来完成的,但有时候我们仍然需要在原生模块中定位问题。当这样的情况发生时,我们的工程师常常被迫在一个他们完全不熟悉的平台中去 debug,更糟糕的是,有时候开发都不能确定是哪个平台发生了问题。
招聘
尽管我们向 React Native 投入了大量精力,但是 Airbnb 在移动端的技术积累也在同步进行,并没有中断。我们也在一直澄清这一点,但是人们还是逐渐将 Airbnb 和 React Native 联系到一起,有的人甚至觉得我们的 App 是 100% 基于 React Native 的。基于这种不真实的印象,很多 iOS 和 Android 工程师不再愿意给我们投简历了!如果你恰好是其中一个,那么我们仍然在招原生开发!
混合编程是个坑
纯原生开发和 100% 基于 React Native 开发都很直接简单。但是当你把两者进行混编时,麻烦就来了:如何分割团队?不同团队之间怎么协作?原生和 JS 如何共享状态?如何保证所有代码都被测试了?跨平台开发怎样进行有效率的 debug?如何决定新功能用原生开发还是 React Native 开发?如何在组织内分配开发资源?如果你选择了混合编程,这些没有头绪的问题就会接踵而至。
三个开发环境
为了成为一个高效的 React Native 工程师,你必须在自己的电脑上同时搭建 React Native,Android 和 iOS 三个环境。像 Airbnb 这种规模的开发团队,每个平台的环境都必须花费大量的精力去搭建,学习并且保持最新。如果你休假了几个礼拜,回来的时候往往要花大几个小时去升级环境。
在原生和 React Native 之间平衡
很多情况下,一些模块使用原生开发或者 RN 开发各有好处。比如说,我们的导航控件非常依赖 Activities 和 ViewControllers 的一些特性,它实现的一大部分也是基于各个平台的原生代码。有时候我们不太清楚一个功能选择使用原生开发还是 RN 开发会更合适,所以工程师往往会选择他们更熟悉更擅长的平台去编码,但这样并不总是最优选择。
跨平台的测试
我们发现工程师总是基于自己的喜好或者体验来选择在哪个环境开发测试。通常来说,他们会默认如果在当前平台测试 ok 了,那么在别的平台也能完美运行的。大部分情况下都没有什么错,因为这正是 React Native 提供的特性之一,但是还是由足够多的案例表明,缺乏跨平台的测试会导致后续出现很多问题。
分割团队
原生开发团队和 React Native 团队各自都面临着技术和交流上的挑战。一旦工程被分割成原生和 RN 两部分,代码就会变得碎片化。在不同模块间共享代码逻辑,模型,状态等等变得很困难,而且程序员不再对整个工程都了如指掌了。我们一开始就预料会遇到这种麻烦,也推测随着时间的推移,移动端团队和 web 开发团队的深入合作会对情况有所改善。但事实上,只有一小部分团队开始在 web 和 移动端之间共享代码和资源,大部分都没有意识到这样做的好处。
主观感知的开发速度
我们使用 React Native 的一个主要目标是加快我们的开发速度。一般来说,一个 React Native 的 feature 会由一个工程师来负责编码,而不是每个平台都分配一个。从他们的反馈来看,虽然总体开发时间比在两个平台各写一遍要少,但是如果用 RN 开发消耗的时间超过了单独在 iOS 或者 Android 上开发时间的 50% 以上,那么在主观上,工程师还是会觉得用 RN 写代码更耗时。
社区、资源和文档
Android 和 iOS 都有十年左右的发展历史,在网上可以找到无数的开源代码,学习资料,遇到问题寻求帮助也很容易。我们自己也发布了很多教程比如CodePath来帮助初学者学习 Android 和 iOS 开发。尽管 React Native 有最大的跨平台开发社区和相关的资源,但是和 Android iOS 比起来,还是规模太小了。所以我们不得不自己开发大量的 RN 基础架构,并且需要投入很多资源做教育培训工作。
日落计划:放弃 React Native
现在业界有很多开发团队决定转向 React Native,并且在可预见的未来都计划使用 RN 来开发。但是对 Airbnb 来说,React Native 并没有帮助我们达成最初设定的目标,而且我们还面临着一系列尚未解决的技术和组织上的问题,这些都让我们继续投入 React Native 变得困难重重。
因此,我们最终决定 放弃使用 React Native,重新投入到原生开发中去。
React Native 没有达到我们的目标
快速迭代
如果一切顺利,工程师使用 React Native 开发的效率是非常令人满意的。但是在实际开发中,我们常常被上文提到的一系列技术和组织上的问题束手束脚,项目意料之外延期也是家常便饭。
保证产品质量
最近,React Native 本身变得越来越成熟,我们也积累了很多开发经验,完成了许多一开始没有把握的事情,比如说共享元素变换,视差滚动等等。我们还用非常 hack 的手段优化了几处页面掉帧的问题。尽管如此,我们还是没有搞定几个主要的技术问题,比如 RN 模块的初始化时间和页面首帧的渲染时间等。内部和外部关于 RN 资料的欠缺让解决这类问题变得更加困难。
只需写一份代码
大部分用 React Native 开发的代码都可以在几个平台共享,但是我们的 App 产品线只有一小部分是基于 RN 的。因此,我们需要构建大量的桥接模块,来保证业务工程师的开发效率。最后的结果就是:我们耗费了大量心血去开发了支持三个平台的代码。我们一开始就意识到在 Web 和移动端共享代码的巨大潜力,但实际上只有少数 npm 包可以完美地兼容这两个平台。
提高开发体验
使用 React Native 的开发体验真是一言难尽。在某些方面,比如build 时间,RN 的表现相当完美;另一方面,在 js 代码中 debug 问题,体验就相当糟糕了。具体的缺点,我们在上文中已经列出来过了。
日落计划
由于 React Native 没有达到我们的目标,我们决定废弃使用它。目前,我们正在制定一个过渡计划,首先是停止一切正在使用 React Native 的新功能的开发,在年底前,我们会将流量最大的几个页面重新用原生来代替,正好有些页面本来就要进行重新设计。我们的原生开发团队会在 2018 年继续支持 React Native,但是到2019年,我们会逐渐放弃对 RN 模块的支持,减轻例如首次加载时间这样的缺点对 App 的负担。
在 Airbnb,我们非常重视开源精神。我们使用了很多来自世界各地的开源框架,并且也在向它们贡献源码,其中也包括许多 React Native 框架。鉴于我们准备放弃 RN,所以以后我们不会再继续维护这些代码了。为了 RN 社区的良性发展,我们决定将这些慢慢框架迁移到 react-native-community 这个仓库中,我们最近在着手迁移 react-native-map,后续马上会开始弄 native-navigation 和 lottie-react-native.。
并不是一无是处
尽管 React Native 没有达到我们的要求,但是使用 RN 开发的工程师们总体上对它还是持有积极的态度。我们对这些工程师做了统计:
- 60% 的工程师认为他们使用 RN 开发的体验非常好。
- 20% 的工程师感觉还不错。
- 15% 的工程师认为体验一般般。
- 5% 的工程师认为体验很糟糕。
63% 的工程师认为有机会的话他们仍然会选择 React Native 来开发 App,74% 的工程师在一个新项目中会考虑使用 React Native。
当然,如果统计只是针对那些只使用 RN 带有强烈倾向性的工程师的话,这样的结果就没有意义了。作为参考,这些被采访的工程师一共写了超过八万行 js 业务代码,220 多个页面,和四万行的基础架构代码,而在每个原生平台的他们开发的代码量大概是这个数字的十倍,页面数是四倍左右。
React Native 正在快速发展
在上文中我们总结了目前为止使用 React Native 开发的一些经验。Facebook 和 React Native 社区正在投入大量精力使 RN 对跨平台开发更加友好。React Native 正在比以往任何时候都快地发展。在过去的一年中,git 上就有超过 2500 次提交。Facebook 刚刚宣布他们正在着手解决我们面临的几个主要技术问题。尽管我们不再使用 React Native 了,但是我们会持续的关注社区的发展,因为 React Native 的胜利不仅仅是技术的胜利,对每个使用我们产品的客户来说也大有裨益。
一些想法
我们将 React Native 整合到现有的大型 App 中,并且持续快速地不断演进。很多我们遇到的困难都是由于选择了混合编程的方式。但是团队的大体量允许我们可以投入精力解决许多棘手的问题,这是许多小公司不具备的条件。使 React Native 页面和原生页面能无缝衔接是可以做到的,但是非常困难。每个使用 React Native 开发的团队都会遇到各式各样的问题,这和团队现有的组织情况,产品,技术要求以及 React Native 本身的属性相关。
React Native 在某些方面会表现的很好,甚至超出我们的期望,比如迭代速度,质量,开发体验等等。有时候会让我们感觉自己处在移动开发变革的中心。尽管这非常鼓舞人心,但是作为一家成熟的企业,我们认真权衡利弊,还是觉得 React Native 目前并不适合我们。
是否采用一个新平台来开发产品可能是技术团队要做的最重要的决定了,这要根据团队的具体情况来作考虑。许多我们的经验和理由对你自己的团队可能不适用。实际上,很多公司仍然在顺利地基于 React Native 来开发产品,对许多其他公司而言,RN 也是最佳选择之一。
虽然我们从来没有停止继续开发原生代码,但是放弃使用 RN 后,我们能腾出更多资源使原生的体验更上一层楼。我们会在后续的文章中讲讲在原生领域的新计划!