随着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:感谢您接受我们的采访。期待您在全球移动技术大会上的分享。