7 月 25 日,又拍云 Open Talk 第十一期《永不止步:移动应用架构的重塑与优化》再次抵达上海,邀请到“in”iOS 负责人白菜、“扇贝”产品与技术负责人吴焱红、“饿了么”移动端负责人胡彪,分享移动应用背后的架构演进之路。in  iOS 负责人白菜在活动上作了题为《敏捷移动开发实践》的分享,以下是分享实录:

image.png

我们是来自杭州的 in ,“生活in记”是我们的品牌产品。它致力于让大家可以记录我们生活当中每一个每一个精彩瞬间。最近我们在技术上有了一个全新的改动 —— in 的 2.0 版本发布了。

这次新版本,我们做了很多事情让大家在使用过程中更方便,比如卡片式的浏览方式及翻页体验,以及为保证大家浏览图片的连续性而定制的翻页体验。

很多女孩子比较喜欢把很多拍的图片拼在一起,像杂志一样。因此这次的 in 2.0 尝试了用一些双页的图片,让大家多种形式更好记录生活的精采时刻。

此外还有时间轴,也就是发图的记录。用户可以根据上面的发图时间形成很好的归类。我们意在将优质的图片挖掘出来给大家,给特别是女生的用户以更优的浏览体验。

用户暴增催生架构革新

in 诞生于 2014 年,当年我们做了这样的尝试:用图片代替微信、微博发的文字。图片比文字更能体现一个人当时的心境。如何把自己拍得更萌更美是一个大问题,因此我们所有的业务都是围绕着发图的模块。

一开始我们成功了,但随着用户爆炸性增长,产品产生了层出不穷的需求,我们发现 in 现有的架构难以支撑,主要体现在:

  • 业务量增大,人手不足,冲突增加
  • 需求变更,BUG 测试混乱,依赖关系复杂
  • 减少业务使得程序更改更加复杂化

于是,在 in 2.0 开发的时候,我们尝试了新的思路,以更高效的解决上面这些用户暴增期出现的问题,因为我们人也不算很多,架构不能太复杂。

独立模块敏捷开发实践

完全独立的模块开发

针对上述的需求和问题,我们采用了独立模块的新模式。这是一个大家比较轻松的,各自都没有很大关联的模式,大家可以随心所欲开发自己的模块,不用担心对别的模块造成很大的依赖。并行开发使得他们可以完全自主地开发,可以同一时间开发自己的模块,不用担心别的模块有没有做好。

我们的方式工程加分是通过把拆分组件实现的, in 2.0 的首页和详情页没有关系,它们是独立的,没有代码的权限。并行测试也是一样,我们把现有工程拆分,每一个小的模块打包一个 APP,中间键单独打包,当 APP 包含一些登入的要素后再把中间键引进去。比如说 APP 测试一个详情页可以从页面 ID 直接跳过,测试相应的详情页的功能。这样使得并行测试得到了比较好的解决。

我们在 in 2.0 上尝试二方库和三方库,还有 iOS 的,所用的方法是分支法。业务层中间件、底层、基础库是分开的,业务层里面也是分开的,它们之间完全无关。中间件是我们的一些基础要素,比如说登入,一些服务等。底层业务和中间业务没有关系。和 in 没有关系也会单独列出来,因为我们考虑到后面还有很多的东西要开发,不仅仅限于 in 的 APP ,其他抽离出来也可以用这些业务层,不用担心依赖过多做不出来。

模块通讯的便捷化

由于中间件、底层、基础库这三个模块都是各自独立的,互相间的通讯比较困难,唯一的解决方法就是标准的制定和模块的制订。之前 H 有一个协议,就是 URL 导航,in 从 APP 跳到拍照,跳到详情页这个是统一的, H5 都是一样的。

那么,如果朋友页就一张图片,跳到详情页怎么实现呢?比如说A的图片是12345,打开12345,A 收到 12345 的页面请求12345的资源,A 压根不关心别的。不管经过多少路由打开我们的 E66 官网看到 12345 ,这就是我们想要的结果,所以 URL 是很好的东西,不仅仅可以跳转,只要一个指令,和在游览的其地址里打开地址一样,浏览器会解析给官网这个页面——B页面,我们会有 URL 路由的组建,在组建里面相应根据URL地址路由到相应的页面,那个页面可以给我一个反馈,就是我已经能识别一张图片详情页的URL,它即将打开。

另外,我们在另一个版本 in 2.1 中追加了一些别的功能,例如我发了 in 2.1 功能的 URL ,如果对方不能识别,我们可以用降级处理,即从 URL 跳到 H 页面,做一个 H 功能的实现,就是刚才我说的消息页面,这样比较灵活。用户不用关心他是怎么到达那个页面, OPEN 做得好就是要自己配制,获取一个数据跳转 URL 。例如我这边点击把协议打开,消息页可以不用管怎么跳过去,地址都可以不用管就达成了。

消息分发的轻量化

我们还把模块更加轻量化,没有之前这么复杂。由于我们的消息模块会跳很多页面,每一个页面都要跳一下,就会各种消息纠缠在一起。之前我们想用模块之间的通讯,通过使用苹果自带的 iOS 一个类似消息中心的功能实现,结果遇到一些问题:我们发现每个人都有自己的实践方法,方法名是什么我也不知道,当这些用户出了一些问题后再调的话很难调,我们要首先找出问题所在的地方。

在2.0我们进行全新的尝试,每个模块都知道自己的作用是什么,当有人发送消息,比如一个消息可以传播给相应注册的用户,还有一个技术突破是标准业务之间的通讯全面接口化,in 之前写的得不是很完善,可能有一些东西不直接用接口,比如投文件 B 的接口直接把对象复制一下就发过去,A接口也不管了,反正负责推出来就行,这个还是有一点问题的。我们发现 in 2.0 这样标准带来的维护成本更低,同时大家有统一的接口。如果有接口更新的话,把原来的接口全部删除,这时可能稍微有一些变更,但不会影响别的模块。

其他方面的改进

业务反馈效果:因为 in 2.0 模块与模块之间压根不会有关联。 in 1.0 会本的成本很大,问题是当我们的产品拿出去,如果反馈的效果不是很高,我们会怀疑回滚会不会漏什么东西,可能又要全部重新测试一遍,那个模块稳定性可能会受到影响。例如有一个版本号打包给产品调研的时候就是一个 2.1 的版本,反馈效果不是很高,使用 in 2.0 的话,由于模块和模块是通过 URL ,即便这个模块不存在了,OPEN 也没有什么影响,唯一的影响就是跳不过去,不会把投文件删了,增加一些不必要的麻烦。

启动管理速度:in 原来可以启动很多东西,大家都要启动的话会拖慢起动的速度,有一些不可控,in 2.0 把这些进行规范,在同一个地方启动,我们只要看一下代码就知道哪些东西在 APP 启动的时候一定要启动,为什么启动,有没有必要启动都可以观察到,方便以后的维护。

模块架构:有人说代码不在同一模块不方便调查原因,这确实是一个比较棘手的问题,我们现在已经害怕再做一次架构。这次架构我们花了比较久的时间和业务一起开发,因为2.0 对我们来说很重要,我们的发送模块很复杂,有 9 张图片可以编辑,产品方的要求特别的严厉,处理的速度一定要快,清晰度又要保证得比较高,不能处理速度快的同时各种清晰度降下来,之前的代码依赖比较高的时候,我们改了一个小的东西,测试没有测出来,直接就上了,结果发现有一个地方错了,图片清晰度惨不忍睹,因为图片模块比较复杂,各种图片要处理,分辨率要求比较高,当时由于苹果的政策原因在架构上暂时没有线上补救的方法,只能赶紧发了一个紧急包去修复,把这些图片全部抽离出来。

in 2.0 有一个脚本语言,这个代码在执行之前会将之拦住,新的代码就不用再为了一些紧急的包发一个新包,但是有一个政策上的风险,要在苹果 APP 上线之后网上下载原码更新,我们还是想对此做一些尝试,例如原来 in 可能是一个图片浏览的 APP,突然更新一些功能变成游戏,修复一下紧急的 BUG。