Tag: 软件开发

走另一条路的6个步骤

尽管Bob叔叔警告The Dark Path时过多批评强类型编译器,但我认为还有很多需要考虑的问题。 除了使用使我们感到安全和免受空值引发的异常影响的编程语言外,您还可以采用很多其他途径,这些途径并不那么黑暗。 自动化测试 林亭 编码标准 代码评论 持续学习 建筑组织 自动化测试 正如Bob叔叔指出的那样,自动化测试非常重要。 它通常被视为与动态语言之间的平衡,动态语言在编译器中对强类型语言没有很好的保护。 JavaScript,Ruby和Python都从测试中受益匪浅,这些测​​试可确保代​​码正常工作,并且尽早发现并及时发现问题。 我认为我们都可以同意,可以全部自动化的单元测试,功能测试,UI测试和集成测试可以照亮黑暗的道路。 林亭 静态分析会在编译代码时生成警告和错误,涵盖了硬性要求和一些有力的建议。 但是编译器适用于计算机。 短毛绒为人们工作。 使用SwiftLint,可以识别代码的多种改进方式,并为项目的维护方式设定标准。 您可以从一开始就使用最少数量的棉绒规则开始,然后逐渐启用更多规则。 它确实可以帮助使代码库的外观和感觉更好,并且允许linter告诉您在提交更改之前可以进行哪些改进,从而可以减少代码审查中的反馈。 它还设置了编码标准,这是下一步。 编码标准 大多数编码标准都很轻巧,这很好。 最好使其简短而甜美。 如果不能轻易记住这些标准,就不会那么严格地遵循它们。 这些标准也应被视为准则,而不是硬性要求集,这些要求实际上可能会随着团队和所使用技术的变化而随着时间而改变。 新的思想和技术一直在涌现,而当前的编码标准可能会包含这些思想和技术。 代码评论 随时间推移设置编码标准的一种方法是使用代码审查。 当您的团队发现编码模式来鼓励或劝阻时,现在是开始就这些发现进行一对一对话的好时机。 随着对代码审查的反馈变得有些重复,可以将这些技巧写下来,以一种不太短暂的方式与团队分享。 代码审查的目的应该是一起学习并分享有助于提高代码质量的技巧。 代码审查不应该是变更需求的清单,因为它将迅速将过程转变为开发周期中不受欢迎的步骤,从而在团队中引起不满。 没有人想要。 而是将其视为分享技巧并更好地了解其他人如何进行软件开发的机会。 对于审稿人来说,这是一个学习和提倡更改的绝佳机会,一旦更改代码,更改可能会影响他们的工作。 持续学习 在常规代码审查期间,会发现许多有关代码更改的发现,以及有关团队中每个人的强项,弱项以及兴趣和激情的发现。 除了在编码标准中添加更多内容外,撰写内部博客文章甚至与团队建设相关的公共博客文章也很有帮助。 写下并分享您所学的内容是巩固这些课程的好方法。 有时不妨将这些课程中的一些内容介绍给整个团队,也许要点午餐,以供不时的午餐和学习 。 当发现兴趣和激情时,鼓励博客文章和演示文稿加倍努力学习并为团队造福的好提示。 建筑组织 最后,只需将所有工作分解成多个部分,以便团队的不同成员可以拥有不同的模块,这些模块就可以整体上取得很多进展。 首先,设计和计划一个定义明确,目的有限的模块要容易得多,可以对其进行构建和测试以表明其按预期工作。 其次,随着新成员加入团队,让他们一次在一个模块上加速工作并让他们在较短的时间内拥有它的所有权变得容易得多,这样他们就可以掌握它并尽快开始进行有用的更新。 第三,它使团队有机会按时处理不同的模块,以更多地了解项目的其余部分,并在此过程中了解他们的新知识。

您了解Swift中的延期吗?

几周前,我开始研究Golang,因为在Axiom Zen中我们已经使用了很多,而且我意识到它还使用了与Swift中基本相同的defer语句。 有趣的是,当我学习堆叠延迟时,我不得不停下来问自己。 Swift中的输出是什么? func some() { for i in 0..<10 { defer { print(i) } } } 由于Golang的延迟使用了堆栈,因此Go中的输出为9,8,7 9, 8, 7, …, 0 。 斯威夫特呢? 好吧,斯威夫特打印0, 1, 2, …, 9 。 因此,Swift使用队列,对吗? 错误! Swift中的defer也使用堆栈,但是defer语句的工作方式是指当前作用域 ,即,它仅在示例中的for范围内进行延迟。 每次通过for循环时,都会弹出defer堆栈 ,这就是为什么它以升序打印数字的原因。 如果是: func someOther() { defer { print(“a”) } defer { print(“b”) } } 正如我所期望b, a那样b, a这将堆叠延迟并仅打印b, a […]

在公司内部同步任务

我们的iOS分支模型 团队越大,当多个人在同一个代码库上工作时,发生问题的可能性就越大。 为了保证无障碍和协作的工作流程,仅知道您的git命令并不会削减它。 因此,有必要定义一个分支模型,以适应内部流程并限制从一群同步工作的人中出现的复杂性。 在Wolox,我们的目标是使开发人员更轻松地管理分支机构,同时在将构建发送给质量保证(QA)部门进行测试时,还节省了时间。 结果? 通过实施此模型,我们的产品质量得以提高,因为质量保证可以使用更完整的方法进行测试。 史诗(用户)故事 我们在iOS部门Wolox的分支模型基于Epics(即用户故事)的概念。 存在此类概念的几种不同定义,但是在Wolox,我们将它们定义为一组任务,这些任务具有完整的功能,可以为最终用户增加价值 。 史诗只有在其包含的所有任务完成后才有意义。 质量保证(QA) 与史诗打交道的主要优点之一是简化了开发人员和测试人员的质量检查流程。 在此模型中,一旦完成,我们就会向质量检查小组发送史诗。 这样,开发人员就不必为每个任务构建一个.ipa,从而节省了时间,并且质量检查团队可以测试其全部功能及其组件之间的交互。 这简化了两端的过程,并使测试人员的工作更有效,从而提高了产品的整体质量 。 我们的分行 主 在我们的master分支中,我们找到了最新版本。 该分支应始终包含工作和可交付的代码。 开发人员 开发分支从母版分支出来。 在这里,我们可以找到质量检查已批准的史诗。 在Wolox,我们使用Scrum,因此在每个sprint结束之后,在检查了此处合并的不同史诗是否相互兼容之后,我们将此分支合并到master。 根据您的方法或项目的具体情况,一旦向客户显示进度(内部或外部),您也可以合并以掌握。 请记住,master必须始终包含正确运行的代码,因此在合并时请谨记。 史诗-{史诗名称} 每个史诗分支都包含已被代码审查且提交请求已被批准的提交。 史诗般的所有任务通过我们的代码审查流程后,便会生成.ipa并将其发送给质量检查人员。 记住要先从开发者那里重新定位! *避免合并错误的一个好技巧是拥有受保护的分支。 {epic name}-{feature name} 每个功能都从其对应的史诗分支中分支出来。 在这里,开发人员进行必要的提交以实现任务或功能。 完成后,开发人员将史诗分支作为目标分支,从而打开一个新的请求代码审查请求。 让我们玩这个… 想象一个已经有几个发行版的项目,其中的master和dev是最新的。 在下一个冲刺计划中,我们决定开发三个新功能: 查看重新设计 新视图(视图B) 实施推送通知 因此,我们将根据dev创建3个新分支: 史诗般的屏幕重新设计 史诗般的画面B 史诗般的推送通知 我们必须为每个史诗选择一个所有者,然后由他负责在存储库中创建新分支,以便团队中的每个成员都拥有相同的分支。 此人还将在必要时创建测试计划,并在史诗完成后构建.ipa并将其发送给QA测试人员。 尽管该史诗具有所有者,但这并不排除其他开发人员在功能分支中从事史诗的工作。 同样,在sprint计划中,我们可以为每个史诗定义任务,或将任务留给每个开发人员或一组开发人员。 这些将是我们的epic-screen-B分支的四个功能: screen-B-设计,我们在其中实现视图和前端 […]

Swift —测试驱动开发(TDD)

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 代码测试是开发中至关重要的部分,以确保您编写的代码既可以执行预期的工作,又可以确保将来的更改不会破坏过去的工作(眨眼眨眼的持续集成)。 TDD,即测试驱动开发,它不仅是一个时髦的词,而且是一种非常有趣且易于使用的开发方法。 有了它,您应该首先编写测试,然后再编写使它们通过的代码: 编写测试(该测试将失败,因为您还没有代码!) 编写最少的代码以使测试通过 进一步增强您刚才编写的代码的测试 重构代码以使新测试通过 在添加测试和重构代码之间进行迭代,直到达到所需的功能和代码质量为止。 为了向自己介绍TDD方法,我遵循了Yvette Cook的TDD指南,因此您应该很清楚地解释该概念,并逐步指导您实施示例项目。 有几个吊舱可以使测试过程更加简化并简化编写测试的任务。 他们是: 快 敏捷 因此,接下来,我将展示您可以对它们进行哪些使用: 将两个Pod导入到项目中: 2.从以下位置更改标题: 至 3.代码在spec()函数中运行: 4.用beforeEach块替换setUp()块: 5.使用Nimble,我们可以使用更易于阅读的方法编写测试。 例如: 变成: Nimble不仅易于编写,而且还赋予您更多表达结果的自由,并且还建立在其他XCTAssert功能的基础上(例如,在测试网络请求时,指定异步期望非常简单)。 请查看Nimble的文档以获取更多信息。 您可以在下面找到进一步的比较: 而旧的(如果失败的话)将不会显示文本错误消息(除非我们指定自定义消息,例如XCTAssert(1 == 2, “your custom error message here”) ,它会采用Nimble方法,它将自动使用在it(“message”)标头中指定的描述。 通过使用这些Pod,我认为我的测试不仅易于编写,而且最终也易于阅读(因此,将来可以根据需要进行更新)。 我打算在我现在开始使用的另外两个Pod上写一篇单独的文章,使您可以用更少的代码以不同的方式测试UI🙂现在,您可以检查他们的github页面: 敏捷快照 KIF 确立了测试的重要性之后,接下来的系列文章现在将重点介绍CI方法:它的重要性以及如何在XCode,Swift项目中将其付诸实践。 在这里检查。

通过创造混乱来进行单元测试竞赛条件(快速)

多线程竞争条件不会始终如一地发生,这使得它们很难重现。 另一方面,最佳软件实践要求我们编写自动化测试以验证我们的更改。 我将分享我的技术来创建足够的混乱,以使那些罕见的崩溃变得足够可靠以进行测试。 什么是比赛条件? 如果您有多个线程试图同时变异和访问数据,可能会发生不好的事情。 一个线程可能会更改一个值,而另一个线程正在使用它! 避免这种情况的最好方法是以不可能的方式构造代码。 Swift的结构是一个很好的起点,因为它们是在写操作时复制的(额外的功劳:从功能上考虑!)。 但是我们不能总是做理想的事情。 我们在现实世界中发展,但我们的控制范围之外。 也许我们陷入了遗留代码库。 也许我们没有时间或金钱来重构所有东西。 有时,我们所能做的就是实施最佳实践。 最佳实践之一是: 修复错误时,编写一个可重现该错误的单元测试以防止退化。 通常这是直截了当的,但是这些竞争条件崩溃可能很棘手。 它们很少出现在崩溃报告器中,并且您从未在设备上看到过这种情况。 让我们崩溃 首先,设置一个包含一些不安全代码的简单方法: 不料? 更像预期的那样。 现在,您可以修复它,并且可以放心,将来的更改不会使它恢复正常。 肖恩每天在 Livefront对抗 混乱 。

如何:创建一个UIPageViewController

创建UIPageViewController的步骤—代码行= 60 故事板 将UIPageViewController拖到情节提要上。 将所需的页面数的View Controller拖动到情节提要上 为情节提要ID和恢复ID设置名称 码 4.创建UIPageViewController类,并继承UIPageViewController,UIPageViewControllerDatasource和UIPageViewControllerDelegate 5.添加数据源所需的方法 故事板 6.在情节提要中将UIPageViewController设置为其自定义类名称,即您刚刚在代码中创建的名称 设置过程完成。 现在介绍实现UIPageViewController的功能的实现。 码 设置数据源和UIPageViewController的委托 创建一个函数以检索视图控制器(应用程序的页面) 创建一个延迟实例化的数组:通过调用我们刚创建的函数来填充每个索引 在viewDidLoad中:从数组的第一个索引设置UIPageViewController的第一个视图控制器。 数据源方法 5.在viewControllerBefore中: 检查条件 如果在上一个索引处有一个视图控制器,那么您可以向后滚动 如果页面数量大于“ 0”,那么如果不是,则可以从0索引滚动到最后一页 如果先前的计数以某种方式超出了pages.count的范围,则返回nil,这样应用程序不会崩溃。 从数组索引返回ViewController 6.在viewControllerAfter; 逻辑与inViewControllerBefore相同,但滚动方向相反 可选:将滑动类型从页面卷曲(如大多数电子书)更改为滚动(如大多数应用程序)。 可以在UIPageViewController的情节提要属性检查器中完成此操作 UIPageViewController实现

使用Swift自定义iOS中的导航栏

更改导航栏颜色 为了更改所有视图控制器的导航栏颜色,必须在AppDelegate.swift文件中进行设置 将以下代码添加到didFinishLaunchingWithOptions函数中 var navigationBarAppearace = UINavigationBar.appearance() navigationBarAppearace.tintColor = uicolorFromHex(0xffffff) navigationBarAppearace.barTintColor = uicolorFromHex(0x034517) 在这里tintColor属性更改导航栏的背景颜色 barTintColor属性影响颜色 后指示器图像 按钮标题 按钮图片 此代码不会影响导航栏标题的颜色。 它仍然保持黑色 更改导航栏标题的颜色 将以下代码添加到didFinishLaunchingWithOptions函数中 var navigationBarAppearace = UINavigationBar.appearance() navigationBarAppearace.tintColor = uicolorFromHex(0xffffff) navigationBarAppearace.barTintColor = uicolorFromHex(0x034517) // change navigation item title color navigationBarAppearace.titleTextAttributes =[NSForegroundColorAttributeName:UIColor.whiteColor()] titleTextAttributes影响标题文本,在这里我将标题文本设置为白色 以编程方式更改导航栏标题 为了更改导航项的标题(在ViewController中),您必须在ViewController的viewDidLoad函数中设置标题 override func viewDidLoad() { super.viewDidLoad() self.navigationItem.title = “New title” } 以下是此更改后的示例输出 更改状态栏颜色 […]

iOS测试的一些有用的提示和技巧

在为iOS开发的那些年里,我一直不愿意在我的应用程序上使用测试。 我不认为这是必要的,并且还认为这样做会浪费我的大量开发时间。 但是,反复进行手动测试和错误修复使我有了新的工作机会。 结果不只是正面的,但我不得不承认,开始并不容易。 由于这是进行开发的一种新方法,因此在编写代码之前,我们必须更改思维方式。 在这篇文章中,我将告诉您我们如何在LateralView中工作,为我们开发的应用程序创建测试。 工具类 Xcode有自己的框架来编写测试,但是我更喜欢使用一个友好的库来促进BBD。 它的名字叫Quick,它是Swift和Objective-C的一个行为驱动的开发框架。 我用于测试创建的另一个工具是OHHTTPStubs,这是一个旨在非常轻松,非常有用地对网络请求进行存根的库。 要测试什么? 添加到模型中的每个功能都是测试的目标。 特别是,我喜欢从用户的角度测试动作的完整行为。 这就是BDD所讲的,这也是我创建测试所依赖的过程。 按照这个原则,我不会测试激活按钮的特定功能,而是在用户按下按钮后测试应用程序的最终状态。 改变我们开始开发应用程序功能的方式非常重要。 总是最好: 编写测试 执行测试 等待测试失败(因为尚未编码解决方案) 编码解决方案 为测试编写足够的代码以使其正常工作 如我之前所说,BDD的主要思想是测试应用程序的行为。 这意味着我们将不匹配函数的结果或模型对象的属性。 相反,我们将专注于为用户提供可见和有形的元素。 我们将根据用户在应用程序上的实际响应以及响应后的最终状态进行测试。 斑点结构 BDD为编写测试提出了一种更具叙述性的语法。 第一组测试是Spec,通过使用Quick,其结构如下: 对于测试用例的语法,更重要的块是它 , describe和beforeEach 。 它的功能是代表接受标准以验证所需的最终状态。 describe块使我们可以指定场景并将测试序列分组。 例如,可以将它们分组,因为它们共享相同的初始设置。 此设置可以写在另一个重要的块中: beforeEach ,这是将在每个代码之前执行的代码,并包含第一个describe所包含的describe块。 有关“快速”功能的更多信息,请转到“带有快速示例和示例组的有组织的测试”。 期望功能是负责验证期望结果的功能,它将向我们显示测试是否成功。 如果您想了解更多关于Expect函数的用法,请查看Nimble的github。 一个例子 在此示例中,产品所有者请求一个带有电子邮件和密码输入的登录屏幕。 它应确认电子邮件有效,否则应在标签中显示错误消息。 它还具有一个导航到“注册”屏幕的按钮。 这是一个非常基本的示例,但足够有趣,可以从测试和BDD领域入手。 在beforeEach块(1)中,我们编写代码以初始化将要测试的导航控制器和视图控制器。 第一个测试是应该显示错误消息的测试,如描述所指示(2),我们模拟用户按下登录按钮而不填写电子邮件字段。 然后,在it块(3)中,我们使用断言来演示应用程序的行为。 在此示例中,我们希望标签的文本等于“无效的电子邮件”。 另一个简单的示例是测试,该测试包括在发生某些情况后导航到另一个屏幕。 在这种情况下,我们希望应用程序在用户按下注册按钮(4)之后进入注册屏幕。 为此,我们在beforeEach函数中模拟按钮的TuchUpInside事件。 在it块中,我们必须使用类匹配器beKindOf断言topViewController等于期望的类( […]

为什么我比Interface Builder更喜欢代码

本文 最初发布在我的博客上 。 像今天许多iOS(和macOS)开发人员一样,我通过遵循Apple自己的教程开始为Apple设备进行开发。 我仍然记得,在2011年并且来自Python和C ++的背景下,在助手编辑器上打开.xib文件和相应的类,然后从一个文件拖到另一个文件以创建IBOutlets和IBActions ,是多么神奇。 我想,“太好了”。 摆脱样板代码而只关注我的应用程序应该做的事情确实令人耳目一新。 没多久,我开始看到依靠这种矛盾的缺点。 特别是当我从从事小型教育项目转为开始与其他开发人员进行大型项目时。 合并地狱 .xib和情节提要板都不是人类可读的。 您应该使用Xcode为您生成的那些文件的漂亮图形表示。 这意味着,如果您和您的同事碰巧在同一个文件上进行工作,那么其中一个将不得不在以后解决合并冲突。 很多时候,合并将涉及随机选择更改,然后在Xcode上打开文件并弄清楚需要做什么以确保文件处于所需状态。 最后但并非最不重要的一点:Xcode只需打开它们即可更改Interface Builder文件。 有时,稍加修改就会导致文件的大量更改(这是因为文件的XML节点在内存中表示为一个集合 ,而集合不能保证顺序)。 其他时候,Xcode只是为了好玩而更改.xib的语法。 紧密耦合,几乎没有编译时间安全 您是否曾经运行过您的应用程序,并确信它会按预期运行,只是在您打开某个视图控制器后看到它崩溃了? 在检查了崩溃的确切原因之后,发现这是未连接的IBOutlet吗? 是的,我们都去过那里。 此外,Interface Builder文件更难重用,甚至更难重构。 几乎不可能单看这样的文件并对文件定义的所有内容都一清二楚。 当涉及到Interface Builder的问题时,我几乎看到了所有事情。 从可能突然使Xcode崩溃的文件仅从打开某个文件到可以使用不同xib实例化的视图控制器开始,并且当使用这些xib中的一个实例化实例时,可能导致崩溃,因为等待它,因为IBOutlet没有该xib上的对应元素,并且由于Xcode生成IBOutlets作为隐式解包的可选变量,因此任何尝试访问该变量的尝试都会导致应用崩溃。 拖拉东西不是我的强项 有一些小事情使通过“界面生成器”添加约束的任务变得异常艰巨。 就像必须移动到下一个布局约束字段一样,以便当我单击“ 添加约束” ,Xcode打开单个Storyboard所花费的时间,或者正在编辑某些内容并使Xcode崩溃时,Xcode不会忽略我的约束。 (然后必须重新打开该项目,并找出最后保存的更改是什么)。 当用代码完成UI工作时,更容易准确地查明发生了什么或需要更改一年前编写的代码中要实现该新功能的内容。 特别是,如果代码是出于良好实践的考虑而编写的,那么所有内容都是明确的,我将确切地知道在哪里查找。 这使我想起了我使用Python多年的乐趣:显式比隐式好。 但是编写自动布局代码是如此冗长而乏味…… 有一些框架可以消除编写自动布局代码的痛苦。 我选择的框架是制图学。 制图使编写自动布局代码极其简单和直观。 只需从项目的自述文件中查看以下示例: constrain(view) { view in view.width == 100 view.height == 100 […]

Swift —在Bitbucket上的持续集成

本文是同时介绍TDD和多个CI概念的指南的一部分。 您可以在 此处 查看介绍性文章 。 当使用位桶时,我们将使用CircleCI来满足CI的需求,因为它与TravisCI非常相似且易于配置。 不幸的是,它仅适用于对我们不起作用的Linux机器(因为我们需要一台macOS机器来构建我们的xcode项目)。 但是CircleCI确实提供了为期两周的免费试用,因此您可以签出它,看看它是否值得。 让我们开始工作: 首先在CircleCI网站上创建一个帐户,然后对您的Bitbucket帐户进行配对(您也可以使用您的BitBucket凭据直接登录Travis,从而无需进行配对过程)。 从项目列表中选择所需的项目,以便CircleCI可以为其生成Webhook。 现在,CircleCI已挂接到您的项目上,并且当您的代码更改时,它会收到通知(默认情况下,它被设置为在每次推送以及合并时都运行)。 现在是时候告诉CircleCI每次对代码进行推送更改时要做什么。 为此,我们必须将一个文件添加到项目的根目录,并将其circle.yml 。 CircleCI的配置方案需要更多的指令(​​与Travis相比),如果被多个文件分割,则更容易做到,这就是我们要做的。 首先在项目的根目录下创建一个Scripts文件夹。 现在创建以下文件(每个要点底部的文件名): 7.现在配置CircleCI并准备就绪! 提交并推送您的更改(确保包括.yml文件和所有脚本),应该通知CircleCI,它将开始构建您的项目并运行测试! 如果一切顺利,您应该得到一个类似于以下的屏幕: 有些不对劲? 请在下面发表评论,我将尽力帮助! 9.随着CircleCI的启动和运行,我们现在应该利用它的功能并使我们的CI工作流更加强大。 SwiftLint Swiftlint是一种工具,可以帮助您识别和标记代码的某些部分,这些部分可能不遵循社区或您的团队所遵循的样式规则。 因此,它将帮助您坚持简洁的代码惯例,并在整个团队之间保持共同的风格。 Swiftlint可以在本地或CI服务器上运行。 让我们先在本地运行它: 首先在控制台上运行brew update和brew install swiftlint ,然后在转到项目的根文件夹后,运行swiftlint 。 而已! 短毛猫会检查您的代码并提出可能发现的任何问题! 2. SwiftLint的另一个优点是,您可以配置XCode来运行它,以便在每次构建后进行编码时都能得到实时警告! 为此,我们必须在Xcode的构建过程中添加一个新的“运行脚本阶段”,并包含以下脚本: 尽管非常有用,但SwifLint有时还是会有些干扰。 在某些情况下,您可能会收到您确实不想更改的代码的警告(例如上面的AppDelegate甚至是测试类,它们本来就很长)。 为避免这种情况,您可以配置.yml文件以指定文件排除项。 我希望您更明确一些,并像 // swiftline:disable:next line_length 有了SwiftLint的本地部分,现在该让CircleCI处理它了。 首先,将新文件添加到Scripts文件夹中: 现在是时候创建一个CodeCov帐户了。 使用您的Bitbucket帐户注册,然后从列表中添加您的存储库。 您应该看到类似于此屏幕。 记下令牌ID,因为稍后我们将需要它。 最后,我们现在可以配置CircleCI,以便每次构建项目时也可以检查覆盖范围。 我们必须在yml文件中添加两件事: […]