Tag: 清洁架构

适用于iOS开发人员的SOLID原则

接受原则,而不是架构 这些原则一起使用时,旨在使程序员更有可能创建易于维护和随时间扩展的系统。 SOLID Principles是用于以适当方式开发软件以避免错误设计的编码标准。 它是由Robert C Martin推广的,并在面向对象的设计范围内使用。 如果正确应用,它将使您的代码更具可扩展性,可维护性,逻辑性和可读性。 SOLID原理中的原理是什么? SOLID原则不是规则,不是法律,也不是完美的真理。 这是对良好的软件设计的建议,该软件设计既不严格也不脆弱。 对原理和模式的了解使您有理由决定何时何地应用它们。 如果您不了解它们,那么您的决定就会更加武断。 SOLID是五项设计原则的首字母缩写,旨在使软件设计更加易懂,灵活和可维护。 SOLID原理是Martin在2000年提出的。 在阅读有关原理时,您将遇到两个术语“刚性”和“脆弱性”。 让我们讨论一下它们是什么: 刚性:当更改导致相关模块中其他无关的更改时,软件变得难以更改。 简单的更改变得昂贵。 硬代码是具有依赖性的代码,这些依赖性会在很多方向上产生作用,以至于您无法进行孤立的更改而不更改其周围的所有其他内容。 —罗伯特·马丁 例如,您尝试更改数据层中的一些底层细节,突然之间,在为您的View进行格式化的类中遇到了编译错误。 如果您经常发现自己几乎触及了项目的所有文件,那么只要您在单个类中进行更改,就会出现僵化代码的症状。 易碎性:易碎代码比敏捷代码更糟糕,因为它不会产生编译时错误。 修复程序引入了会导致回归问题的新错误。 易碎的代码以您无法预测的奇怪方式中断。 —罗伯特·马丁 这里解释原理的内容太多了。 我将为这些原则提供专门的职位。 S —单一责任原则 O —打开/关闭原理 L-Liskov替代原理 I —接口隔离原理 D —依赖反转原理 感谢您阅读文章。 您可以在以下位置找到我: Linkedin: Aaina Jain 推特: __aainajain

使用VIPER架构构建Todo List iOS应用

介绍 确定构建iOS应用程序时使用哪种应用程序架构是最具挑战性的任务之一,可以从MVC,MVVM,MVP,View State,VIPER等众多架构中进行选择。 我们选择的体系结构将决定软件的构建方式以及随着软件的扩展而扩展。 本文将介绍的架构之一是VIPER架构。 VIPER以单一职责原则将应用程序结构划分为模块/屏幕内的组件。 这使应用程序变得更加模块化,并且与其他组件的耦合更少。 由于每个组件之间的边界(协议/接口),单元测试和集成测试变得更加简单。 VIPER的基本组件分为5部分: 视图:显示演示者告诉的用户界面,还将用户输入传达回演示者。 交互器:处理应用程序的业务逻辑,它与演示者进行来回通信 演示者:从交互器获取数据,并处理如何在视图中显示数据的逻辑。 它还从视图中继用户输入,并从交互器获取/更新数据。 实体:交互器使用的模型对象。 通常,交互器从单独的数据存储对象中获取实体。 路由/线框:处理演示者对象询问的导航逻辑。 它与要显示的其他模块/屏幕进行通信。 使用VIPER构建我们的待办事项列表应用 在本文中,我们将使用VIPER作为我们的应用程序体系结构构建一个简单的TodoList应用程序。 项目GitHub存储库可在此处获得。 我们将建立: TodoItem实体和TodoStore:TodoItem是代表Todo项的基本Class对象,TodoStore是存储TodoItem数组的DataStore。 TodoList模块/屏幕:向用户显示UITableView中TodoItem的列表,并为用户提供添加新TodoItem,删除TodoItem以及导航至TodoDetail模块/屏幕的功能。 TodoDetail模块/屏幕:显示TodoItem的内容,为用户提供删除和编辑TodoItem的功能。 它导航回到TodoList模块/屏幕。 应用程序委托集成:通过从TodoListRouter实例化TodoListView来设置应用程序的根UIViewController 建筑数据实体 TodoItem实体 TodoItem实体只是代表TodoItem对象的普通类。 它提供2个属性,标题字符串和内容字符串。 TodoItem实体 TodoStore数据存储 TodoStore是存储TodoItem列表的DataStore Singleton对象。 我们的应用程序只是将数组存储在内存中,但是将来我们可以扩展以将数据存储在File或CoreData中。 它通过todos属性和方法公开TodoItem数组,以添加TodoItem并删除TodoItem。 TodoStore 构建TodoListModule / Screen TodoListModule协议 我们为每个组件使用协议来定义每个组件如何在TodoList模块中进行通信的边界。 TodoListModule协议 实现TodoListViewProtocol 我们创建一个子类UITableViewController的TodoListViewController对象,并实现TodoListViewProtocol。 TodoListViewController的职责是按照演示者的指示显示用户界面。 它保留对演示者的引用,以中继用户输入并查看生命周期事件以使演示者做出反应。 当视图出现时,它将调用演示者viewWillAppear方法,以便演示者可以从交互器检索数据。 导航添加栏按钮项触发一个操作,该操作将显示带有2个文本字段的UIAlertActionController,供用户输入TodoItem的标题和内容。 然后,它将用户输入中继回演示者。 当用户滑动UITableViewCell并删除该行时,该视图会将用户输入重定向以将关联的ToDoItem删除回呈现给演示者。 TodoListViewProtocol提供2种方法来实现,showTodos传递ToDoItem数组,该数组将用于在UITableView内部显示TodoItem的列表。 如果演示者发生错误,showErrorMessage会传递一条错误消息,该UIAlertController将显示给用户,其中包含错误消息。 TodoList视图 实现TodoListPresenterProtocol […]

测试仪或方案接口BDD和体系结构MVVM

在应用程序界面上倒入测试仪,在界面上进行测试时应遵循的原则,或者在最佳方式下可以使用此方法。 检验界面的刚度,强度和脆弱性 。 借用:解决方案选择的技巧,未经测试的临时执行子接口。 Ils nesont pas force与工业化完全兼容(例如:une executiondéclenchéeau commit)。 德,法执业者和劳力士。 僵化 : 更改设备的测试界面,维护时间不长。 脆弱 :经验丰富,执行力十足,而詹姆斯·加兰蒂则无能为力。 最好的解决方案,最好的方法是合理的使用。 识别和测试双重接口的界面(KeyFeature) 。 Ces parcourscléssont la raison d’êtrede votre应用程序。 倒入商业应用程序:测试或测试面板。 在界面上倒入测试器,并在其他可信任的地方使用BDD( 行为驱动开发 )。 一流的测试人员和界面的测试人员 ,快速和强大的测试人员,可以很好地融合各种测试方法 ,以方便地定位和应用这种界面。 联盟架构MVVM ,最简便的BDD接口测试仪。 Un BDD peut tester la dynamique UI: d’un change de de couleur ou d’image 禁忌的立场 d’un segue ou de l’apparition d’un弹出窗口 […]

威伯·斯威夫特

NavigationController对View,View to Presenter,Presenter to Interactor和Router都有很强的引用。 因此,我们让NavigationController包含所有模块。 结果,此解决方案使我们可以在将ViewController从NavigationController中删除后销毁所有模块。 TableViewDelegate和TableViewDataSource 我们建议使用的方法不是唯一可能的方法。 创建它是为了没有更好的东西。 让我们用一个例子来展示它。 这里有一系列的人类对象,它们是通过一些API异步接收的。 人类具有以下特性: –名称:字符串; –年龄:整数; –照片:UIImage; 为了显示信息,UITableView正在使用。 人的名字,年龄和照片被加载到一个单元格中。 VIPER原则之一说View是被动的,但是Presenter不能向View返回任何内容。 视图应具有设置器,Presenter用来显示信息。 问题在于它仅适用于已创建的对象,而不适用于动态创建的对象。 这意味着您不能为每个单元格写一个setter。 这是为什么? 首先,编写应用程序时,单元数是未知的。 其次,为相同的对象编写setter是愚蠢的。 解: 让我们为View内部Human的每个属性创建一个变量,然后为每个新变量添加一个setter。 接下来,在Presenter中创建一个方法,该方法从Interactor获取数据并将其设置为View中的“ currentHuman”变量: 这样,每个单元格都填充有正确的数据。 它破坏了原理,该原理说View除了对UIViews和Presenter的引用外不应有任何其他内容。 但是它遵循另一个规则,并且代码仍然可以测试。 PS:本文由BytePace移动开发人员撰写。 您可以在这里查看他的作品和其他文章:http://bytepace.com/

iOS:Swift中的存储库模式

在上一篇文章中,我们有机会从概念上定义应用程序的体系结构。 这篇文章的目的是深入了解我们正在使用的该体系结构的关键组件的实现。 在这篇文章中,我们将讨论如何实现: 储存库模式 存储库模式是一种软件设计模式,可提供数据抽象,以便您的应用程序可以使用具有接口的简单抽象。 使用此模式可以帮助实现松散耦合,并且可以使域对象的持久性忽略。 它还使代码更具可测试性,因为它允许我们注入实现该定义接口的模拟存储库作为依赖项。 在Tiendeo iOS应用程序中,此模式使我们可以从数据层抽象域层,还可以在数据层内部从其数据源(Web API,Realm,用户默认值等)提取数据存储库。 让我们以一个简单的方案来看它: 在域层中,我们定义了一个RepositoryProtocol ,它允许我们按照依赖关系规则从数据层中抽象出域层(业务逻辑),这是干净架构中建议的。 (+信息) 让我们看一个常见的例子: 但是有很多RxSwift运算符可以在许多情况下为您提供帮助。 如果您对此感兴趣,我们会在其他文章中讨论RxSwift运算符。 希望您发现这篇文章有趣并且对您的项目有用。 任何问题或评论都将受到欢迎! 谢谢,祝你好运! 相关文章 在以下文章中,我们详细介绍了架构中的其他关键组件: Tiendeo应用程序中的MVP清洁架构 依赖注入 RxSwift +干净的架构

iOS应用程序的清洁架构

VIPER推广了适用于iOS的Clean Architecture。 与Bob叔叔的原作相比,这是一个很小却根本的区别! 在过去的一年中,我非常高兴与业务中的朋友讨论可以在iOS *中使用的各种架构模式。 讨论通常会回到“清洁建筑”一文中的想法。 我们尝试在iOS应用程序的上下文中了解它,以及它如何与平台的其他惯用模式(如模型视图控制器和情节提要)相适应。 一个反复出现的主题是理解“ Presenter ”的“ 正确 ”角色-最具体的示例在使用VIPER架构iOS应用程序中进行了详细介绍。 VIPER作为第一个可行的示例很受欢迎,并且很好地解释了Bob叔叔的适用于iOS的Clean Architecture方法** 与原始资料进行更仔细的比较后,发现在Presenter上,Clean Architecture和VIPER之间存在无法解释的不一致,这似乎是很根本的。 VIPER建筑 通过以下简单说明,我们介绍了Presenter在VIPER中的角色: 演示者:包含视图逻辑,用于准备要显示的内容(从Interactor接收) 和对用户输入做出反应 (通过从Interactor请求新数据) 清洁建筑 在我们将其与原始“清洁架构”文章中的图表进行比较之前,这似乎是合理的。 你看见了吗? 这条无痛的粉红色小线几乎是在事后想写的! 继续说明: 这些模型可能只是从控制器传递到用例 ,然后从用例传递到演示者和视图的数据结构。 注意控制流程。 它从控制器开始,遍历用例 ,然后在演示者中结束执行。 另请注意源代码依赖性。 他们每个人都指向用例。 当您看到所有参与者的更详细的时序图时,这可能会变得更加清晰(也许)。 一个方向 VIPER采用传统的堆栈体系结构方法,其中通信是双向的,例如向下流经各层,然后再次进行备份。 在“干净的体系结构 ”中,控制流只能沿一个方向传播。 视图->交互器->演示者->视图 演示者不是View和Interactor之间流程的中央协调者,它的唯一职责是作为接口适配器,将来自Interactor的输入转换为方便的东西,例如View Model跨越边界。 就这样-很小但很重要的变化。 突然,体系结构变得越来越简单。 单一方向上的控制流非常可爱,其好处似乎有几个: 关于架构的更容易推理 改善关注点分离 删除Presenter Interactor之间不必要的样板 消除诱惑以拦截通过Presenter的输入 更加遵守依赖性规则 如果您使用VIPER,那么您可能已经在项目中看到了Clean Architecture的大部分好处。 更改为“更清洁的体系结构”可能不值得在您的团队中展开辩论。 也就是说,在实现下一个功能时可能值得尝试。

使用MVVM清理架构

在本文中,我们将特别讨论使用DDD,TDD和MVVM的iOS应用程序的Clean体系结构。 通过分层实现关注点的高级分离。 干净的体系结构看起来是一个非常仔细的思想和有效的体系结构。 它极大地认识了用例和实体之间的不匹配,并将前者置于我们系统的主导地位。它还旨在最大程度地独立于任何可能妨碍应用程序可测试性或替换性的框架或工具。 。 实体:包含企业范围的业务规则。 用例:包含特定于应用程序的业务规则。 接口适配器:包含用于外围技术的适配器。 在这里,您可以期待MVC,网关的实现 框架和驱动程序:包含诸如数据库或框架之类的工具。 默认情况下,您在这一层中不需要编写太多代码,但重要的是要清楚说明这些工具在体系结构中的位置和优先级。 灵活 可测 容易明白 高维护性 可以与DDD等最佳做法很好地配合 尖叫-用例在项目的结构中清晰可见 复杂 学习曲线:比其他样式更难掌握 间接的-接口的数量可能超出人们的预期(我认为它不一定很糟糕,但是我看到人们指出了这一点) 没有惯用的框架用法-在这个领域,依赖规则是无情的 繁重的-从某种意义上讲,您最终可能会获得比当前项目中更多的类(同样,多余的类不一定很糟糕) 何时使用干净的体系结构:团队是否熟练和/或足够有信心,系统是否会比主要框架发布的版本有效? 系统是否会超过开发人员和利益相关者的就业机会? 交付模式,例如(MVVM,MVC,MVP) UIViews和UIViewController的位置 完全独立于平台 域的具体实现 隐藏所有实施细节 基本上,您的应用程序是什么以及它可以做什么(实体,UseCase等)。 它没有实体之外的实现 下载样例项目 ITHHKN /带有MVVM的清洁架构 使用MVVM清理架构–在本文中,我们将了解如何使用以下方法为iOS应用程序实现清理架构: github.com 参考: https://github.com/sergdort/CleanArchitectureRxSwift http://pguardiola.com/blog/clean-architecture-part-2/

iOS:Tiendeo应用程序中的MVP清洁架构

Tiendeo移动部门在2017年面临着巨大挑战:从头开始重新制作该应用程序。 我们的旧版应用程序创建于2013年。它是使用简单的MVC架构,Objective-C(当然)构建的,它使用RestKit,AFNetworking和许多其他Pod …经过多年的开发和一些开发人员,它变得庞大,不可扩展,不稳定,具有大量的视图控制器,大量的AppDelegate,一些新功能都在Swift中进行了编码,还包含一些重构的部分,因此我们很少有Swift-Objective-C桥,……这是一个为孩子们吃早餐的怪物。 考虑到所有这些问题以及业务方向的一些变化,该公司与移动部门一起决定重新制作该应用程序。 ✨ 因此,尽管我们为旧版应用程序提供了少量维护,但我们开始同时为Android和iOS两个平台构建新的应用程序。 这个事实标志着我们将使用的架构。 干净的建筑 我认为,根据我的经验,现代应用程序体系结构必须健壮,稳定,可扩展,可测试,适应更改和可维护。 我认为干净的架构可以提供所有这些功能。 基本上,干净的体系结构使用依赖规则将代码构建在同心层中: 内圈中的任何人都无法完全了解外圈中的任何事物。 特别是,在内圈中的代码不得提及在外圈中声明的名称。 其中包括功能,类。 变量或任何其他命名的软件实体。 只有一条规则! 太酷了! 👌内部层包含业务逻辑,中间层包含控制器和用例,外部层包含UI,框架,DB等。 当系统的任何外部部分(例如数据库或框架)变得过时时,都可以通过这种方式构造代码,您可以用最少的麻烦替换那些过时的元素 。 存档的一些关键技术优势包括: 实现的抽象 单一责任原则 关注点分离 解耦代码 在进行了这一简短介绍之后,让我们回到我们的故事! MVP +清洁架构 我们决定在两个平台上都使用ReactiveX来应用MVP和干净的体系结构。 我们还尝试在两个平台上保持相同的类和函数命名。 以这种方式保持两个平台同步对我们来说真是太棒了,因为当我们计划新功能或讨论错误等时,两个团队都在谈论相同的组件,相同的结构,几乎相同的方法名称,即使一个开发人员想要切换到在另一个平台上,这种方式要容易得多。 构成我们的体系结构的层是: UI层 域层 资料层 这是体系结构的方案: 让我们来研究一下: UI层 我们将MVP用于UI层。 我们使用依赖注入将依赖项注入到Presenter中,例如:用例,自定义对象等。 Presenter在用例和视图控制器之间居于中间。 它处理用户交互,启动适当的业务逻辑并将响应发送到视图控制器。 Presenter不会导入UIKit类以使其更具可测试性。 UI层具有与域实体不同的自己的视图实体。 域层 业务逻辑层。 每个用例都是执行特定业务逻辑的可重用且独立的组件。 域层对其他层一无所知,只是从定义为协议的存储库中获取数据并返回结果。 域层具有其自己的域实体,不同于视图数据实体。 资料层 它使用存储库模式(+ info)。 基本上,存储库模式在数据源上添加了一个抽象层,用例从中获取数据。 使用存储库模式,您只需一个入口即可查询来自不同数据源(核心数据,领域,Web服务器等)的模型对象。 业务逻辑不应该知道数据来自何处。 […]

在Swift中使用Clean Architecture的外部依赖关系

与你们中的许多人一样,我们一直在为GDPR做最后的冲刺。 而且我们意识到我们的应用程序与外部SDK有很多依赖关系 。 市场营销需要新的跟踪, 导入SDK-A 。 我们需要深度链接, 导入SDK-B ,我们还需要跟踪广告, 导入SDK-C ,有关应用程序通知的信息… SDK-D … 🐞问题 所有这些花哨的SDK给我们带来了很多问题 您见过这样的AppDelegate吗? func appDidFinishLaunching … { Firebase.setup(“ 32FD-324AFF-12FD4D”) Firebase.logLevel = .verbose AnotherSDK.start() AnotherSDK.startSomething() AnotherSDK.disableSomething() AndAnotherSDK.doAnotherConfiguration() 返回真 } 如果我们有一个新的Swift版本,我们需要等到所有这些SDK更新之后。 使用Cocoapods时,干净的编译可能会花费很长的时间,因为我们需要重新编译所有这些漂亮的依赖项。 我们决定使用SDK-A,在没有真正注意到的情况下,我们50%的类都在使用SDK-A的API。 如果SDK-A的所有者决定关闭此漂亮的工具怎么办? 它还将关闭我们的应用程序! 我们都是这些SDK的奴隶! 更有趣的是:使用GDPR,用户必须控制所有这些SDK。 等一下,不要和市场营销人员打架! 🏆清洁建筑 是时候为这些混乱带来一些秩序了。 外部依赖项需要成为我们应用程序的插件! 应用程序使用Crashlytics,Appsee,控制台报告崩溃,将其存储在文件中或将其打印在纸上并不重要 。 这些只是细节。 💉依赖注入 因此,让我们开始构建一个我们可以注入的协议(因此可以在单元测试中对其进行模拟。) ⚙️模块 请务必注意, 唯一的公共API必须是ExtenalDependenciesInjection。 因此,我们可以将整个实现带到另一个模块中。 之后,我们可以将该模块导入到我们的应用中。 甚至在许多应用程序中重复使用此模块。 因此,我们不必经常重新编译所有这些外部依赖项。 您的编译时间将更快,CI服务器也会更快。 […]

iOS:Swift中的依赖注入

在上一篇文章中,我们有机会从概念上定义应用程序的体系结构。 这篇文章的目的是深入了解我们正在使用的该体系结构的关键组件的实现。 在这篇文章中,我们将讨论如何实现: 依赖注入 我认为James Shore的这段话定义了依赖注入是什么: 依赖注入意味着给对象一个实例变量。 真。 而已。 依赖注入是一种软件设计模式,可以帮助您使代码更具可测试性,从而减少耦合。 习惯性依赖注入模式面临单例模式。 我认为,根据我作为iOS开发人员的经验,我建议在大多数情况下使用依赖项注入模式,因为除其他外,它在测试期间隔离类非常方便。 尽管这两种模式在每种情况下均有效,但是由于项目的某些组件在某些访问模式下可以更好地工作。 有一些替代方案,例如Swinject,可以在项目中实现依赖项注入,但是在向项目添加新的依赖项之前,我们希望向我们提出一个关键问题:确实有必要吗? 我们可以解决这种需求而无需添加第三方依赖项吗? 在这种情况下,我们认为可以,可以! 我们意识到我们实际上并不需要任何外部库,这就是为什么…… 让我们以应用程序中一个常见情况的示例开始实施: 您有一个带有Presenter的UIViewController。 该Presenter需要一个对象来填充视图,并具有从存储库中获取数据的用例。 我们的建议是定义一个带有一系列方法的协议,这些方法将接收返回准备使用的实例所需的所有实例变量。 我们将此协议命名为Assembler 。 注意,我们需要初始化用例存储库,以将用例注入演示者。 现在,我们可以使用此协议来实例化UIViewController: 结论 使用这些汇编程序来解析程序依赖性的优点是: 没有第三方依赖性。 输入解决依赖性所需的参数,因此开发人员不会犯错误。 要实例化一个组件,您需要解决其依赖性,这可以保证其行为良好。 该应用程序的每个组件都是分离的,可以进行注入模拟测试。 帮助您避免使用共享实例。 (…或至少让​​您考虑是否必要) 希望您发现这篇文章有趣并且对您的项目有用。 任何问题或评论都将受到欢迎! 谢谢,祝你好运! 相关文章 在以下文章中,我们详细介绍了架构中的其他关键组件: Tiendeo应用程序中的MVP清洁架构 RxSwift +干净的架构 储存库模式 这个实现受到了这篇文章的启发。