务实的iOS App架构
【原文】https://medium.com/@martinmitrevski/pragmatic-ios-app-architecture-f7d6334fd8e4
关于iOS App架构的文章有很多,解决方案有很多,其中也不乏设计精巧的架构。但是没有一种架构适合所有的场景。But,如何选择、取舍呢?下面的评估中有几条参考规范。
Evaluating architecture
app中的每个模块都应该精心的组织并解耦。模块之间不需要知道彼此的内部详细情况。
架构要表达出项目所属的商业领域。这是新加入成员能够快速从代码中获取到的信息。对于维护和扩展一个产品,架构能进行“自我介绍”是至关重要的。特别是,在不断地往里面添加人手的时候。
可扩展性。是否容易往里面添加新的特性。拥有一个优雅的解决方案可以在未来帮你节省大量的时间和金钱。
架构是否满足商业领域的需求。app是以大量数据驱动的?还是有大量需要用户填写的表单?app的复杂程度,是只有五个页面还是有50个页面?
开发团队的工作效率。团队是否可以快速的理解新的架构和不懂得概念?是否可以无障碍的独立进行开发工作?可以想象你的架构中只有一个storyboard,在多人协作并且都编辑storyboard的情况下,合并代码的时候可能会掉进坑里!
测试是选择架构的另一个重要因素。那个关键模块是我们想要测试的?只对值得测试的部分进行测试,不要为了代码覆盖率(code coverage)而进行测试。你可能有90%的代码覆盖率但是却没有覆盖到至关重要的部分。另一个极端的情况,完美的项目设计,彼此分离的模块,但是代码覆盖率却是0。
现实情况——另一个至关重要的部分。项目的截止日期和预算情况如何?在质量和交付日期之间如何取舍?工程师需要更多的时间用最优的方式去设计和实现项目,但销售人员追求的却是快速。每个人都有自己的关注点,我们需要有意识的在两只之间的进行平衡。低劣的产品不会持久,但是迟来的产品也会被市场所淘汰。
因此,实用、中立(neutrality)、大局观,正是这些方面驱动着我决定采用什么样的架构。
The good old MVC (经典架构 - MVC)
相当困惑,为什么那么多人都放弃实用MVC模式?有人说它代表着复杂笨重的View Controllers,不适合大型项目。但是我们有很多概念和模式可以帮助减小View Controllers的大小。比如: delegation(代理), composition, dependency injection, protocols(协议), pure functions(唇方法), service / utility classes, navigation centers等。这些技术手段使得测试并不是那么的困难。
MVCGoing reactive
当然,这还要看app的类型,像facebook这种数据驱动的app就不适合使用MVC,fb里面有太多的cells和内容,使用经典的MVC几乎不太可能。一个带有数据流的更加被动的方案更适合这种情况(A more reactive approach with uni-directional data flow is more suitable in such cases.)。有一个很棒的fb架构演示可以在这里查看。
MVVM
区别于流行于iOS领域的其他模式,MVVM是另外一种有趣的设计模式。具有挑战性的是它可能会让你的项目更加依赖像RxSwift这样的第三方框架。MVVM由Microsoft发明,而且由于他的本地数据绑定使得它极为好用。有时你甚至会有这种感觉:你通过它与iOS SDK fight。另外一个具有挑战性的方面是团队的学习曲线,这是由于它不同以往的编程方式造成的。不管如何,它都是对MVC的一次升级,是选择架构时的一个有价值的参考项。
MVVMClean Architecture with VIPER and Clean Swift
Robert C. Martin,世界级软件开发大师,设计模式和敏捷开发先驱,敏捷联盟首任主席,C++ Report 前主编,被后辈程序员尊称为“Bob大叔”。
有这样一个有趣的引述:VIPER就是当你允许java企业开发者进入iOS领域将会引发的一些事情(VIPER is what happens when you allow Java enterprise programmers into the iOS world.)。VIPER会最大限度的分离关注点且极易测试,这既符合Uncle Bob 的整洁架构思想。但是,再带来诸多好处的同时,还存在着一些麻烦,比如:太多的模板代码、太多不同的部分、可能过度的设计。有时应用VIPER的项目看起来可能及其整洁,但是当你进行一个极小的改变的时候可能会影响到app的很多层(牵一发而动全身)。那它还值得采纳吗?答案是,看上面讨论的诸多因素而定。
VIPERVIP或者Clean Swift是整洁架构的另一端口,这和VIPER有相似之处。从表面上看它看起来挺好的,但是(我)没有实际的经验。现在有很多不同的低耦合的组件来让你的应用变的更易测试、更加健壮。Xcode中也有模板绑住你从零开始。
Plugin architecture
还有一种不同的方式,就是Eclipse鼓励的插件架构。
首先这种方式解决什么样的问题,以及为什么我们决定使用它?Well,有这样一个项目——用户并不知道最终产品应该长什么样子。我们有一个创建灵活的框架的任务,使用这个框架我们可以创建很多由几个可组合的模块组成的不同的应用。客户可以用他们来进行A/B测试,找出用户想要的关键特征。例如,在其中一个app中包含两个模块,而在另外一个app中则包含5个模块。菜单是可插拔的,这意味着我们可以轻松地把tiles菜单替换成旋转菜单、导航抽屉或者tab bar。超级灵活!最酷的事情是我们可以通过文件对app的外观和感觉进行配置。这意味着只要后台的一点小小的改变我们就可以触发一个完全不同的app。
Plugin ArchitectureApp容器知道如何为app读取配置信息、展示模块。但它不知道应该展示那个模块,抑或模块是如何实现的(原生,混合)。
各个模块是彼此独立的,因此开发者可以完全的进行独立开发。为了与各模块进行交互,开发者需要在容器中实现一些必不可少的方法。模块需要提供扩展点,在这里你可以注入其他模块的功能。
做到这些需要大量使用协议(protocols)。这个架构能很好的满足你的需求。然而,这样还存在一些挑战,例如:模块间的通信难问题和代码复用问题(因为模块之间是彼此独立的)。
Uni-directional data flow(单向数据流)
配合着单向数据流使用还有一种有趣的架构。受到Redux、Flux、ReSwift及其他相似架构的项目的启发,可以使用单一的数据结构展示app的状态。在这个数据结构保存着app使用中的的UI和models的状态。Views订阅并对任何的状态改变进行相应的相应——他们是观察者。只能通过向保存app状态的存储器发送消息才能改变状态。通过使用减速器(reducers)展示状态的改变。这种类型的架构可以更容易的帮助你解释程序的状态。当需要恢复之前的状态的时候(例如:撤销功能),它们的用处的真很大。然而,时间将会告诉你这个架构是否适用于更复杂的app。
Conclusion
应该选择什么样的架构呢?当然,并没有直截了当的答案。如果答案很明显的话就不会出现那么博客和讨论了。大家总是能够选择最好的(最合适的)其中一个。诚然,不同的架构在给定的问题领域中可能会有不俗的表现。对于这个话题你是如何想的?有没有一个完美的app架构?