Airbnb公司自Swift语言诞生起就一直坚持加以使用。在这一过程中,我们通过亲身经历体会到这款现代化、安全且由社区驱动的新兴语言带来的各类助益。
直到最近,我们的代码库中有很大一部分由Swift 2编写而成。我们刚刚完成了面向Swift 3的迁移工作,刚好在新版本的Xcode放弃支持Swift 2之时。
我们希望与技术社区共享我们在迁移过程中积累的经验与心得、Swift 3为我们应用带来的提升以及期间值得一谈的技术性结论。
“无中断式开发”方法
我们有数十套模块及部分第三方库是由Swift编写而成,其中包括数以千计的文件与成千上万代码行。如果你认为如此规模的Swift代码库仍不足以构成挑战,那么这里要给大家提个醒——Swift 2与Swift 3的模块之间无法相互导入,这进一步提高了迁移过程的复杂性。即使是正确的Swift 3代码导入Swift 2库后亦无法编译通过。这种不兼容性导致我们很难以并行方式实现代码转换。
为了确保对代码进行逐步转换与验证,我们开始创建一套依赖性图表,其中以拓扑方式对我们的36套Swift模块进行了排序。我们的具体升级规划如下所示:
将CocoaPods升级至1.1.0(以支持必要的pod升级);
第三方pods升级至Swift 3版本;
按照拓扑顺序对我们的自有模块进行转换。
通过与其它已经完成此类迁移工作的企业进行沟通,我们意识到大多数项目需要在迁移时暂时冻结开发任务。我们希望尽一切可能避免对代码库进行冻结,即使这意味着会给迁移工作增添种种复杂性因素。由于转换工作本身很难以并行方式进行,因此所有已有的解决方案都存在效率低下的问题。另外,因为很难估计整个转换所需要的具体时间周期,所以我们希望能确保在迁移过程中继续发布App新版本。
整项迁移工作由三名工作人员负责。其中两位专注于代码转移,第三位则专注于协调工作内容、与团队沟通以及进行基准审查。
包括准备工作在内,我们设定的项目时间表如下所示:
1周:调查并筹备(1人负责);
2.5周:转换(2人负责),与主团队进行转换影响通报及交流(1人负责);
2周:QA与bug修复(QA团队与对应的iOS功能负责人);
Swift 3的影响
尽管我们对于Swift 3带来的诸多全新语言特性相当兴奋,但我们亦希望确切了解此次更新会给我们的最终用户以及整体开发者体验带来怎样的影响。我们密切关注Swift 3对发布IPA大小及调试build时间的影响,因为这一切是我们在使用Swift过程中的两大痛点。遗憾的是,在通过多种不同的优化设置实验之后,我们发现Swift在这两方面的表现仍然差强人意。
发布IPA的大小
在迁移至Swift 3后,我们发现所发布的IPA出现了2.2 MB体积增量。通过初步发掘,我们发现这几乎完全是由于Swift库自身大小的增加而导致(我们自己的二进制文件大小几乎没有变化)。以下为几项未压缩二进制文件未经压缩的体积增加实例:
libswiftFoundation.dylib: 增长233.40% (3.8 MB)
libswiftCore.dylib: 增长11.76% (1.5 MB)
libswiftDispatch.dylib: 增长344.61% (0.8 MB)
考虑到Foundation等Swift 3库得到的显著增强,这种变化也完全能够理解。另外,当稳定版Swift ABI发布时,相信这些应用程序将不再需要因上述强化而遭遇体积增长的问题。
测试版Build时间
在迁移完成之后,我们的测试版build时间延长了4.6%,即在原本6分钟的基础上增加了16秒。
我们尝试比较了Swift 2与Swift 3之间的各函数编译时长,但却无法得出具体结论——因为二者间的格式存在很大差异。不过我们确实找到了一条函数,其编译时长在迁移之后激增至12秒。幸运的是,我们通过调整将其编译时间还原到了正常水平,但这也证明了检查转换代码的重要意义。Build Time Analyzer for Xcode等工具能够在这方面帮上大忙,当然大家也可以设置合适的Swift编译器标记并解析build结果日志以达到类似的效果。
运行时问题
遗憾的是,虽然代码已经在Swift 3中全部编译完成,但迁移工作仍未彻底结束。Xcode代码转换工具并不能保证实现完全相同的运行时行为。另外,正如我们在后面所提到,代码转换仍然需要人工介入并且里面有一些坑。这意味着我们恐怕还需要通过回归测试将其解决。由于我们的单元测试覆盖率不足以提供充足的信心,因此我们不得不花费额外的QA周期以审查新近迁移完成的应用。