不少前端团队都面临着独石应用的工程巨大、理解困难和合作混乱的种种问题,微前端或许是一种比较好的解决方案,它允许我们为应用加入新功能而不影响整体结构。但同时,我们可能会付出一些代价,例如重复依赖、团队自治带来的工作方式分散等问题。采用微前端具体有哪些风险与挑战?我们应该如何应对?如何判断自己的团队是否适合微前端?不妨来看看 字节跳动在落地微前端的过程中的踩坑填坑经验 。
许多企业都从微服务中尝到了甜头,但是你是否想过,微服务模式的火在某一天也会烧到前端?
2019 年 4 月,ThoughtWorks 技术雷达将微前端纳入了 ADOPT 阶段,该阶段代表 ThoughtWorks 认为该项技术或者模式值得被行业采用。
在微前端方案中,Web 应用程序被分拆为多个模块,每个模块可以独立开发、部署和测试。好处显而易见,与微服务相似,松耦合允许我们更改一个模块而不影响其他模块,微前端可以减少团队间的依赖,增加灵活性。但缺陷也十分明显,作为一个更分散的架构,微前端不可避免地导致我们需要管理更多的库和工具,这增加了运维复杂性。另外,如果不同开发团队使用不同的技术栈,也会带来许多复杂的问题。
字节跳动微服务前端解决方案,经过几年发展已经成功支持了几十个对内和对外的系统,在此过程中,他们收获了哪些果实?遇到了哪些难点?具体如何应对?带着这些问题,InfoQ 采访了 字节跳动前端工程师艾石光 ,希望能给即将或正在走上微前端之路的你带来一些可参考经验。
艾石光:微前端的理念就是用微服务的模型去重构前端工程。微服务是一种设计模式,已经作为在软件工程行业近年发展最快的趋势和特征,被充分验证过和实践过了。也深入影响了从语言到环境的方方面面。但是在前端工程里,浏览器是一个很独特的运行时环境,和部署在操作系统上的服务端应用有不小的区别。前端目前有种种隔离技术在快速发展、有一些方便模拟操作系统性质的实践,但还没有对应的底层机制,也没有可以达成标准级别的整体进展。微前端是在享用和微服务相同的工程理论的成果的同时用适应前端特征的方式去做微服务化。
艾石光:作为微服务模式的一个特殊发展,前端微服务可以有很多不同的导向。例如有些侧重优雅耦合有些重视运行时隔离。从具体的组成部分来说,很多环节都有多种方案可以取舍。
对前端运行时架构来说,有几种不同的沙盒组织方式,例如变量守护、IIFE、利用 prototype 链条包装 global 等。对 CSS 隔离与复用架构来说,还可以用 shadow DOM、CSS Module 等。
对服务发现和托管部署服务,可以用流量层打通和额外 list 接口等。
对应到开发环境和调试服务,同样有很多的调试测试解决方案、工具集,具体可以在演讲中讨论。
艾石光:Web Component 作为前端 DOM 层的一种拆分和隔离机制,其实是一个很有效的技术方案。我们的设计里也在尽可能的吸收这方面的理念和技术。进而把“前端”作为整个工程来说时,独立和隔离只是众多议题中的一步,还涉及到通信、复用、多态等诸多环境。同样重要的还有框架同构和异构、环境一致、服务发现和治理等等。这些需要更精细更成体系的工程模型来协调处理。
字节跳动的一些业务例如头条号,很久之前就发展到一个代码仓库庞大到发布时间超过半个小时、新人加入非常难上手的程度了,也一直在摸索各种解决方案、组织方法。在 2 年前刚好遇到业务发展产生了一个新的时机:这个项目开始需要跨大团队的组织协同,多个团队一起建设。这些合作的开发者来自不同结构、不同流程、甚至不同地区的组织。这时再一起来合作同一个前端项目,如何高效的拆分、优雅的复用等等工程问题成了解决效率敞口最重要的手段。
艾石光:前端微服务最明显最适合落地的场景是各种中后台项目,尤其是那些传统的 iframe 工程。实际试用过 frames 开发架构的同学会知道真的使用时,如何打造实用可理解的 deeplink 就已经很麻烦了。况且还有很多技术细节。比如那些底层复用、父子通信、session 打通、服务发现等。实际上已经默默承受了很多在微服务里解决得很好且最终效果可以好得多的问题。
前端微服务需要解决的难题涵盖了从集成开发环境到服务转移到部署和流量识别和承载的后端架构,具体涉及到的面很广,细节还是很多的。
我们团队把前端微服务抽象成了服务发现、运行隔离和环境一致三个方面,分别对应了了从开发到发布到线上运行的全部环节。
艾石光:最大的好处肯定是开发效率上的,很多多余的认知成本、协作成本都被消除了。
其次是上下线的效率提高了非常多。之前的统一发布模式需要耗费 30 分钟上线、10 分钟回滚,这很难适应一些业务变化。例如头条号平台从 19 年到今天各模块共有 4292 次创建版本,这些版本还会组合出无穷种 A/B 测试的可能。这些都是传统的发布管理机制很难胜任的。
在工程质量上,通过微服务化有很多底层 / 中台能力都可以由 masterpage 内置,有一些数据采集和回收可以在服务发现平台上布置,例如 sourceMap 的权限管理、console log 的回收都可以统一由 masterpage 安排、业务方无感知。这都是一些收获。
艾石光:前端微服务整体上的安全性和可控性还是比较不错的。但是如前面所述目前还没有标准和底层深入支持,所以也新产生了很多独特挑战需要去应对。我觉得最值得提的新引入风险还是来自开发调试过程。
我们认为 docker 等技术是服务端微服务的一个重要优势,容器技术的成熟使微服务在线上线下有非常一致的环境表现。而前端更接近非容器的、类似于各种 BaaS 的模式。像 firebase、GAE 等不借助容器的微服务体系都有整套的调试解决方案和运行监控数据回收方案,可以保证部署前有条件充分调试,也有可靠的测试,能先测试再部署。而微前端的本地开发的环境与调试用的代码和最终上线运行会有不小的区别。不仅如此,线上合并后的环境变化极快,其他平行的模块加起来更新频率非常高。所以这时发现和复现问题都是一个重要的环节。
我们也提供了很深入的解决方案,投入了很大的研发精力去应对这个挑战。我们建设了完整的开发链工具,比如配置代码的修复和消毒,还有融合云打包的脚本植入、自动化验证等。调试方面有整套的代理服务植入到开发环境的浏览器内,有独立的调试命令也有充分与 webpack-dev-server 结合的方式。这些一起实现了让使用者开发时,虽然写的代码仅仅是寄生在 masterpage 内的代码片段,但是开发体验几乎和传统的页面开发完全一致、开发环境看到的运行表现也几乎完全模拟线上。
其次是服务发现过程的模块上下线,是一个需要小心对待的需要极高可用性的中心系统。对此我们做了从 ETCD、Redis 到前端 localstorage 的多层容灾。为了更好地支撑流量,我们还在进一步尝试更多的部署架构。
另外我们也做了更详细的线上错误回收,并且打通到了用户反馈系统。在我们微服务框架里的 console log 都会被收集和整理,并且一起储存时会自动装载上 call stack。
艾石光:从技术角度上说如果你开始观察到工程的组织需要费心去设计才能继续保证直观和优雅,尤其是对非主要作者的开发者来说,如果必须要额外的交流介绍、探讨、商量、协调,才能解释清楚一个项目的设计思路和构造,就应该开始考虑用不同级别的拆分模型来处理你的项目了。
如果你的团队有技术异构的诉求,例如不同的编译机制、不同的逻辑层实现、不同的展示层框架,又不希望降低项目的复用度和运行时的流畅,也可以考虑以解耦的角度去尝试微服务。
最后一个更普遍的情况是,如果你的项目上线非常频繁,变化很多,大量的时间消耗在反复的编译、部署里,对应的一定有更多的时间消耗在单测和验收过程。这时也建议从微服务角度去重新考虑。
采访嘉宾:艾石光,字节跳动前端工程师,加入字节跳动以来一直致力于发展和建设前端基础工程,包括基础设施建设、业务工程与过程的改进和打磨。与团队一起,在为公司业务提供中台产品的同时,也在努力提升公司前端团队的研发效率与工程质量。至今,已经成功打造了微服务技术体系、富媒体中台框架、服务迁移工具等产品。艾石光一直活跃在前端开发领域,在加入字节跳动之前,曾经在阿里巴巴和 CRIC 等企业参与前端开发,有丰富的工程化产品、技术中台和研发框架的打造经验。他将在QCon 上海 2019 作题为《前端微服务在字节跳动的打磨与应用》的演讲,带你了解微服务在成熟产品上的实践、发展历程和逐年打磨沉淀的技术细节,点击了解详情。