作者 | 抖音主框架团队 责编 | 张红月

出品 | 字节跳动技术团队(BytedanceTechBlog)

抖音 Feed 容器在推荐、关注、同城、朋友等多个场景中使用,每个场景都有自身的逻辑和业务,最终汇总在 FeedViewcontroller 中,随着业务的迭代,代码越来越臃肿,面临如下的问题:

抖音小程序开发需要什么基础(抖音iOS推荐)(1)

Feed 容器多场景下承载业务

Feed 容器承载了基础功能、直播、登录、登出、性能监控、预加载等多个功能。

由于之前没有做好管控,导致容器中业务相互耦合严重,业务边界不清晰,开发过程中稍有不慎,就会对其他业务造成影响。

抖音小程序开发需要什么基础(抖音iOS推荐)(2)

业务迭代效率低

由于代码都在容器类中直接修改,一个版本经常会有多个业务在容器中进行修改导致冲突的情况,此时就需要多方进行 review,保证改动不出问题,往往还要平台业务的同学进行支持,业务的整体迭代效率比较低。

抖音小程序开发需要什么基础(抖音iOS推荐)(3)

防劣化&监控缺失

业务耦合,对代码改动没有监控,导致 FeedViewController 越来越膨胀。因为没有合理架构导致无法做拆分,代码劣化越来越严重,而且基于现状无法进行防劣化。

抖音小程序开发需要什么基础(抖音iOS推荐)(4)

目标方案

为了解决上述问题,首先设定好目标,然后根据目标提出解决方案,最终落地实现,验证目标是否达成。

目标

思路

方案

针对 Feed 容器内部多场景、多业务耦合导致整体维护困难,新业务接入成本高的问题,首先按照场景、业务和功能维护进行拆分梳理。在拆分完成后为了方便各个业务进行维护,设计了 ControlerKit 工具实现了生命周期方法的分发,并且通过 Context 进行状态管理,实现了各个业务间的通信和状态维护。

抖音小程序开发需要什么基础(抖音iOS推荐)(5)

整体架构图

基础容器

Feed 基础容器,采用组件化框架,支持基础组件和业务组件的动态组合和扩展,由业务无关、统一的列表形态组成,通过数据驱动页面展现。同时对外暴露生命周期事件,方便组件进行监听。其中基础容器由平台方进行统一维护,并提供了完善的监控体系,方便进行问题的定位和追查。

基础组件

Feed 容器的基础组件部分,采用的方式是平台方统一进行维护。目前的基础组件,主要包括播放控制、播放策略优化、列表预加载以及页面管理等。

其中,全屏 Feed 相关的基础组件,为多业务共用,具备可复用、可扩展等优势。

业务组件

业务组件是和业务强相关的组件,业务方可以根据自身的需要进行灵活定制,组件本身可插拔,由各业务方进行维护。

应用场景

业务方基于 Feed 容器,组合业务组件和基础组件构建的页面,在构造过程中可以基于配置文件实现容器的定制,比如推荐和关注。

容器化工具

多个业务耦合在同一个容器中,导致容器类越来越臃肿,一方面造成各方同时维护越来越困难,另一方面对于新业务和新同学接入十分不友好,需要花费很多时间熟悉上下文以避免改动对其他业务造成影响。

为此设计了 ControllerKit 库,该库实现了复杂页面的分发,解决 ViewController 臃肿问题,规范代码拆分标准,提供分发方法的能力。各个接入方按照规则注册后,实现自己关心的生命周期方法,并在方法中实现对应的逻辑即可。

抖音小程序开发需要什么基础(抖音iOS推荐)(6)

ContainerViewController

ContainerViewController 是容器 ViewController,实现了 ContainerProtocol,保存了上下文环境,负责了各个生命周期方法的分发。

ContainerProtocol

声明了容器对外提供的属性和方法,方便各个 SubController 进行访问。

ControllerProtocol

声明了基础的声明周期和共有的方法。

Controller

Controller 是将 ViewController 中的代码拆分出来的子模块,可以接收分发出来的 viewDidLoad、viewWillAppear 等生命周期及自定义方法调用,还可以向 ViewController 中添加子 View。

ControllerManager

ControllerManager 负责 Controller 的注册、管理、方法分发。通过 classNameArray 返回 Controller 的字符串类名数组即可,可以支持 Controller 在其他仓库的能力

Manager 需要声明分发的 Controller 协议,只需要声明,不需要实现,Manager 内部会通过消息转发机制统一分发。

各角色之间的关系

ContainerViewController 实现了 ContainerProtocol,并持有 ControllerManager,各个子 Controller 注册到 ControllerManager 中,各个 Controller 可以通过 ContainerProtocol 访问容器的能力,ControllerManager 通过 ControllerProtocol 里面声明的方法进行分发。

比如:ContainerViewController 初始化后调用 viewDidLoad 时,会通过 ControllerManager 依次分发到实现该方法的 controller 中,各个 Controller 在自己的 viewDidLoad 方法中实现自己的逻辑即可。

Controller 优先级

Feed 容器的实现

根据 ControllerKit 对 Feed 容器的类结构改造如下所示

抖音小程序开发需要什么基础(抖音iOS推荐)(7)

基于 ControllerKit 的设计和实现

各个类和协议的介绍:

重构后业务迭代方式

抖音小程序开发需要什么基础(抖音iOS推荐)(8)

防劣化建设

为了防止随着业务的迭代,Feed 容器逐渐劣化,需要进行防劣化建设。首先进行框架和业务分仓:

抖音小程序开发需要什么基础(抖音iOS推荐)(9)

新方案优势

抖音小程序开发需要什么基础(抖音iOS推荐)(10)

接入示例

以下以兴趣选择和业务为例,介绍新老业务的接入。

新功能接入 - 兴趣选择

兴趣选择是新的类型的卡片,需要进行卡片注册并处理相关逻辑。

抖音小程序开发需要什么基础(抖音iOS推荐)(11)

历史方案

FeedViewController 直接进行修改,包括如下内容:

新方案

抖音小程序开发需要什么基础(抖音iOS推荐)(12)

存量功能拆分—Feed 监控

Feed 监控功能在 FeedTableVC 中处理了很多业务,而且这些逻辑也其他业务存在着耦合。

抖音小程序开发需要什么基础(抖音iOS推荐)(13)

采用新方案进行拆分

首先创建 FeedMonitorController,增加业务相关的属性、生命周期方法中实现对应的逻辑,之后抽取单独的业务 controller 在生命周期方法中处理熟人相关逻辑。同时注册到 controllerManager 中,并设置 AB、原有代码判断 AB。上线验证,全量后删除容器老代码。之后业务自闭环,再进行迭代时直接在 FeedMonitorControlle r 内容修改即可。

抖音小程序开发需要什么基础(抖音iOS推荐)(14)

抖音小程序开发需要什么基础(抖音iOS推荐)(15)

当前进展&后续规划

规划和节奏

抖音小程序开发需要什么基础(抖音iOS推荐)(16)

抖音小程序开发需要什么基础(抖音iOS推荐)(17)

重构后的收益

老容器新容器
因为业务耦合,需要了解 Feed 的结构和多业务的细节,新同学熟悉的时间需要 2 天左右;在实现过程中,由于多个业务同时进行迭代,相互影响,质量无法保障只需要在自己的业务 Controller 开发即可,无需关心容器的结构以及其他业务方,极大的提高了开发和迭代效率;改动不影响其他业务线的代码,保障了代码的稳定性

抖音小程序开发需要什么基础(抖音iOS推荐)(18)

— 推荐阅读 —

,