架构之路 (二) —— APP架构分析(一)

版本记录

版本号 时间
V1.0 2018.05.16

前言

前面写了那么多篇主要着眼于局部问题的解决,包括特定功能的实现、通用工具类的封装、视频和语音多媒体的底层和实现以及动画酷炫的实现方式等等。接下来这几篇我们就一起看一下关于iOS系统架构以及独立做一个APP的架构设计的相关问题。感兴趣的可以看上面几篇。
1. 架构之路 (一) —— iOS原生系统架构(一)

回顾

上一篇主要讲述了苹果原生iOS框架的架构,这一篇我们就说一下如果自己要完成一个APP,需要如何去设计架构。


架构设计结构上划分

我们说APP的架构设计,但是架构设计需要我们怎么在结构上进行划分呢?可以按照下面进行划分。

  • 网络设计方案

    • 这里包括对网络层很好的设计和封装,让工程师可以方便安全的调用,同时也要保证用户在各种网络环境下有很好的体验。
  • 数据解析和页面渲染设计方案

    • 这里包括数据模型的搭建、页面如何封装降低耦合以及高效的渲染。
  • 数据持久化存储设计方案

    • 这里包括,当有本地存储的需求时,如何保证数据可以在本地合理的存储。
  • 动态部署方案

    • 这里包括,如何不发版就更新版本和解决问题。这个以前都用热更新hotfix,不需要发版就可以进行更新,但是苹果现在给禁掉了。现在还有一个可以解决部分问题的方案:可以采用云控,利用服务端进行控制,达到对某些功能的调控,但是还是不能通过热更新进行更新版本。

其实也可以有三层分层架构:展现层、业务层、数据层。

  • 展现层:视图页面渲染
  • 业务层:业务功能实现
  • 数据层:包括数据的下载(包含所谓的网络层)和转化,甚至持久化

好的架构衡量标准

  • 代码整齐,分类明确

    • 代码整齐是每一个工程师的基本素质,先不说你搞定这个问题的方案有多好,解决速度有多快,如果代码不整齐,一切都白搭。分类明确的字面意思大家一定都了解,但还有一个另外的意思,那就是:不要让一个类或者一个模块做两种不同的事情。如果有类或某模块做了两种不同的事情,一方面不适合未来拓展,另一方面也会造成分类困难。
  • 不用文档,或很少文档,就能让业务方上手

    • 尽可能让你的API名字可读性强,对于iOS来说,objc这门语言的特性把这个做到了极致,函数名长就长一点,不要紧。
  • 思路和方法要统一,尽量不要多元

    • 解决一个问题会有很多种方案,但是一旦确定了一种方案,就不要在另一个地方采用别的方案了。也就是做架构的时候,你得时刻记住当初你决定要处理这样类型的问题的方案是什么,以及你的初衷是什么,不要摇摆不定。另外,你当初设立这个模块一定是有想法有原因的,要记录下你的解决思路,不要到时候换个地方你又灵光一现啥的,引入了其他方案,从而导致异构。
  • 没有横向依赖,万不得已不出现跨层访问

    • 没有横向依赖是很重要的,这决定了你将来要对这个架构做修补所需要的成本有多大。要做到没有横向依赖,这是很考验架构师的模块分类能力和是否熟悉业务的。跨层访问是指数据流向了跟自己没有对接关系的模块。有的时候跨层访问是不可避免的,比如网络底层里面信号从2G变成了3G变成了4G,这是有可能需要跨层通知到View的。但这种情况不多,一旦出现就要想尽一切办法在本层搞定或者交给上层或者下层搞定,尽量不要出现跨层的情况。跨层访问同样也会增加耦合度,当某一层需要整体替换的时候,牵涉面就会很大。
  • 对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件

    • 把这点做好,很依赖于架构师的经验。架构师必须要有能力区分哪些情况需要限制灵活性,哪些情况需要创造灵活性。比如对于Core Data技术栈来说,ManagedObject理论上是可以出现在任何地方的,那就意味着任何地方都可以修改ManagedObject,这就导致ManagedObjectContext在同步修改的时候把各种不同来源的修改同步进去。这时候就需要限制灵活性,只对外公开一个修改接口,不暴露任何ManagedObject在外面。如果是设计一个ABTest相关的API的时候,我们又希望增加它的灵活性。使得业务方不光可以通过Target-Action的模式实现ABtest,也要可以通过Block的方式实现ABTest,要尽可能满足灵活性,减少业务方的使用成本。
  • 易测试,易拓展

    • 要实现易测试易拓展,那就要提高模块化程度,尽可能减少依赖关系。如果是高度模块化的架构,拓展起来将会是一件非常容易的事情。
  • 保持一定量的超前性

    • 这一点能看出架构师是否关注行业动态,是否能准确把握技术走向。保持适度的技术上的超前性,能够使得你的架构更新变得相对轻松。另外,这里的超前性也不光是技术上的,还有产品上的。
  • 接口少,接口参数少

    • 越少的接口越少的参数,就能越降低业务方的使用成本。
  • 高性能

    • 高性能非常重要,但是在客户端架构中,它不是第一考虑因素。客户端业务变化非常之快,做架构时首要考虑因素应当是便于业务方快速满足产品需求,因此需要尽可能提供简单易用效果好的接口给业务方,而不是提供高性能的接口给业务方。

架构模式的选择

前面根据需求对框架的架构分类,可以分为三层结构甚至四层结构,这里就说一下架构模式,可以说架构模式是架构实现的方式。常见的有MVC、MVVM和VOPER等。好的架构模式可以让模块功能更清晰,维护起来也很方便。

下面就一起看一下这几种架构模式:

1. MVC

  • 任务均摊 – View和Model确实是分开的,但是View和Controller却是紧密耦合的
  • 可测试性 – 由于糟糕的分散性,只能对Model进行测试
  • 易用性 – 与其他几种模式相比最小的代码量。熟悉的人很多,因而即使对于经验不那么丰富的开发者来讲维护起来也较为容易。
MVC

这里MVC就不多说了,相信大家对它是最先接触也是最熟悉的了。

2. MVVM

  • 任务均摊 – 事实上,MVVM的View要比MVP中的View承担的责任多。因为前者通过ViewModel的设置绑定来更新状态,而后者只监听Presenter的事件但并不会对自己有什么更新。
  • 可测试性 – ViewModel不知道关于View的任何事情,这允许我们可以轻易的测试ViewModel。同时View也可以被测试,但是由于属于UIKit的范畴,对他们的测试通常会被忽略。
  • 易用性 – 在我们例子中的代码量和MVP的差不多,但是在实际开发中,我们必须把View中的事件指向Presenter并且手动的来更新View,如果使用绑定的话,MVVM代码量将会小的多。
MVVM
  • Controller主要作为调度者,居于中心位置。客串部分View相关功能。
  • ViewModel专门做“显示逻辑”,并且用属性观察者做绑定,必要的时候用Notification。
  • 在Swift中,ViewModel和Model推荐用Struct;Logic倾向于用class。从一个简单直观的概念来说,ViewModel需要保持轻量级,跟随页面走,随时准备修改。Model也是轻量级,跟随后台API定义走,只是个数据结构,随时准备修改。而Logic就显得比较大,考虑稳定,考虑复用。
  • 增加Logic类,负责业务逻辑,比如从网络取数据,修改数据库,检查用户名合法性,具体的响应逻辑,监听后的具体处理等等。

3. VIPER

  • 任务均摊 – 毫无疑问,VIPER是任务划分中的佼佼者。
  • 可测试性 – 不出意外地,更好的分布性就有更好的可测试性。
  • 易用性 – 最后你可能已经猜到了维护成本方面的问题。你必须为很小功能的类写出大量的接口。
VIPER
  • View: 也是View + Controller
  • Present:相当于ViewModel,叫展示器
  • Interactor:交互器,侧重于业务逻辑;从网络取数据,数据库等功能都在这里。
  • Entity:就是Model,仅仅是数据定义
  • WireFrame:就是Router,是页面跳转

参考文章

1. iOS应用架构谈 开篇
2. 我们常见的分层架构,有三层架构的:展现层、业务层、数据层。

后记

上面很多都是一些大牛的技术经验之谈,感兴趣的给个赞或者关注,谢谢~~~~

你可能感兴趣的:(架构之路 (二) —— APP架构分析(一))