iOS 架构设计之冗余性思考

作者 : 董朝

做客户端开发的同学都知道业务需求千变万化,你永远不知道他未来会变化成什么样子。而作为开发人员也绝对不喜欢需求变更。本来说好的,都快做完了,产品经理变卦了:咱们不这样搞了,你看我七十二变。

我们极不情愿跟着这纷繁复杂的变化屁股后面,而疲于奔命。天下没有那么容易偷的懒,若不想应对这变化。就需要走到变化前面。技术往前走一步,领先于业务,而不是被业务赶着屁股走。这就需要冗余性思考,在做业务开发的时候,作为Coder就需要往后思考,业务可能会怎么变,当前程序结构是否足够灵活,方便调整。当业务需求调整的时候,能够以最小的代价来满足。而这就是『冗余性』思考。

针对变化进行设计而不只是针对需求。

这里说是『冗余』,是因为开发测多想了几步,为未来可能的变化也做了铺垫。与一些同学坚持的程序设计满足当前需求,不进行过度设计的理念多少有些不符。而我认为进满足当前需求进行设计是传统软件开发的路数,在互联网软件开发过程中,已经不适用。互联网软件产品,尤其是终端上的,版本迭代频繁,功能更新迅疾。已经很难有稳定的需求存在,变化是其本质特征。于是要求我们在开发的时候,就需要针对这种变化做出一定的设计。

探寻变化的规律

设计机制而不是仅仅满足需求

机制与策略分离

我们首先要说一个观点就是机制与策略分离。我们希望设计的是一整套能够满足上述要求的协议,其次才是实现,最后才是在我们的APP中的具体应用。这也是我这一年来的一个非常重要的总结。并且在逐渐开源出来的一些库中也体现着这个设计。具体说一下,所谓机制即是抽象出来的规则,比如:

f(x)=x^2 x属于R

所谓策略即是在具体场景中的应用,比如当x=2的时候:

f(2)=4 x=2

面对需求,我们需要首先透过表层的的东西,深入一步探讨一下在需求之下在变化的东西。举个例子来讲,我们都有处理过TableView相关的需求。

在版本1.0的时候,产品告诉你我们要做Feed。展示样式吗有目前是这个样子的:

当没有深入思考的时候。我没有区分什么机制那些变化的规律,什么是需求产品的当前的诉求。然后就开始动手了。写UITableViewCell的子类,往上面加Label和UIImageView,一起都是固定的。然后加载数据展示。。。。。

而1.0没发布几天,产品说咱们的Feed展示样式太简单了。现在我们需要支持链接跳转,Coders你们看UI给到的样式是这样的:

于是我们又开始增加新的UITableViewCell的子类。。。。。版本1.1发布了。

后面还有版本1.2,1.3,1.4……终于有一天忍无可忍

这个时候于是就有了重构,我们开始抽离Feed的公共部分放在基类里面,通过类继承等技术手段来控制工程的复杂度,同时提高开发效率。这个时候,我们反问一句:

这些重构的工作是否可以提前到1.0版本的时候开始做呢?

这里当然会有两方观点,

一方认为:代码腐败是伴随着项目推进必然产生的现象,何必实现多花费劳工去提前设计,兵来将挡水来土掩就好了。

另外一方认为:我们坚信事物背后都有一定的规律可以依循,虽然代码腐败是必然现象,但是依旧可以通过一定的技术手段来极大的减速这个过程。 ***

先说一点,这里没有对错之分。要是争对错了,估计又是一场骂战。只能说我更倾向于认同第二种观点。在项目设计初期,我们可以通过去预判功能走向,来进行软件设计。透过表面UI和业务逻辑,去看背后的底层变化逻辑。而这也正是我一直比较看好的:机制与策略分离比较好的应用。

首先透过表层的业务逻辑,去深度思考业务或者功能背后的底层变化规律。真对这些规律设计类库,然后再在当前的业务中选取适当的策略进行应用。再次强调一个理念:

针对变化进行设计而不仅仅是需求

几种真对变化进行设计的Case

说完干巴巴的理念的东西,我们来看一些大家喜闻乐见的具体的应用。

Talk is cheap, show me your code.

增加Client端的动态性或增加CS之间交互性

一般我们认为客户端开发很像是固体,给人的感觉是很硬的,一旦发版之后很多修改将变得异常困难。尤其是iOS的客户端,由于AppStore审核的限制,发版也相对难一点。一个很“硬”的东西,不如一个很“软”的东西更容易应对变化。这种变化有可能是业务需求,有可能是软件的BUG,有可能是系统突发危机…..

金以刚折,水以柔成。 ——晋·葛洪《抱朴子·广譬》

所以为了应对这些变化,需要让我们的Client变得像水:容万物而不折。我们就需要给其相应的能力。这里有两种策略:

增加CS之间交互性,通过Server下发指令来操作客户端

增加Client端的动态性,比如JSPatch,还有OCScript这类的方案。

让客户端变得像是一个可以接受指令的机器人,能够在服务器的配合下,灵活应对各种需求和突发状况。

动态性

先说动态性,这一块是业界一直在探索的东西,远的有Hybird等基于WebView的方案,进的有RubyMotion和ReactNative,还有阿里团队的Wexx,都是非常优秀的尝试。尤其是ReactNative和Wexx,最近一段时间很多团队将其引入到了技术栈,让自己的客户端可以支持动态发版,也就是常说的插件化。

去年下半年滴滴和手Q团队也分别抛出了两个非常惊艳的方案,一个是滴滴的DynamicCocoa,一个是手Q的OCScript。在编译器级别进行修改,通过下发中间语言,在客户端上跑对应语言的虚拟机来解释执行对应的语言。让客户端变得像是一个容器,可以承载下发的业务逻辑。

如果我们单纯的从业务需求的角度去思考,可能这些方案很难会出来。这些方案背后的大神们,也是深入思考之后,把这些机制性的方案设计并构建出来的。把动态性的支持做到如此的深入,也是极牛逼的事情。非常期待他们开源。

交互式客户端

交互式的客户端这种策略,更像是一个缩水版的“动态性”策略。我们在客户端中预置一些能够响应的指令。在需要的时候,通过服务器下发具体的指令,来触发执行客户端对应的逻辑。让客户端能够被动的应对一些业务需求和突发状况。下面我们说几个具体的应用:

命令式缓存

在我们构建了服务器与客户端命令式交互的架构(服务器向客户端发送指令,执行特定的动作)之后,我们做了一些有意思的事情。就比如命令式缓存:服务器向客户端下发文件缓存指令,客户端收到指令后进行文件缓存操作。

这套简单的系统构建起来之后,我们在这上面做了很多有意思的事情。

利用预缓存减小安装包体积

界面开发中往往用到很多的图片资源,尤其是PNG格式的资源,虽然可以进行压缩,但是某些尺寸比较大的背景资源图片还是可能会达到上百KB。这对于一个ipa包来说,也是举足轻重了。

最开始,可能为了包体积,我们牺牲了用户体验。对于这样的图片使用网络资源。这样就很难保证用户跳转到界面的时候,能够第一时间看到正确的背景图片。甚至有些网络差的时候,图片压根就下载不下来。

于是,我们做了这样的设计:

2.1版本将引入A,B,C三张大体积的图片

在2.1版本没有发布之前,就向全量客户端下发预缓存指令:缓存A,B,C三张图片。

然后发布2.1版本,用户升级之后进入对应页面时,将直接从本地缓存中读取对应的图片进行展示。

这样即兼顾了用户体验也减小了包体积。

利用预缓存减少CDN压力

在活动运营的时候,尤其是重大的节假日,一旦活动发布之后的段时间内,用户访问量激增,将会导致CDN过载。大量用户初次访问页面,大量下载文件资源。这个时候,就完全可以在活动之前,下发预缓存指令,来缓解CDN过载的问题。

染色日志上报

在我们客户端支持的指令列表中,日志上报也是一条非常有意思的指令。当客户端发生问题的时候,我们最开始的时候是手足无措。后来有了Crash上报,但也只是能够上报Crash这种极端情况。有很多没有Crash的情况,可能只是用户某个用法不当,或者产品逻辑本身有问题的时候,就比较难以追踪。这个时候我们就需要去查看生产环境上的日志。这个是在服务器开发中是比较常见的策略。

于是我们就构建了这样的一条指令,当指令被触发的时候,会将用户本地打的生产Log使用非对称加密之后上传到制定的地址。这种指令是和用户挂钩的,我们是根据UID针对单一用户下发指令。

然后我就可以,通过管理端拿到对应的Log,解密后查看。来看生产日志中可能存在的问题。

构建可运营的客户端

可运营的概念来自于别人的文章。意思是让自己的客户端能够支撑运营人员的需求,动态的更改展示的内容,甚至是功能点。虽然我们不进行发版,但是可以支持内容的动态替换,支持功能点的动态上线下线。甚至当某些功能上线之后,能够动态的增加其对应的保障性功能(例如日志,数据上报这样的保障性功能)。这里要说一下数据部分。

对于数据上报功能的设计,重点需要考虑扩展性,因为对于数据种类的需求无法一次就确定,往往随着产品的迭代会增加新的数据需求。这时候如果能够通过不修改上报模块,只在目标监控点增加采数据集代码就能完成新增需求,这就说明上报系统已经具有不错的扩展性了。当然这只是在客户端增加了数据上报的基础设施,真正运营的工作还要靠团队建立一个强大的大数据分析平台了,数据上报之后其实只是一堆数字垃圾而已,而真正赋予这些数字垃圾信息化价值的过程是分析。试想作为产品经理的你每天一到公司都会收到关于产品的数据邮件,可以看到新鲜的数据报表,曲折的线图,跃动的燃烧图等,这些都将为你的工作和负责的产品提供非常有价值的支撑,你应该感谢有这么好的运营团队。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互联网数据官iCDO

在微信小程序里,我们要怎样做数据分析

近期本来打算系统的写一下App数据分析的套路,但忽然“微信小程序”发布了。作为一名信仰互联网和做数据分析多年的“老司机”,看到新事物我也是很兴奋的。不过我还没看...

5495
来自专栏SDNLAB

P4: 面向服务器主导网络互联推进技术创新

P4是一种新的高级编程语言,P4用于软件定义网络。P4用于描述数据平面的行为,这些数据平面的行为可以对应于任何转发,修改或检查网络流量的系统或设备。P4最先在网...

2978
来自专栏上线了的专栏

Strikingly 团队2017技术展望

为了应对多客户端(Web, iOS, Android)的挑战,2016 年我们在团队层面和技术栈上做了很大胆的尝试:我们把前端团队和移动端合并了,组成了客户端团...

3070
来自专栏韩伟的专栏

论可复用的游戏服务器端开发框架(二)

RPG系统的可复用模型 RPG系统主要负责提供游戏中提供“积累、成长”的快感,也是驱动玩家反复进行游戏操作的重要系统。RPG系统能提供这种作用的最基本逻辑,是以...

35410
来自专栏BestSDK

想用APP创业,那你要明白API的重要性?

每一家初创企业和公司都会有提供给世界的接口。有的接口超级简单,比如Google—你能做的只有搜索;有的复杂一点,比如在Amazon上面买东西—你可以浏览、搜索、...

2829
来自专栏Rainbond开源「容器云平台」

好雨云帮一周问答集锦(11.14-11.20)

1154
来自专栏ThoughtWorks

「微前端」- 将微服务理念扩展到前端开发 | 洞见

前言 在 ThoughtWorks 正式发布的最新一期技术雷达当中,「微前端(Micro Fontends)」已经进入到试验阶段,而试验环所列出的技术是我们认为...

3907
来自专栏YouMeek

微服务系统:解惑、技术选型

在商言商 一家公司在发现新的市场需求的时候,先发制人所产生的优势是非常重要的。所以美国利宝相互保险公司执行副总裁兼首席信息官 James McGlennon 说...

62012
来自专栏IT技术精选文摘

解密腾讯海量服务之道

一直对腾讯做产品的能力比较敬佩的,我们组做消息推送系统,而腾讯的信鸽就是我们学习的榜样。京东很多做产品的思想是跟腾讯学的,而京东很多同事也从腾讯过来的(京东合并...

3105
来自专栏小狼的世界

Google SRE 读书笔记 扒一扒SRE用的那些工具

最近花了一点时间阅读了《SRE Goolge运维解密》这本书,对于书的内容大家可以看看豆瓣上的介绍。总体而言,这本书是首次比较系统的披露Google内部SRE运...

822

扫码关注云+社区