实用的iOS应用架构

最近,我一直在阅读许多有关应用程序体系结构的文章。 有很多这样的文章,有很多不同的见解和解决方案。 开发人员分享他们的经验,优缺点可能会帮助我们决定在未来的项目中走哪条路,这是很好的。

我同意,有许多很好的架构,经过精心设计,并具有很好的关注点分离,可以解决其他方法的弊端。 但是,我也认为没有适合所有项目的应用程序架构。

我们如何衡量架构对项目是否有利? 好吧,我认为此评估中有几个相关参数。

评估架构

首先,应将应用程序的组件合理组织和分离。 他们不应该对其他组件的内部细节了解太多。

其次,正如鲍伯叔叔所说的那样,体系结构应该对项目的业务领域“尖叫”。 它是运输应用程序吗? 也许一个金融机构? 这是您从项目中获得的信息,只需以新手的身份快速浏览一下代码即可。 拥有不言而喻的架构对于维护和增长产品至关重要,尤其是在增加人员时。

然后,我们当然具有可伸缩性。 添加更多功能有多容易/难? 拥有一个优雅的解决方案可能会在将来为我们节省大量时间和金钱。

另一个参数是架构如何适合业务领域的要求。 它是繁重的数据驱动的应用程序吗? 它有很多需要用户输入的表格吗? 我们将要构建的应用程序的复杂性是什么? 是“ 5个屏幕”应用程序还是“ 50个屏幕”应用程序?

需要考虑的另一件事是开发团队的效率。 团队能否迅速了解新架构和可能不同的概念? 他们将能够独立处理功能而不会阻塞自己吗? 想象一下,只有一个故事板的架构,团队中的每个人都必须在用户界面上工作。 合并地狱等待发生。

测试是体系结构决策中的另一个重要元素。 我们要测试哪些关键组件? 在测试方面,我属于认为必须只测试值得测试的零件的小组。 我不喜欢做很多无用的测试,只是增加了代码覆盖率。 代码覆盖率只是一个欺骗性的统计信息。 您可能有90%的测试覆盖率,但是错过了关键部分。 在另一个极端,我看到了设计完美的项目,这些组件具有很好的隔离性,覆盖率为零。

在决定应用程序体系结构时,这使我想到了另一个关键部分-上下文。 项目的截止日期和预算是多少? 我们必须在质量(交货时间)上进行哪些权衡? 工程师需要更多时间以最优雅的方式设计和实施项目,而销售则需要更快的时间。 每个人都有自己的利益,我们必须意识到双方的平衡。 低质量的产品不会持续很长时间,但是市场上可能不再需要后期产品。

这就是为什么我认为在进行体系结构决策时,我们需要务实,中立和对全局的理解,而对我而言,这是做出此类决策的动力。 我们不需要偏向任何一种方法,也不应抛弃其他方法。 这只会限制我们的工具集,并在做出决策时缩小我们的可能性。

好老的MVC

我很困惑为什么这么多人只是放弃了Model-View-Controller模式。 他们代表Massive View Controllers。 它不适用于大型项目。 好吧,我已经看到(并从事过)非常大的项目,这些项目很好,干净且可维护,并且遵循Model-View-Controller。 我们有很多概念和模式可以帮助我们减小视图控制器的大小,例如委派,组合,依赖注入,协议,纯函数,服务/实用程序类,导航中心。 有了这些技术,测试也不是那么困难。

* MVC模式-图片取自Apple文档

变得被动

但是,当然,这完全取决于应用程序的类型。 诸如Facebook之类的数据驱动型应用程序可能不会从MVC中受益匪浅。 单元和内容的类型太多,几乎不可能在这里拥有良好的旧MVC。 在这种情况下,使用单向数据流的更具响应性的方法更适合。 查看有关Facebook架构决策的精彩演讲。

MVVM

与iOS世界中流行的其他模式相比,MVVM是一种有趣的模式。 我在带有RXSwift扩展的项目中使用了它,并且效果很好。 我面临的挑战是,这可能会使您的项目过于依赖第三方框架,例如RXSwift。 该模式是由Microsoft发明的,并且在那里效果更好,因为它具有本机数据绑定支持。 有时候,我感到我们在与iOS SDK对抗。 另一个挑战是团队的学习曲线,因为这是一种不同的编程方式。 无论如何,它是对MVC的良好升级,并且是您做出决定时的宝贵选择。

使用VIPER和Clean Swift清理架构

我读过一个有趣的引文,当您允许Java企业程序员进入iOS世界时,VIPER就是这种情况。 VIPER具有最终的关注点分离,可测试,并且遵循Bob叔叔的Clean Architecture。 但是,这些巨大的好处来自许多样板代码,太多不同的零件以及可能的过度设计。 我没有直接使用过-我已经对该项目进行了一项技术审查,我必须说它看起来很干净。 但是有时即使是很小的更改也可能会传播到应用程序的许多不同层。 这值得么? 答案是-这取决于上面讨论的许多因素。

VIP或Clean Swift是Clean Architecture的另一个端口,类似于VIPER。 从外部看,它看起来不错,但是没有用它来表达经验。 同样,这里有许多不同的解耦组件,它们有望使您的应用程序更具可测试性和健壮性。 有一些Xcode模板可以帮助您入门。

插件架构

我在其他文章中没有遇到过的一种不同的方法,但是我们在项目中使用的是Eclipse启发式插件体系结构。

首先,它可以解决什么问题?为什么我们决定采用它? 好吧,我们有一个项目,客户不知道最终产品的外观。 我们的任务是创建一个灵活的框架,该框架将构建由几个可组合模块组成的许多不同的应用程序。 客户需要用于A / B测试的功能,以找出用户想要的关键功能。 在一个应用程序中,我们有两个模块。 在其他5个不同的模块上。 菜单也是可插入的,这意味着我们可以轻松地用旋转圆圈菜单或导航抽屉或标签栏替换平铺菜单。 超级灵活。 最好的是,该应用程序的外观可通过文本文件进行配置。 这意味着我们可以通过在后端进行简单的更改来触发一个完全不同的应用程序。

应用程序容器知道如何读取应用程序的配置以及如何显示模块。 它不知道需要呈现哪些模块,也不知道如何实现这些模块(本机,混合)。

这些模块是独立项目,开发人员可以单独进行全面工作。 开发人员需要从容器中实现所需的方法才能集成到容器中。 模块还可以提供扩展点,您可以在其中插入其他模块的功能。

通用功能(网络库,数据层)提取到模块可以使用的核心库中。 构建系统结合了所有内容,并根据提供的配置创建了不同的应用程序。

这是通过大量使用协议来完成的。 该架构非常符合我们的要求。 但是,这里也存在挑战,例如模块之间更难的通信和代码的可重用性(因为模块非常隔离)。

单向数据流

我们将通过实验性的但非常有趣的架构以及单向数据流来完成架构之旅。 受Redux和Flux,ReSwift和其他类似架构的启发,它们在单个数据结构中表示应用程序状态。 在此数据结构中,我们保留UI和应用程序正在使用的模型的状态。 只要状态改变,视图就会订阅并做出反应-它们是观察者。 只能通过将操作发送到保存应用程序状态的商店来更改状态。 为了执行状态更改,我们使用减速器。 这些类型的体系结构将帮助您更轻松地推断应用状态。 当需要恢复过去状态(例如撤消功能)时,它们确实很有用。 但是,时间会证明它们是否适合更复杂的应用程序。

结论

那么您应该使用哪种架构? 当然,没有简单的答案。 如果答案如此明显,那么我们将不会有太多的博客文章和讨论。 每个人都可以一直选择最佳的。 同样,在给定的问题域中,几种不同的体系结构可能也非常有效。 您对此主题有何看法? 您是否有喜欢的应用程序架构?