背景:基础侧期望能统一视频的合成流程,换个说法,就是合成用他们的代码。
思考1: 我首先思考的是这个需求该不该做
在手q上,两端的业务逻辑差别很大,比如基础侧支持图片上传,日迹要求特效封面跟视频分离(清晰度原因),各自支持的拍摄(日迹有分段拍摄)和编辑模式(基础侧有专门针对图片的编辑模式)也不尽相同,最重要的是有各自的拍摄入口,所以有两套合成代码算合理。但在qim上,拍摄和编辑都是统一的,差异落在了封面分离和编辑图片上,而清晰度问题自从提高了分辨率后,也不算是大问题了。其次,基础侧一直在增加拍摄和编辑的功能,两套代码后面会非常难维护,所以,流程统一是趋势,重构势在必行。
思考2:除了满足产品需求,我还能做什么
现有代码有什么问题,能否借着重构的机会解决现有代码的问题?我汇总了当前发表流程的一些问题:
1 代码耦合严重,可读性差
视频合成,数据存储,通知发送都在一个类里,回调级级嵌套,if..else代码太多
2 拓展性差
整块代码对外层是个黑盒子,参数都是固定的,没有任何可拓展性
3 同步代码困难
4 数据上报准确率有问题
5 取消任务的代码散落在各处,切账号引起的bug很难修改
6 不支持并发,通过信号量间接实现单任务,任务卡死就会卡死整个任务队列
重构时,能一并解决上面问题再好不过。
思考3:如何落地
一般技术需求,尤其是大一点的技术需求,都会面临工期问题,比如,你的排期超过了当前迭代版本的deadline,排完产品需求你还有人力富余吗,同期有没有产品需求也在修改这块的功能,如果他们在源代码基础上做需求,会不会互相影响 ?
排期问题,要跟pm仔细确认灰度时间和发布时间,预留后足够的测试时间。
需求问题,要跟leader和产品确认好人力情况,保证有人员能排。确认同期是否有对应的该模块需求,方便协调。
方案问题,要考虑好几套落地方案,比如,完整方案,折中方案,临时方法等,在讨论时大家有选择的余地。
考虑了上面的几个问题,我才放心进行方案设计。
思考4:如何设计
以前一直说,希望我们有一套数据层的框架,可以很容易的拓展和复用。但是这套框架该解决什么问题,其抽象粒度如何,一直没有定论,而且数据层一直是其他同事负责的,我也没有太关注。
现在问题交到我手里,我又重新开始思考这个问题。
诚然,我们现在有一套基于wns封装的网络请求api,有面向对象的数据库,有约定好的通知机制,如果完全理解这里面的规则,使用起来做业务需求完全没问题。但是,注意,我这里用了“api”这个字眼,从整个app的角度来看,不管你提供了多少个调用接口,能处理多少的功能,其只能算是针对业务逻辑提供的一些数据请求接口以及数据回调,是非常静态的。
如何合理的调用这些api,把数据请求,数据存储,UI刷新全部串起来的机制是没有的,即“动态”框架是没有的。
我们可以回想以前接触过的能真正称之为框架的东西,比如MFC,不仅提供了View/Doc的设计规范(静态),而且提供了大批的宏来控制和分发消息windows消息(动态)。又比如BeeFramework,不仅提供beeModel、BeeView等mvc各个层级的基础模块类,而且提供了编辑器,路由代码等等有效组织模块运行的框架。
一套框架之所以能成为框架,我的看法是,不仅要有静态的模块,也要有动态的模块。想当年我们用mfc的时候,是可以一行代码不写就运行app的,beeframework虽然要写启动的VC,但这也是遵循苹果的机制。
废话这么多,其实只是想提出我的看法,我们现在的数据层框架,不能算是个框架,只能算一组“api”。
思考5:任务队列可以实现app的动态框架吗
答案是不能。任务队列本身有其特定的使用场景,一般不涉及到UI操作的代码适合放到任务队列里。(当然你也可以认为runloop也是个任务队列,这里不争论这个问题), 我这里说的任务队列应该是异步,支持并发,以及UI无关的。虽然不能解决UI问题,但是针对数据层,却完全可以实现动态框架,因为数据层天生符合异步,支持并发,以及UI无关等要求。
思考6:技术选型
在IOS里,系统提供了一套队列框架。NSOperation以及NSOperationQueue。
NSOperation
NSOperationQueue
NSOperation提供了三种状态的流转execute -> cancel -> finish,以及标识该操作能否并发运行,任务依赖等等执行相关的属性,NSOperationQueue提供了添加操作,取消所有操作,设置最大并发数等管理任务的接口,正式我们想要的东西。
但是为什么很少看到有人使用他们呢?
一般一套看起来很好的东西却没什么人用的原因无外乎以下几个原因:
1 看起来很美,用起来其实很复杂,很麻烦。
2 性能有问题,不可控。
3 一开始设计的时候没用,现在没法子用了。
4 有很好的替代方案,系统逐渐淘汰它了。(ios经常发生这种情况)
5 大家都不用,我也不用。(万一出问题咋办)
6 见识短,其实大家都在用,你不知道而已。
后面一个是开玩笑,带着以上担忧,我google了一下。google过程省略,整理的结论如下:
1 使用确实有门槛,首先NSOperation的各个属性基本都是只读的(比如,isExecute, isCancel,isFinished等),只能通过重载的方式来实现状态的流转,而且系统要求你实现相关属性的KVO。
你也可以使用系统提供的派生类,NSBlockOperation或者NSInvocationOperation,从字面你可以看出一个是对oc函数的封装,一个是对c函数调用的封装。
2 性能有一点小问题,就是内存开销比GCD要大,GCD底层是基于C的,其效率更高,开销更小。NSOperation早于GCD出现,早期版本他们的实现是完全不同的,在iOS 4 与 MacOS X 10.6以后,Operation Queue的底层实现都是用GCD来实现的。(网上说法,没验证) 。
3 这个不讨论。
4 暂时没有这种迹象。
5 Operation VS GCD
贴篇stackover的争论https://stackoverflow.com/questions/7651551/why-should-i-choose-gcd-over-nsoperation-and-blocks-for-high-level-applications,年代可能有点久远,最近的文章好像都没看到比较激烈的讨论了。
类似xxx VS xxx的文章,跟php是世界上最好的语言一样,只要不是某一方具有压倒性的优势,一般的结论就是没有结论。存在即合理,只要我们的场景适合,那他就是组好的语言。