iOS架构设计之冗余性思考
做客户端开发的同学都知道业务需求千变万化,你永远不知道他未来会变化成什么样子。而作为开发人员也绝对不喜欢需求变更。本来说好的,都快做完了,产品经理变卦了:咱们不这样搞了,你看我七十二变。
我们极不情愿跟着这纷繁复杂的变化屁股后面,而疲于奔命。天下没有那么容易偷的懒,若不想应对这变化。就需要走到变化前面。技术往前走一步,领先于业务,而不是被业务赶着屁股走。这就需要冗余性思考,在做业务开发的时候,作为Coder就需要往后思考,业务可能会怎么变,当前程序结构是否足够灵活,方便调整。当业务需求调整的时候,能够以最小的代价来满足。而这就是『冗余性』思考。
针对变化进行设计而不只是针对需求。
这里说是『冗余』,是因为开发测多想了几步,为未来可能的变化也做了铺垫。与一些同学坚持的程序设计满足当前需求,不进行过度设计的理念多少有些不符。而我认为进满足当前需求进行设计是传统软件开发的路数,在互联网软件开发过程中,已经不适用。互联网软件产品,尤其是终端上的,版本迭代频繁,功能更新迅疾。已经很难有稳定的需求存在,变化是其本质特征。于是要求我们在开发的时候,就需要针对这种变化做出一定的设计。
设计机制而不是仅仅满足需求
机制与策略分离
我们首先要说一个观点就是机制与策略分离。我们希望设计的是一整套能够满足上述要求的协议,其次才是实现,最后才是在我们的APP中的具体应用。这也是我这一年来的一个非常重要的总结。并且在逐渐开源出来的一些库中也体现着这个设计。具体说一下,所谓机制即是抽象出来的规则,比如:
f(x)=x^2 x属于R
所谓策略即是在具体场景中的应用,比如当x=2的时候:
f(2)=4 x=2
面对需求,我们需要首先投过表层的的东西,深入一步探讨一下在需求之下在变化的东西。举个例子来讲,我们都有处理过TableView相关的需求。
在版本1.0的时候,产品告诉你我们要做Feed。展示样式吗有目前是这个样子的:
f92d48e3eda24ac1.jpg
当没有深入思考的时候。我没有区分什么机制那些变化的规律,什么是需求产品的当前的诉求。然后就开始动手了。写UITableViewCell的子类,往上面加Label和UIImageView,一起都是固定的。然后加载数据展示。。。。。
而1.0没发布几天,产品说咱们的Feed展示样式太简单了。现在我们需要支持链接跳转,Coders你们看UI给到的样式是这样的:
a9737d9f1957c23d.jpg
于是我们又开始增加新的UITableViewCell的子类。。。。。版本1.1发布了。
后面还有版本1.2,1.3,1.4……终于有一天忍无可忍
这个时候于是就有了重构,我们开始抽离Feed的公共部分放在基类里面,通过类继承等技术手段来控制工程的复杂度,同时提高开发效率。这个时候,我们反问一句:
这些重构的工作是否可以提前到1.0版本的时候开始做呢?
这里当然会有两方观点,
一方认为:代码腐败是伴随着项目推进必然产生的现象,何必实现多花费劳工去提前设计,兵来将挡水来土掩就好了。
另外一方认为:我们坚信事物背后都有一定的规律可以依循,虽然代码腐败是必然现象,但是依旧可以通过一定的技术手段来极大的减速这个过程。 ***
先说一点,这里没有对错之分。要是争对错了,估计又是一场骂战。只能说我更倾向于认同第二种观点。在项目设计初期,我们可以通过去预判功能走向,来进行软件设计。透过表面UI和业务逻辑,去看背后的底层变化逻辑。而这也正是我一直比较看好的:机制与策略分离比较好的应用。
首先透过表层的业务逻辑,去深度思考业务或者功能背后的底层变化规律。真对这些规律设计类库,然后再在当前的业务中选取适当的策略进行应用。再次强调一个理念:
针对变化进行设计而不仅仅是需求
增加Client端的动态性或增加CS之间交互性
一般我们认为客户端开发很像是固体,给人的感觉是很硬的,一旦发版之后很多修改将变得异常困难。尤其是iOS的客户端,由于AppStore审核的限制,发版也相对难一点。一个很“硬”的东西,不如一个很“软”的东西更容易应对变化。这种变化有可能是业务需求,有可能是软件的BUG,有可能是系统突发危机…..
金以刚折,水以柔成。 ——晋·葛洪《抱朴子·广譬》
所以为了应对这些变化,需要让我们的Client变得像水:容万物而不折。我们就需要给其相应的能力。这里有两种策略:
增加CS之间交互性,通过Server下发指令来操作客户端
增加Client端的动态性,比如JSPatch,还有OCScript这类的方案。
让客户端变得像是一个可以接受指令的机器人,能够在服务器的配合下,灵活应对各种需求和突发状况。
动态性
先说动态性,这一块是业界一直在探索的东西,远的有Hybird等基于WebView的方案,进的有RubyMotion和ReactNative,还有阿里团队的Wexx,都是非常优秀的尝试。尤其是ReactNative和Wexx,最近一段时间很多团队将其引入到了技术栈,让自己的客户端可以支持动态发版,也就是常说的插件化。
去年下半年滴滴和手Q团队也分别抛出了两个非常惊艳的方案,一个是滴滴的DynamicCocoa,一个是手Q的OCScript。在编译器级别进行修改,通过下发中间语言,在客户端上跑对应语言的虚拟机来解释执行对应的语言。让客户端变得像是一个容器,可以承载下发的业务逻辑。
如果我们单纯的从业务需求的角度去思考,可能这些方案很难会出来。这些方案背后的大神们,也是深入思考之后,把这些机制性的方案设计并构建出来的。把动态性的支持做到如此的深入,也是极牛逼的事情。非常期待他们开源。
交互式客户端
交互式的客户端这种策略,更像是一个缩水版的“动态性”策略。我们在客户端中预置一些能够响应的指令。在需要的时候,通过服务器下发具体的指令,来触发执行客户端对应的逻辑。让客户端能够被动的应对一些业务需求和突发状况。下面我们说几个具体的应用:
构建可运营的客户端
可运营的概念来自于别人的文章。意思是让自己的客户端能够支撑运营人员的需求,动态的更改展示的内容,甚至是功能点。虽然我们不进行发版,但是可以支持内容的动态替换,支持功能点的动态上线下线。甚至当某些功能上线之后,能够动态的增加其对应的保障性功能(例如日志,数据上报这样的保障性功能)。
BY:yishuiliunian