人物采访 / T SALON

编辑内容

Bill 谈跨端技术与工程师成长:从业务性能到渲染、标准和团队协作

回顾 2022 年 T Chat 第 15 期两段录播,串起字节跨端方案的演进、Lynx 与 Flutter 的选型边界、架构分层和性能挑战,以及 Bill 对技术探索、算法、方案评审和跨端开发者成长的看法。

T Chat 第 15 期 Bill 分享跨端技术与成长的访谈封面
T Chat 第 15 期 Bill 分享跨端技术与成长的访谈封面

本期视频发布于 2022 年。文中的技术状态、个人经历与观点均为当时情况。

跨端开发常被概括为用一套代码支持多个平台,但真正落到业务里,还要回答更多问题:页面多久出现,原生能力怎样接入,不同平台的表现能否一致,开发者需要重新学习多少东西,以及由谁维护这些能力。

2022 年 11 月发布的 T Chat 第 15 期中,Bill 先围绕字节的实践讲述跨端方案的演进,再与主持人讨论自己如何进入这一方向、怎样理解技术选型与工程师成长。技术分享约 34 分钟,成长对谈约 27 分钟。两段内容相互连接:前半场提到的架构、标准与性能问题,在后半场变成了个人应该学什么、团队应该怎样工作的具体讨论。

技术分享:跨端方案怎样被业务问题推动

从页面加载体验说起

Bill 首先把讨论范围放在跨操作系统的 UI 框架上:业务代码通过中间层接入不同平台,尽量减少开发者直接处理平台差异的工作。这不是说平台差异会自然消失,而是把一部分适配责任交给框架及其维护者。

他回顾,早期一些业务使用 Web 方案承载页面,随后在对体验要求更高的场景中遇到加载白屏、调用端侧能力的开销和功能定制等问题。活动页面尤其能体现这种压力:用户并不一定要进入这个页面,等待时间过长就可能退出,因此加载体验与后续业务行为直接相关。

他用春节活动解释这种影响:用户点击入口,先看到加载状态,等了很久仍没有进入真正的活动页面,就可能返回主流程。这个页面不是用户必须完成的任务,等待成本会直接影响其继续参与的意愿。加载速度因此不只是框架跑分,也关系到活动页面能否接住入口流量。另一个问题是定制玩法:搜索卡片、电商活动彩蛋或双十一倒计时,需要的端侧功能并非普通 Web 页面天然具备,业务和客户端要一起决定怎样提供。

这段叙述解释了团队为什么会继续寻找其他方案。它讨论的是 Bill 所经历的业务场景,不能据此把所有 Web 页面都归为性能不足,也不能仅凭访谈推算具体的用户流失率。

原生能力可以复用,性能目标仍要验证

接下来,Bill 讲到引入 React Native 的阶段。业务需要的定制组件、功能卡片等,可以由客户端开发者提前提供能力,再交给上层业务使用。这为跨端开发与原生能力之间建立了连接,也减少了每个页面都由两端分别实现的工作。

电商是他重点举出的例子。业务起步时,商品详情、提交订单等核心页面逐步迁移到 React Native;客户端团队可以预埋所需组件和端能力,让上层页面较快组合出功能。但迁移到新技术栈以后,业务侧又做了 A/B 实验。他回忆,页面进入耗时变长,GMV 等核心指标出现不理想的变化。技术栈带来的人效收益,必须再与真实页面性能和经营结果一起核算。

但支持功能并不等于满足全部业务目标。他回忆,一些电商核心页面在迁移后,通过业务侧实验观察到了进入页面耗时和业务指标的变化。这些具体问题推动团队继续建设内部跨端方案 Lynx。录播没有给出足以复核的完整实验数据,因此这里保留迁移决策的原因,不将其扩展成框架之间普遍适用的性能排名。

他也提到,Flutter 同期在发展,但对于已有大型应用,包体积和接入成本是需要考虑的条件。对独立应用、小团队而言,条件可能不同。因此,这段演进并不是所有业务依次更换同一种框架的过程,而是不同场景对性能、资源和开发方式提出了不同要求。

人效提升依赖提前建设的基础能力

在 Bill 的讲述中,跨端能减少重复开发,有一个前提:端侧组件、方法和基础设施已经具备足够的可用性。业务开发者能够顺畅地构建页面,是因为有人提前处理了跨平台接入、原生能力和工程工具等问题。

与此同时,习惯 HTML 和 Web 标准的开发者也有自己的需求。Bill 提到团队还会改善 Web 侧页面的呈现与加载,尽量让开发者保留熟悉的开发方式。跨端体系因此包含不同承载路径,而不是要求所有业务使用完全相同的表达方式。

他用搜索页面及活动页面说明这种变化。按其回顾,搜索页面经历过不同技术路径,团队也为加载失败准备过回退方式,并持续观察业务表现。春节、世界杯及需要快速响应的专题页面,则体现了跨端方案对迭代速度的价值:客户端开发者提供基础,上层业务开发者根据活动需要组织页面和交互。

搜索页面的顺序尤其清楚:先是原生实现,后来改用 React Native,未成功加载时留有 Web 兜底;再迁到 Lynx 后,Bill 称相关业务数据与原生时期基本打平。这是他在分享中描述的业务观察,不是公开的完整对照实验。他还展示春节活动与当年的世界杯入口:这类页面玩法多、调整快,既要保证用户打开后的体验,也要让产品和业务团队能够及时修改内容。只有端侧基础设施、上层页面生产和必要的回退方式一起工作,跨端的人效才可能兑现。

他还回忆了 2020 年初与疫情有关的专题页面,当时内部方案刚起步,页面却需要尽快上线。这个例子与春节促销和世界杯活动不同:紧急信息页面首先要赶上发布时间,若每次调整都依赖客户端发版,交付节奏便跟不上。三类页面各有目标,却都要求底层方案让上层业务及时组织内容,同时让端侧保持可接受的加载与展示效果。

这些例子的共同点是,框架能力必须与页面的交付方式一起看。性能、快速更新和特殊功能都可能成为选型条件;一个场景中的收益,并不自动适用于另一个场景。

团队职责变化,最终会落到架构分层

业务页面由前端开发者更多地承接之后,客户端开发者的工作会发生变化。Bill 并不认为这意味着客户端能力不再重要。相反,原生功能定制、稳定的基础接口和技术架构建设,是上层能够快速开发的条件。

他据此解释了一套分层思路。最上层是面向业务开发者的 DSL,即开发者用来描述界面与逻辑的表达方式;中间的端能力层承接业务定制、预加载、缓存等需求,也包括桥接、资源处理与监控等通用能力;再往下是执行逻辑和组织渲染的引擎,最终落到 iOS、Android 等平台完成界面绘制。

端能力层的一个设计目标是可插拔。不同宿主应用和业务环境有不同要求,框架需要给定制保留位置,同时避免把每个业务特例都塞进共同的底层。平台渲染部分则要承担差异处理:布局、组件行为和执行顺序不完全相同,维护者需要让上层的同一份描述尽可能得到一致的结果。

Bill 顺着一份页面描述走过这几个层次:业务开发者先选择熟悉的写法组织 UI;端侧中间层接住通信、预加载、缓存及业务自定义组件;引擎处理执行和渲染指令,最后由系统与 GPU 完成画面。每一层都可能成为性能或一致性问题的来源。例如同一布局规则在 iOS 与 Android 上的处理次序不同,若中间层没有消化差异,业务就会出现越来越多的平台判断。若为每个特殊业务直接修改底层,引擎本身也会变得难以维护。分层的意义正在于把这两类变化留在合适的位置。

这也改变了开发者需要理解的知识。前端代码一旦参与端侧界面构建,就应关注 CPU、内存与稳定性;客户端开发者也可以进一步理解上层业务如何组织。Bill 希望两侧人员扩大自己的视野,理解对方的约束,减少跨边界协作中潜在的问题。这是对能力融合的建议,并不意味着两类岗位原本就缺少相应能力。

三类挑战:开发习惯、平台差异与端侧计算

讲到瓶颈时,Bill 首先讨论 DSL 与开发者群体的关系。React Native、其他跨端框架及 Flutter 的开发方式并不一样,开发者进入新方案时,需要付出不同的学习和生态建设成本。他特别重视既有开发习惯:语言和组件体系换了,原来的工具、经验和社区资源能复用多少,也要一起计算。

这部分包含他在当时对生态路线的判断。更适合保留下来的选型问题是:方案面向谁,团队已经掌握什么,需要补齐哪些能力。不能把一次访谈中的评价写成对某个框架今天普及程度或社区活跃度的结论。

第二类挑战是平台不一致。每增加一个平台,都可能带来新的兼容工作,成本既由框架维护者承担,也会传递给业务开发者。Bill 肯定 Flutter 自行承担渲染工作的思路,认为它有助于减少渲染层差异;同时,他也指出跨平台仍然存在其他需要处理的不一致,不能把自绘等同于消除所有平台差异。

第三类挑战是端侧计算。界面描述需要解析、计算和绘制,逻辑层与平台层之间也需要交换数据。低端设备的资源约束,会让这些工作更容易成为性能问题;高端设备即使有更多核心,也需要合适的线程设计才能使用这些能力。这里讨论的是值得分析的开销来源,而不是把所有白屏或卡顿都归结为同一个原因。

Bill 将“多端一致”与“计算负担”分开讨论。自绘能够减少对两个系统原生控件和绘制行为的依赖,但平台的输入、资源、系统能力仍不可能完全一样。与此同时,跨端框架从上层逻辑传送数据到端侧、再构造和更新 UI 树,都会消耗算力。他以低端设备易感受到卡顿为例,提出一方面优化层间通信,另一方面重新考虑线程如何利用高端设备的多核资源。不能只看最终画面是否相似,也要看达到相似效果用了多少端侧工作。

标准与社区,决定方案能否长期使用

面对这些挑战,Bill 将遵循标准和拥抱开发者放在重要位置。面向前端群体的方案,如果大量偏离他们熟悉的规则,就会不断增加使用成本。分享中,他把对齐 Web 标准作为方向,同时承认当时的具体实现尚有差距;这是建设目标,不能改写成当时已经完全兼容的功能承诺。

社区则让使用者有机会反过来改善方案。框架团队无法预先完成所有场景的能力建设,使用中的反馈、共同维护和生态补充,都影响方案之后如何演进。对 Bill 而言,框架的好坏最终需要接受实际开发者的检验。

他也展望了移动端之外的屏幕与交互场景,包括桌面和新的终端设备。如果渲染层能够提供更统一的能力,上层业务就可能更容易扩展到其他环境。他同时提及 WebAssembly 作为值得关注的执行技术方向。这些内容属于当年的探索和判断,并不证明某条路线已经解决了多终端的全部问题。

技术分享最后提出了三个相互连接的方向:上层允许不同开发者使用熟悉的 DSL;中间能力根据场景连接平台渲染或自绘等不同路径;底层尽量形成稳定的渲染指令表达。这样,某一层发生变化时,其他层不必全部跟着重写。这里保留的是他的设计思路,不是对某个具体实现迁移成本的保证。

他把上层的多种写法举得很具体:熟悉 React 的团队、熟悉 Vue 的团队,不应只因为底层采用同一个跨端引擎,就必须接受完全一样的业务语言。中间层要把这些输入转成可以处理的结构;渲染层再根据目标设备的能力选择平台绘制或自绘。Bill 希望渲染指令有稳定的表达,使未来增加桌面、VR 或眼镜等终端时,不必从每一种 DSL 重新起步。这里是面向未来的架构设想,新的输入方式、交互和系统能力仍然需要逐一适配。

为什么不直接采用 Flutter

分享结束后的观众提问,把抽象的选型问题拉回到具体团队。Bill 的回答集中在两个条件:成熟大型应用对包体积有较强约束;业务开发者还需要学习相应语言、DSL,并建设配套的工程能力。这些投入可能影响接入决策。

主持人随后追问,小型团队是否面对同样的负担。Bill 明确补充,独立应用和探索型业务可以有不同选择。他回顾 Flutter 在一些独立应用中的使用,认为它能够帮助团队较快地构建双端相近的业务并进行验证。不能只截取前半段的限制,而遗漏后半段认可其适用场景的回答。

成长对谈:从理解渲染到形成自己的工程判断

选择跨端,既来自业务,也来自对底层的兴趣

第二段开始,主持人问 Bill 为什么选择跨平台方向。Bill 回忆,早期在滴滴探索 React Native,与团队希望改善双端一致性、提高研发效率有关。对于他个人,这个方向还提供了一个深入理解渲染的机会:开发者写下的代码,经过哪些步骤,最终变成屏幕上的内容?

在他看来,不同设备和交互形式会变化,但围绕界面构建与渲染的基础理解可以继续使用。选择一个方向,也可以是在寻找能够支撑后续迁移的知识,而不只是追随某个框架的热度。

谈到成长阶段,他没有给出一张按年限划分的晋升表,而是讲述问题怎样推动自己继续学习。早期落地跨端方案,让他感受到双端差异和兼容工作的困难;之后研究 Flutter,又使他看到另一种处理渲染的思路。随着端能力建设和方案研究增多,他逐渐从单个模块走向整体架构,思考各层应该负责什么、哪些环节值得优化。

这里的学习不是照搬某一个方案,而是持续追问它解决什么问题、给实际业务和使用者带来什么价值。遇到新方案时,先理解它为何这样设计,再考虑可借鉴的部分。

兼容代码里的困难,是进一步探索的起点

观众随后问到滴滴的自研方案。Bill 将回答重点放在平台差异上:如果开发者需要在业务代码中不断判断当前平台,跨端带来的便利就会被这些兼容工作抵消。因此,他希望未来能够在更底层继续探索,减少差异传递到业务层的程度。

Bill 提到早年方案中可见的条件分支:一段本该描述业务界面的代码,若不断出现“若是 iOS 则如此、若是 Android 则那样”,维护者实际仍在分别处理两端。主持人的问题问的是一个具体项目,Bill 却把回答引向通用的设计边界:与其让每个页面重复判断,不如尽可能在渲染或基础能力层找共同的表达。这个方向也解释了他为什么持续关注 Flutter 的自绘思路,同时仍坚持为开发者保留熟悉的上层写法。

主持人把问题进一步转向职业初期。Bill 的建议是多尝试不同方案、了解不同原理,再通过自己的实践形成判断。他不鼓励把别人给出的结论直接当作自己的答案;比较、验证和反复思考,才会逐渐形成个人的技术观点。这也解释了他前面为什么从具体项目一路谈到架构和渲染。

Lynx 的定位与重复建设的边界

当主持人问 Lynx 在体系中的位置时,Bill 再次强调了适用场景。他描述的重点是性能诉求较高的页面和重要活动,并非所有页面都需要使用同一套方案。Web 场景仍有自己的路径,缺少大规模基础设施建设资源的独立应用,也可以选择其他成熟方案。

讨论由此转向重复造轮子。Bill 给出的区分是基础能力与业务定制:共同的底层能力应该尽量统一,但不同业务的服务、流程和优化需求可能不同,在相应层次做定制有合理性。不能只因为出现了两套相近的代码,就跳过它们所处层次和解决的问题,直接下结论。

他也提到,不同业务环境的隔离要求可能影响实现组织。这里呈现的是访谈中的分层原则和当时观察,不据此声称掌握公司内部所有系统的实际关系。

标准支持会增加工作,也能减少使用者的负担

关于 CSS 支持与开发体验的提问,让 Bill 进一步解释了标准问题。他承认当时仍有未对齐之处,团队也在继续改进解析及相关基础能力。主持人追问:支持更多规则,会不会使框架越来越重?Bill 的回答是,能力增加确实需要相应实现,同时还要通过架构梳理控制开销。

为什么仍然要做这件事?因为不兼容的成本会转移给业务开发者。一个人进入新团队后,如果必须重新学习一套只在本公司有效的开发规则,其已有经验和工具就难以复用。Bill 因此把标准建设看作长期使用与生态发展的条件,而不只是功能清单上的一项。

这一问答把框架体积和开发体验之间的取舍说得更完整:减少实现能降低某些成本,但也可能让更多人承担额外的学习、迁移和维护工作。

关注新路线,仍然先看它要改变哪个环节

主持人问到近期关注的技术时,Bill 提及美团围绕 Rust、WebAssembly 与跨端执行方式所做的尝试。他关注的是逻辑执行、层间通信与原生渲染之间的组织方式,以及新方案试图改善现有路径的哪些问题。

这一段体现了他观察新技术的方法:把新名字放回执行流程,讨论它替换或改进的是哪一层。录播并非完整架构文档,没有提供具体组件名称、性能数字或今天的实现状态。

算法训练与跨端工作有什么关系

在个人经历部分,Bill 回顾自己于 2019 年初进入字节,并谈到当时面试中对算法能力的关注。他也说明要求会随时间变化,重点在于基本思路和清晰的解题过程。这是个人对当时经历的回忆,不是现行招聘题型或通过标准。

更具体的讨论发生在工作应用上。跨端开发需要处理 UI 树的遍历、更新以及其他数据结构问题,算法知识并不只出现在面试中。主持人进一步问到树、图等方向,Bill 则不希望把学习限制为少数题型:不同算法提供不同的解决问题思路,基本的数据结构和分析能力都值得积累。

两人还逐项谈到链表、图、动态规划和贪心。主持人试着从渲染树出发,推断树和图类题目是否特别值得练;Bill 认可 UI 树确实会在遍历与更新中用到,却没有据此给出一份“只刷这些题”的清单。在他看来,算法训练也训练分析和选择方法的习惯,实际工作里的问题不会总按面试题型出现。访谈给出的可执行建议是持续练基础,而不是猜测某一类题一定对应某个岗位。

因此,他给出的建议不是寻找某种题目的捷径,而是在平时持续练习,既提升分析问题的能力,也为遇到实际工程问题时准备更多工具。

工程师文化,需要让方案讨论真正发生

谈到团队文化,Bill 建议学习成熟团队怎样提出想法、组织技术方案、开展代码评审,并推动方案落地。他特别关注评审是否真正促进理解与改进:如果只是走完流程,团队很难借此提高技术质量。

他用所在团队的方案文档做例子。提出一个需求时,要说明背景、目的和要解决的问题,也要考虑长期维护与测试。将这些内容写清楚,能让讨论围绕具体依据展开,并使后续人员能够追踪当时的选择与原因。

主持人提到 RFC 式的技术文档,Bill 接着说自己的团队也会用方案文档讨论需求:从背景、目标到测试和长期维护都要写进来。两人关心的不是文档格式,而是 idea 从提出到落地之间有没有真正的讨论。Bill 特别批评只点一下通过的代码评审;这样的流程虽留下记录,却无法发现问题或帮助工程师理解为什么要改。小团队不必照搬大公司的手续,也可以先从把问题和取舍写清、让评审有实质反馈开始。

这段经验的价值在于把工程师文化落实到可观察的工作方式上:问题有没有说清,方案有没有被认真讨论,记录是否能服务后续维护。它不要求团队复制某家公司的全部流程,也不应被理解成所有团队都采用相同制度。

后续成长:理解自己工作之外的约束

最后,主持人问跨端开发者怎样继续发展。Bill 再次回到前端与原生开发之间的融合:前端开发者可以理解客户端为什么关心内存和资源管理,客户端开发者也可以深入了解上层界面与业务的构建方式。

他希望开发者跨过岗位名称划出的边界,同时继续关注标准和设计。仅凭实现者自己的想法完成一套方案,可能让实际使用者付出很高成本。技术深入与理解使用者并行,才更容易把能力做成别人能够长期使用的工具。这与整场分享中反复出现的渲染、标准和开发者体验形成了呼应。

完整录播

查看本期原视频与分段信息:我在字节做跨端 →