Tag: 软件架构

毒蛇的第一个项目

在完成我在Viper的第一个项目之后,这篇博客文章只是一些个人经验。 如果您以前从未听说过Viper和干净的体系结构,则应该明确地观看此视频: 最初,一切都进行得很顺利,当我独自从事该项目时,我对自己感到非常高兴。 但是随后另一位开发人员加入了🙂他的第一个反应并不令人鼓舞: 男人,这个毒蛇的东西有点冗长。 我在各处写协议和存根…… 因此,我再次查看了代码。 好吧,他是对的。 如果您遵循这本书,最终会得到很多协议,在大多数情况下只能使用一次。 那时的某个地方,我还观看了有关保持代码可持续性的视频: 类由不同颜色的圆圈表示,您在类中的依存性越高,圆圈越大。 中心的蓝色大圆圈是AppDelegate。 好吧,它保留了对某些顶级视图控制器的引用,处理了一些通知,初始化了一些数据访问对象。 似乎其中没有太多代码,但最终仍然有很多讨厌的依赖项。 如果您考虑一下,这是有道理的。 AppDelegate可以引用RootViewController,而RootViewController可以引用MenuViewController,依此类推。因此,依赖关系的增长。 第二张图是我的第一个Viper项目。 AppDelegate做得少得多。 基本上,它只是创建一个根线框并将控制权传递给它。 每个模块仅知道需要直接调用的模块。 当然,这是您在任何项目中都想拥有的东西,但是在Wireframes中进行所有设置会使依赖项更加公开,并有助于使模块具有针对性和隔离性。 我最喜欢的是: 错误少很多。 它们几乎没有,而潜入其中的那些易于修复。 代码变得更像可互换的乐高积木。 使用现有模块组装新模块,重新组装旧模块,引入接口并为某些类添加不同的实现,所有这些都很容易做到。 我认为,这种方式的主要原因是依赖注入以及线框中所有模块的创建/组装。 再一次,重构非常容易。 想象一下,更改应用程序的整个导航树不会再让您感到恐惧🙂 几个月后,我很想再次查看该项目。 但是到目前为止,它看起来非常有前途!

另一个干净的架构

你在跟我开玩笑吗? 还没有足够的干净架构模式吗? 是的,有。 像VIPER / Riblets一样,它们都是完全相同的清洁体系结构原理的不同方法,但是它们在细节或处理某些元素的方法上有所不同。 一切始于著名的Bob叔叔的文章,因此请务必查看一下。 我们在这里介绍的是我们在Tooploox成功介绍的一个(感谢出色的Jorge Ortiz研讨会,不要错过他的作品)。 事实证明,这对我们的工作流程和代码质量非常有用,我们希望通过本系列文章分享一些经验。 为什么架构很重要? 在考虑我们的应用程序体系结构时,我们不应该考虑是否使用一种,而是要使用哪种。 有效的体系结构有助于创建结构化,易于理解的代码,从而降低维护成本。 由于每个人都可以独立工作,因此将所有模块模块化可以使团队合作更加轻松和富有成效。 它有助于设计解决方案并减少出错的可能性。 不必担心事物如何协同工作或如何连接某些零件,您可以专注于实际的逻辑。 最后,它将项目管理提升到一个新的水平,即由于在熟悉的环境中使用了经过验证的模板,因此计划和估算更加准确。 它还降低了新团队成员的进入门槛,并使团队更加灵活。 那么,为什么不简单地使用MVC,MVVM呢? 为什么还要另一个复杂的解决方案? 别误会,MVC和MVVM是有效的体系结构。 他们各有优缺点,可以用来创建出色的解决方案,但它们确实有局限性。 通常,MVVM很难扩展。 毕竟,移动应用几乎绝不是仅有的一些功能和几种视图。 随着功能数量的增加,MVVM开始变得难以维护,视图模型变为大规模视图模型,因此很难将所有内容按原样分开。 另外,如果您关心单元测试,那么MVC / MVP / MVVM也不是最佳选择,因为出于测试目的而分离元素和模拟依赖项要困难得多,并且每个组件往往都有多重职责。 如果您曾经使用过MVVM,则可能已经注意到它不是完整的体系结构。 它缺少诸如路由或依赖性管理之类的一些基本层,并且通常通过引入协调器或强制破坏封装并使组件以非结构化方式相互通信来完成。 通过使用干净的架构,您的代码将变得更加模块化,结构更好和高度可扩展。 每个元素都是轻量级的,并且遵循(至少尝试)遵循单一职责规则。 通过控制反转,各层具有良好的分离性,因此组件易于更换。 使用这种结构编写单元测试很简单,可以模拟依赖关系,并且功能简单且易于进行单元测试。 通过松散耦合元素,可以对同一特征进行并行编码。 只需就协议和合同达成协议,然后做好您的工作即可。 使用功能要容易得多,因为您可以一次将精力集中在一个问题上,而不必关心其他任何事情。 硬币的另一面。 但这确实有一些缺点。 它很复杂,一开始有时很难理解,而且入门门槛很高。 它也有点肿。 您将创建很多不同的协议,类,工厂,并且您将必须管理所有文件。 这不是轻而易举的事情(记住缺乏适当的反思并不能帮助迅速进行依赖注入管理)。 这些文件/类中的许多都是简单的传递实体,因此有时感觉像是在浪费时间,但这是有原因的。 它还有点违反框架和官方准则。 Apple API被设计为可与MVC配合使用,因此有时您必须要有一些技巧才能使其与干净的体系结构相处。 最终,我们发现所有的努力都是值得的,缺点并没有真正掩盖我们作为团队所获得的收益。 确实,关于干净架构的资源并不多,可以通过实际示例逐步解释一切。 我们认为这是有时在移动开发中忽略更复杂的体系结构的原因之一。 我们想改变这一点。 让我们开始吧 干净架构的主要重点是将模块分为多个层:连接器,演示者,视图,用例和网关,这些层符合SOLID原则。 […]

iOS应用程序要求清单

当我们开始开发新应用时,通常会经过客户定义的要求,并开始考虑概念,体系结构和估计。 这些要求的范围可以从用几句话写成的模糊概念到带有模型,用例和接受标准的详细规范(很少有)。 但是,即使定义了产品的所有功能需求,也有一些事情被假定由客户完成,或者在定义规范时甚至没有考虑。 这可能是由于缺乏技术知识,假设或认为工作量太低而无法在以后定义的想法。 不幸的是,这些事情通常不会那么小,并且可能对项目成本产生重大影响。 这篇文章将探讨几种类似的情况,因此您可以粗略地概述并核对清单,以了解在项目开始时需要询问的内容。 在没有互联网连接的情况下使用应用程序可能会引起最大的误解之一。 如今,应用程序通常连接到后端系统上的REST服务,以获取所需的数据并将其呈现给用户。 当您有互联网连接时,一切都很好。 但是,需要尽快定义应用程序在您无法访问互联网时的行为方式,因为这会对项目的时间表和成本产生重大影响。 这里有几个选项。 这是最简单,最便宜的选择-如果没有互联网连接,该应用程序将无法运行。 每当对后端的请求失败时,应用程序应显示一个弹出窗口,指出发生了错误,并且需要显示该数据的屏幕为空。 这是一个更复杂的选项-您应该在连接可用时存储最新保存(或预先捆绑)的数据,并将其呈现给用户。 在这种情况下,您可以实现文件系统缓存,使用许多数据库选项之一,或者如果数据量很小,则可以摆脱“用户默认值”。 但是,您执行的任何需要在后端进行更改的操作(例如,我要离线添加产品)都是不可能的,并且会显示一个弹出窗口,您需要具有互联网连接才能执行此操作。 这是最复杂的选项。 它支持上面的只读模式,但是即使没有互联网连接,它也支持对数据进行更改。 为此,通常,您将需要在后端的数据库与移动电话上的本地存储或数据库之间实现同步机制。 同步机制需要进一步定义,因为其各种可能性会对项目的复杂性和成本产生不同的影响。 这里最复杂的部分是当移动应用程序和后端对同一组数据进行更改时会发生什么。 执行同步时,手机和服务器上的数据之间存在冲突。 有几种解决冲突的方法。 其中之一总是胜利 例如,可以说我们的冲突解决机制是从后端(或电话)获取最新更改并仅使用这些更改。 另一侧的更改将被丢弃。 这是最简单的选择,但它会导致丢失丢弃的数据,这对用户可能至关重要。 更好的选择是保留更改的时间戳。 当发生冲突时,我们将采用较新的更改并丢弃较旧的更改。 这种方法是对前一种方法的小升级,但是仍然会丢失数据。 两种方法中的快速优势就是要求用户选择他们想要保留的数据。 最复杂的方法是合并有冲突的数据,并以一种易于理解的方式将其呈现给用户,因此他们能够根据所做的更改查看要合并的数据。 它还应允许用户放弃合并并选择一侧或另一侧的更改。 类似于git或svn冲突解决方案。 如您所见,离线使用的复杂性从非常简单到非常复杂的实现不等,可能需要数周的开发时间。 很常见的误解。 如果该应用程序可以在iPad上运行,则应提前知道。 尽管每个负责任的开发人员都应使用自动布局,大小类和所有其他UI技术来实现灵活的布局,但这种要求需要事先知道,因为这可能会影响项目的组织和工作量。 另一个问题是iPad的屏幕要大得多,这意味着如果仅将iPhone应用程序缩放到iPad屏幕,则该应用程序的UI可能会非常空白。 要求iPad设计可以帮助计划和构建项目。 这同样适用于横向支持,在这种情况下,您始终应谨慎使用自动布局约束和对应用程序进行连续测试。 也应在项目开始时阐明受支持的最低iOS版本。 例如,请考虑以下情形:您需要开发增强现实应用程序。 您选择ARKit,开发所有内容,然后将要测试的应用程序发送给客户端。 但是,他们无法安装该应用程序。 他们的设备是装有iOS 10的iPhone 6。 您可以要求他们安装iOS 11,这已经引起了人们的注意,因为客户会急于检查市场上发行的OS版本。 iOS 10才使用了2年,因此缩小了该应用程序的市场规模。 当您最终说服他们安装iOS 11时,您意识到iPhone 6S及更高版本支持ARKit。 […]