一个app的初始阶段,必然是先知足各类业务需求。而后,通过屡次版本迭代以后,先前的因为急于知足需求而致使的杂乱代码则会充斥整个项目。而此时,项目有了必定的规模,有了必定数量的开发人员,那么为了达到快速迭代版本的需求,则是须要有一个强大的架构来支撑。git
在开始谈app架构以前,曾经我一度认为,一个好的app就是须要有好的架构,若是没有一个我所认为的“好架构”,那么这个app就是很low。web
直到去年参加北京ArchSummit时,听了无数的公司他们对于产品的架构以后,我陷入沉思,由于我总在本身的认知里选出一个本身认为最好的架构,而后以为其余架构都是垃圾。设计模式
静下心来想一想,每一个产品都有本身不一样的定位,若是抛开它们的定位,抛开它们的业务需求去谈若是给它们设计一个良好的架构,这简直是扯淡。xcode
更况且不少优秀的app架构也是由一开始很弱而慢慢变得愈来愈强。网络
因此没有最好的架构,只有适合本身的业务的架构才是最好的架构,而且它是逐步地变强变大。架构
本文将举一个例子来演示这个过程。并发
架构,又名软件架构,是有关软件总体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。app
以个人理解,它就像是人的骨架通常,一我的从小生长到大,围绕着整个骨架去发展,变高变胖。框架
能够把app开发当作一个汽车工厂的流水线,造车身->喷漆->组装等等。即把整个开发流程切成一个个模块,每一个模块相互独立,并发工做。这就是所谓app架构。工具
某天,一个叫Jim的开发者,他打算开发一个app,固然有必定计算机基础的他知道采用MVC的设计模式来构造app,因而一个星期后,终于能跑起来一个app,可是此时,看一下项目的目录结构:
v1.0
嗯,不错,咱们不但能run,还能看出这个app用了MVC的设计模式耶。
可是随着开发的页面愈来愈多,一个月后,app有了10个页面,此时,打开Controller、View、Model这三个文件夹以后,发现每一个文件夹里面居然有几十个文件,它们杂乱无章的洒落在一块儿。此时不断有用户向Jim反映,xxx地方怎么按钮位置不对,xxx位置网络请求不成功。
头痛的Jim才知道,当初应该把粒度分的更细,因而又了接下来的架构。
Jim把不一样的功能模块放在一起,因而获得了以下的架构:
v2.0
可是不对,一些工具类,公用类该放哪呢?Jim仔细思索了一番,因而又将上述架构进行改进,获得如下的架构:
v2.1
嗯,这看起来才像样嘛。
慢慢地,Jim发现网上有不少能够现成拿来用的第三方框架,而他同时也学习了Cocoapods这个神器。
什么是Cocoapods:
CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over eighteen thousand libraries and can help you scale your projects elegantly.
它是一个能让你方便地管理第三方库的一个工具。
因而,项目变成了这样:
v2.2
此时的架构已经知足了我的开发者,或者说是小型开发团队的需求了。
可是在一个初具规模的公司,上述的架构模式是远远不行的,试想一下,若是有20我的同时开发一个app,而此时你们就算各自负责本身的模块,若是同时有不一样模块的同窗添加或者删除文件,对于.xcodeproj
文件来讲,会有严重的冲突。
那么,怎么办呢?
想一下cocoapods的做用吧,其实利用它能作不少不少事,咱们彻底能够把Home、Detail、Login
等模块抽出来,也把它视为“第三方库”(实际上能够算是二方库)。初期阶段能够这么作:
v3.0
能够看到咱们把Home
这个模块抽出来了。
这么作有什么好处?
若是咱们把各个业务模块都抽出来,首先来讲,能够解决冲突的问题,而且业务团队之间的工做不受影响,而且能够并行开发,也无需再等待其余兄弟业务团队的进度了。
当其余业务团队的任务完成时,咱们只需pod update
,将代码升级到最新就能够了。
而且当一个公司有多个app时,若是有公用的模块,用这种方式会更优雅。
固然,若是你以为直接指定git地址太low,你彻底能够搞一个私有Spec,专门存放业务模块代码。
不少人会说上述方式很复杂,还不如采用在主工程下中放子工程(业务模块)来实现抽象:
不合理的架构
可是我以为这个方式管理起项目很麻烦,更新模块代码、不一样app间复用模块代码都会没上述的方式优雅,因此我以为这种方式没有上述的好。
如今虽然咱们对各个模块进行了抽象,可是业务模块间仍是互相引用,对于开发来讲,虽然解决了代码的耦合问题,对于代码的引用关系却没有改变:
v3.0
上图才只有4个模块,若是有上百个模块的话,这个关系能够复杂成一个庞大的蜘蛛网,这对于后期维护来讲,成本是巨大的。
因此咱们想,有木有好的方式来解耦呢,固然是有的,我以为如下两个方式是很好的:
middleman
urlRoute
先来介绍middleman(中间人模式)
middleman
如图所示,咱们只需将全部的模块依赖这个middleman,让middleman来处理各个模块的关系,模块A若是须要依赖模块B,彻底能够考middleman来处理,而且返回模块A所须要的模块B的内容,这样就解决了解耦。
再来讲说urlRoute,其实这个方式相似于Facebook很早前的320结构了。
思路就是将每一个页面当作是一个url,设置一套路由规则,在页面打开时将url进行路由查找,而后这样一来,只要模块A按照既定的规则写好url,那么模块B依赖模块A时,只需根据url打开就好了。
urlRoute
两种方式各自有本身的优势和缺点,他们主要的区别在于:
传参的方式
所需维护的具体内容不一样
我更倾向于urlRoute,为何这么说呢?
因为本文讲的是app架构,这里就简单介绍下:
若是一个页面出现了问题,咱们能够用各类patch的方式来打补丁。可是,若是一个页面出现了致命的错误,打patch的成本过于高的话,此时若是用urlRoute,则有个妙招。
咱们能够更改appConfig(app的配置,能够从服务端动态更新),更改页面所对应的url,而且改为在路由规则里跳到webview的规则。
这样以后,当跳到此模块时,则会打开对应的H5页面,而不是原来的有问题的页面。
固然middleman也能够处理成这样,可是从实现的角度来讲,显然是urlRoute更为优秀。
架构远远不是一篇文章能讲清楚的,也不只仅只是结构层次方面的内容,还有例如push、hotpatch、动态化、appConf、Service中间件模块的具体实现,MVCMVVMMVCS设计模式等等。本文只是从最基础的地方展示具体业务模块的解耦方式,但愿能起到抛砖引玉的做用。