随着 Facebook、Twitter、微博的崛起,向 UGC、PGC、OGC,自媒体提供平台的内容消费型 App 逐渐形成了独特的客户端架构模式。与电商和通讯工具类 App 不同,微博客户端具有多信息流、内容丰富多样、对数据量和延迟敏感等特点。微博的信息流承载着文字、网页、照片、视频、直播等多样的内容形式,所以复杂信息流对团队的开发效率、App 的性能都带来了极大的挑战。
2016 年 6 月 24-25 日, GMTC 全球移动技术大会将在北京举行。本届大会,我们邀请到了新浪微博移动端资深研发专家邱晨老师。曾就职于 Facebook、Storm8、Twitter 的邱晨老师,将在本届大会上分享《微博复杂信息流的架构之道》,与大家分享如何应对复杂信息流所带来的挑战。
我们就来采访一下邱晨老师,分享她这一路历程,探寻挑战背后的技术力量。
受访嘉宾介绍:
邱晨,微博移动端资深研发专家。曾就职于 Facebook, Storm8, Twitter,以全栈工程师的身份参与开发过多款 App,对产品有着执着的热情。现在主要负责客户端流程优化、持续集成和一些重构的工作。
InfoQ:邱老师您好,您就职的公司包括 Facebook、Twitter、微博,能否介绍一下它们的研发团队风格各有什么特点呢?
邱晨: Facebook 是一家具有 Hack 精神的公司,工程师对产品有很多自己的看法。在 Hack Week 的时候,大家会把自己的 idea 实现出来进行评审,评审出好的 idea 会正式上线。“Move Fast & Break Things”这个 FB 的座右铭体现了它大胆尝试的工程师文化。
Twitter 的风格是对技术追求极致,同时鼓励大胆的交流。大家会很乐于分享和学习新的技术,保持对技术的好奇心。Twitter 有个项目叫 Twitter University,每周都会推出课程,每个人都可以注册参加,同时也可以注册成为讲师,与大家分享。在 Twitter,大家很注重代码质量和集成测试,尽量将 Bug 扼杀在开发阶段。
微博的研发团队对技术很有热情,经常会与国内外的技术专家进行技术交流,并且在不断地改进自身的架构和学习新的技术。通过自己的实践来找到最好且最适合的解决方案。我所在的移动研发中心,一直在不断地尝试引入新的技术,例如 ComponentKit,React Native,Hybrid App 等。工程师之间的交流方式也是简单直接,这点跟 Twitter 有些像,尽量减少沟通成本,快速解决问题。
InfoQ:能否简单介绍一下微博 iOS 端框架,由哪些部分组成?
邱晨:微博 iOS 端主要由微博核心源码、第三方团队 SDK 和开源 SDK 组成。在业务层,每条业务线都有自己的一个或者几个模块,这样保证了多条业务线的并行开发。在 Code Base 之外,我们还有 Gerrit 代码审查,AB Test 系统,打包平台,联调环境,Jeckins 自动化集成等系统来辅助整个 App 开发流程。
InfoQ:微博 iOS 端架构模式是怎样的,在 Controller 优化上做了哪些工作?
邱晨:微博 iOS 端的架构模式是以 MVC 和 MVP 为主,同时配合单例的模式。其中信息流的架构主要采用 MVP 思想,我们会建立一个中间层处理业务逻辑和同步逻辑,并且将 Data Source 和一些其他的 Protocol 在中间层实现。所有的基础功能都被分离出来,建立对应的 Store 和 Manager 单例,在这些单例中完成网络请求的发送、获取和解析,在 Controller 中只需指定回调 block。这些基础功能和与之相应的 Model 将会组成像分享,未读,日志这样的基础类模块。同时,我们也会将一些业务逻辑移至 Model 的 Category 中,达到优化 Controller 的目的。
InfoQ:微博 iOS 的组件化如何实现?
邱晨:微博 iOS 端的组件主要分为三层,包括业务层、基础层和工具层,依赖关系自上而下。微博工程主要的模块有信息流,Page,消息箱,登录,分享,支付,多媒体,工具,网络,UIKit 等,现在已有 60 多个模块,每一个模块为一个独立的 Project,通过 CocoaPods 组装。其中一些组件是可以作为 SDK 提供给第三方使用的,包括网络,账户等。由于微博工程还有一些第三方团队在共同开发,同时也是为减少开发过程中编译所花的时间,微博将每个模块的源码编译成静态库,采用 LibraryPods 的方式支持部分源码编译。在组件化之前,微博是比较重度使用 OpenURL 进行模块跳转的,但是 OpenURL 让我们在梳理逻辑时造成困难。于是在组件化优化之后,我们已经减少 OpenURL 的使用。
InfoQ:微博的信息流复杂,那么微博是主要从哪些方面增强信息流的可扩展性呢?
邱晨:微博 iOS 端包含多条信息流,主 Feed,热门推荐,周边微博等。每一条信息流的来源是不一样的,所以每一条信息流都会有与之对应的 Stream 实例,负责信息流的刷新,加载和存储。在 Stream 实例中,所有的信息都是以 Section 片段的形式存储起来的,每一个 Section 之间相互独立。
在可扩展性上,微博还是以部件化的思维进行优化的。每一条微博中可能包含着各种各样的内容,比如图片、文字、视频、PageCard,地点等。这些内容都会包含在一个 Cell 内呈现在信息流中,我们通过 Model 对应的 Adapter 进行这些信息的拼装组合。例如一条微博,可能包含多种信息,这时 Adapter 会来判断使用哪一种 Cell,在 Cell 中展示怎样的信息,进行拼装,并且所有的布局规则是在这个 Adapter 中实现的。而 Adapter 的展现形式是在 Controller 里面进行配置的。同一条微博在热门微博信息流的展现形式和主 Feed 可能是不同的。每一个部件只要各司其职,就可以呈现出不同的展现效果。而此时 Controller 并不需要知道一条微博对应的是哪种 Cell,一个推荐用户对应的哪种 Cell。
当我们想在信息流中加入一种全新的内容时,我们要做的就会很简单。例如,当我们要在主 Feed 中加入用户推荐,只需要增加一个用户推荐 Model 对应的 Adapter,并且在主 Feed 的 Controller 中进行注册。这种 Adapter 知道如何组合已有的用户 Avatar 和用户信息 View。又或者我们需要在信息流中支持头条文章的内容。在建立文章 Card View 之后,只要在微博对应的 Adapter 中增加文章 Card 的布局就可以加入这种新的内容。
InfoQ:微博有很多长列表的典型场景,对于复杂内容的长列表渲染如何优化?
邱晨:对于长列表渲染的优化,微博开发了一套自己的异步绘制框架,这套框架于 2012 年上线使用,可以说是国内第一个大规模应用异步绘制的 iOS App。这套框架也使微博的滑动性能达到了业内领先,从低端设备只有 30 左右 fps 提升至所有设备接近 60fps,目前 fps 平均值稳定在最理想的 60,抖动很小。另外,还有很多其他的优化点,例如按需加载,在快速滑动时不加载图片。不阻塞主线程,尤其是 IO 的操作。以及 iOS 端特有的预先计算和缓存高度,也能优化滑动效果。其他诸如重用 Cell 等熟知的优化点就不再赘述了。我们也尝试过在 iOS 端使用 Facebook 开发的 ComponentKit 框架进行信息流的优化,但是由于效果并不十分显著,所以搁置了 ComponentKit 的使用。
InfoQ:iOS 端动态化和热修复使用了哪些技术呢?
邱晨:热修复方面,微博使用的是现在比较流行的 JSPatch,我们已经有 JSPatch 的发布平台用于管理脚本,由于 JSPatch 对性能还是有一些影响,每一个脚本都会经过仔细评估才会全量下发。在动态化方面,我们也有尝试 React Native 的使用,目前已有一些周边页面是基于 RN 框架开发完成的。
InfoQ:微博的 iOS 团队是怎样完成快速迭代的任务的?迭代周期如何?
邱晨:微博客户端团队采用的是敏捷开发模式,每两周为一个 Sprint。在迭代周期开始前,各业务线根据技术排期分配下一个 Sprint 的任务。在迭代周期结束后,会有一周的测试期,进行三轮 Full Case 测试,此时只能进行重要 Bug 的修复。同时我们会通过 AB Test 系统,控制 Feature 的上下线和投放比例,保证客户端的稳定性。在 Feature 投放后,AB Test 系统会收集相关业务的核心数据,并在控制台进行对比展示。通过分析不同实验组的数据反馈,进一步决定是否提高 Feature 的投放比例或者下线。
InfoQ:感谢您接受我们的采访。期待您在全球移动技术大会上的分享。
评论