【翻译】WWDC 2019 :优秀的开发习惯

本文翻译自 WWDC 2019 Session 239
演讲者:Josh Tidsbury算法

成功的APP开发须要掌握方方面面的东西。了解可归入开发流程的实践以提升你的生产力,提高你APP的性能和稳定性。学习如何提升经过Xcode编写的代码质量。得到一些有价值的开发技术的切实理解。编程

早上好,我是Josh,来自苹果技术布道团队。咱们的团队与像你这样来自世界各地的开发者一块儿工做是难以置信的荣誉。咱们的目标是帮助大家开发出真正优秀的APP。在与大家的交流中咱们学习到了不少,得以了解您所采用的流程,面临的挑战,目标和愿景。咱们学习能够帮助你摆脱困境的技巧和工具,虽然咱们听到的每一个故事有些许不一样,但不管来自世界何方,它们均有诸多的共同主题。swift

当你想象手艺这个词时,你首先可能会联想到设计。开发人员和工程师从事的也是手艺,毕竟手艺的定义以下:安全

  1. 规划、制做和执行的技巧
  2. 用心、熟练或创造性地制做和生产

代码是用手写出来的,它涉及很是多的技能,在构建APP时须要创造力的技术和抉择。今天我想和你谈谈这门“手艺活”所在意的事情,将这种在意融入到你的代码、storyboards和产品中。开始看起来可能很容易,但结合对当今咱们开发者提出的全部要求来看,有时会至关困难。手艺的技能水平随着时间而发展,这须要敬业、耐心和专一。这是关于学习去享受过程当中带来的乐趣,几乎与到达目的地时的同样多。这个过程的一部分是将那些开始时须要强烈并有意识关注的事情转换为习惯,相似于实际中驾驶汽车,咱们驾驶时有意识地关注的事物数量会随着时间的推移而减小,由于咱们已经将这些事物转换为天然而然的习惯,在App开发中咱们也能作到一样的事情。
服务器

要作到这一点,就意味着要拥抱好习惯抛弃陋习。当开发一个APP时,开发者须要关注很是多的细节,而这些细节不多有被使用咱们APP的用户直接观察到,然而他们能感觉到因这些细节影响的性能、可靠性和稳定性。网络

咱们没有足够的时间关注这里全部的细节。今天我想花一些时间来回顾一些有但愿改进咱们开发工做中的实践,将它们归入到常规的工做流程后再造成习惯,这在未来会把咱们从挫败、麻烦和浪费时间的困境中拯救出来。我相信大家大部分人已经在实践不少相关东西了,但也许还有一些没能成为你的习惯,说不定在这里会受到一些启发而去实践更多。app

首先咱们来看 组织

1. 组织

除了APP开发人员的身份外我仍是一名木工,对我来讲是很好的从现代生活逃离的一种方式。有一点能够确定的是,在干净的工做间中更加容易打造出又好又漂亮的家具。若是你的工做台是杂乱无章、毫无条理的,那么很难去找寻所需的工具和材料,不得不为你目前的工做腾出空间而搅乱更多的东西,花费了较往常更多的时间同时过程当中也伴随着更多的意外和错误。框架

咱们团队每一年接触不少Xcode项目,有一些实践经验能够帮助你确保工做空间的干净整洁,让你可以最好地进行工做。异步

Xcode项目受益于Group带来的代码结构和组织。让你程序各部分的代码文件一目了然,在你尝试修复Bug时,快速地为你作好准备。编程语言

利用Group以功能模块的角度来组织你的项目,这与用户操做App的方式逻辑上一致。咱们常常看到有些项目使用文件类型来分组,或者干脆就不分组,这样对想要快速了解源文件如何相关联的人来讲没有任何好处。

此外分组有助于你的Xcode项目结构与实际的文件系统结构相匹配。从Xcode 9开始,当你在项目中新建Group同时会在磁盘上建立一个文件夹来存放组内的文件。这意味着不管当你从项目、源代码管理或者磁盘上查看都是类似的结构,有助于减小疑惑和混乱。

Storyboard是很是强大的工具,经过可视化的方式构建用户界面。咱们确实遇到了许多项目将全部的UI一股脑的所有放在一个Storyboard中,没有理由能够这么作。

感谢Storyboard之间能够引用。应该针对应用程序的主要部分分别建立各自的Storyboard,而后经过引用将它们链接起来。你会发现这样能很好的隔绝各自独立的变化,并使你在大型团队合做中更加简单,避免那些使人讨厌的合并冲突的风险。就像你不会把全部的代码放在一个文件中同样,因此千万也不要把全部的UI放在一个Storyboard文件中。

将项目文件保持在最新状态是确保Xcode帮你解决并避免问题累积的关键方法。若是你按期处理这真不能算是一个问题,要是放置不理,在将来确实会引发问题。首先,当你更新到新版本的Xcode时,有时候须要你来决定让Xcode更新项目设置和项目文件到最新的格式。所以,除非你有重要的原理不这么作,不然咱们建议你在出现弹出框提示或在issue navigator出现警告时执行此操做。

其次,确保你的项目使用新的构建系统New Build System,该功能于2017年首次推出。它在性能、依赖管理方面做出了重大改进,对采用Swift包起到相当重要的做用。它从Xcode 10起始做为默认的构建系统,你能够经过从File菜单下的Projects Settings中进行查看验证。

做为木工,咱们经常会保留一些小的废料以防之后可能会用到,直到都要装满它们时咱们才不得不接受这样一个现实:这些小废料从未真正被使用到项目中去。开发人员也有这个偏好,好在有一个(比起木工)更容易的决定,因为你已经将项目代码加入源代码管理之中,你有吧? 去掉那些不须要而且没有使用的代码,不要仅仅将它们注释掉。万一有天你想要把它找回来,若是你真的须要的话,你也能够从那个文件的历史版本将其找回来,扔掉这些“小废料” 吧。

另一件咱们不想失去控制的事情是警告Warning。为此,你和你的团队应该开始零警告的实践,包含警告的代码不该该被签入,你应该像对待错误同样对待警告,尽快地修复它们。若是咱们的项目有着成千上万个警告,其大部分的缘由都是由于开发人员放弃而且没有安排时间去修复它们而累积起来的。此外,若是你在维护这样的一个项目,当新的警告产生时你也根本发现不了。

经过如下这些方式让你的工做空间和项目有条无紊并整洁干净,这对你的APP的长期健康和成功起到相当重要的做用:

  • 利用Group来组织你的项目,与文件系统结构相对应
  • 利用Reference拆分过大的Storyboard
  • 确保项目文件是最新的
  • 清除废弃、旧的代码;
  • 出现警告时就找到并解决引发它的根本缘由。

作好这些事情使得您的项目变得灵活,你的开发流程在项目生命周期中将运转得更好。

2. 追踪

提及源码控制,在搭建项目时你就应该启用它。咱们确实遇到过许多没有源代码管理的项目,特别是那些独立开发团队的项目。在你搭建Xcode项目时,你只须要确保这个复选框被选中就能够了,这样你的项目就会使用Git进行源代码管理。

如今你能够随时回过头看看你过去的修改,当你提交当前的变动集时会发生的变化以及更容易发现任何类型的错误。启用源代码管理以后,那么还应该注意这些事情使得更加有用和高效:

首先,每次提交的粒度小一点。常常性地检查让你的当前代码和分支,保持小增量的更新,让这些变动尽量的局部性和自包含。当你之后须要线索或解决回归bug的时候,这会给你提供一条回顾的路径。同时由于你作的这些都是小的变动,从而下降引入侵害的概率。

其次,编写有用的commit messages。由于有一天咱们都会问出这个但愿本身能回答的问题:当时究竟在想什么。当你试图回忆当时代码发生变动时的情形和缘由时,你的commit messages就是给你将来的笔记。

即便你是独立开发人员也像参与大型团队那样进行源代码控制。这样意味着修复bug和添加新功能均可以经过分支来完成,一旦你完成以后即可压扁合并回主分支或dev分支,同时使用有意义的commit message。现在你有多种选择和模式能够遵循,建议你尝试使用它们,找到最适合你的那种并将其集成到你的开发流程中。

这就是追踪。源代码的管理对成功的现代App开发工做流程相当重要,请将它做为你项目的一部分、视做平常实践的一部分。保持较小的提交,填写有用的commit message,以及利用分支的帮助进行管理和隔离因修复bug或添加新功能引发的代码变动。

3. 文档

在我看来,对代码清晰度和可维护性贡献最大的是注释和文档,它们对你和你的同事们来讲就像面包屑导航那样的做用。有人说我不须要代码注释,个人代码是自记录(self-documenting)的,我对此并不买帐。从算法角度看,良好编写的代码确实清晰的描述了它所作的事情,确实是自记录的。可是它并无说明为何,为何会有这些代码的缘由,这些代码该如何在更大的上下文中进行适配,也没有描述当时编写时采起这种方法的背后缘由。我工做过的最好的开发人员,不只编写使人难以置信得清晰简洁的代码,并且还花时间在代码中留下有用的审查记录或注释,引导将来的读者领会原做者的意图。初级开发人员能在这个过程当中受益更多,由于你的经验会在项目开始到结束时变化很大,开始时作出的决定可能实际上与最后作出的决定不一致。(译者注:初级开发人员由于经验的缘故,致使代码变更的因素更多,所以更加须要清晰描述的文档和注释)

怎么样算做好的注释呢?好的注释假设读者了解所用的编程语言,可以走查代码序列以及采用的步骤,它真正关注的是代码起初写在这里的缘由和支撑这么作的理由。举个例子,这是咱们常常看到而实际没什么价值的注释:

//A constant string id value
let id = "2ADA155F-1529-4D2D-98C4-0E4BD06940E8"
复制代码

我假设大家大部分人都使用Swift写过一些代码,知道这里是建立了一个字符串常量来携带这个值,可是咱们不知道这个id是什么,它的用途以及被硬编码到APP中的缘由。给它加了一点注释后,咱们就明白了这个值存在的缘由,以及它来自哪里。

// The permanent identifier for this application when interacting
// with the CMS, provided by the vendor of the CMS.
let id = "2ADA155F-1529-4D2D-98C4-0E4BD06940E8"
复制代码

咱们还能够更进一步,给变量换个名字后变得更加清晰。

// The permanent identifier for this application when interacting
// with the CMS, provided by the vendor of the CMS.
let cmsApplicationIdentifier = "2ADA155F-1529-4D2D-98C4-0E4BD06940E8"
复制代码

若是你发现你本身的变量使用了单个字母或者相似id等方式命名,也许这是你给它们选择一个更具描述性的名字的好机会。自动补全功能让Xcode充满魅力,你甚至都不用再输入任何更多东西了。这个案例中的标识符在任意时间使用时在贯穿整个代码库都是清晰的。

文档带来的好处和注释类似,但这些好处是遍布整个应用程序甚至以外的。 当你编写本身的APP时,你建立了一层层的抽象和算法,将大段蜿蜒的代码分解成整齐可测试、可重用的函数。若是你没有选择给这些函数添加文档,那么你是在强迫你本身每次使用该函数时都得在头脑中过一遍这个函数的文档,经常必须从头了解这个函数内部的实现,包括每一个参数的用途以及如何产生的结果。

若是你不知道如何在Xcode中添加文档,很简单,只要你将光标定位至函数签名的第一行,再按option + command + /组合键,您须要的全部占位符文本将自动生成,填充空白就行了。

按住option并点击任何使用该函数的地方都会显示跟你已经熟悉并喜好的原生SDK/Swift标准库风格相似的快捷帮助弹出框。

注释和文档对你的时间来讲真是低投入高回报的投资,收益在整个项目周期中都会源源不断。因此请为你的代码添加有用的注释,让读者能更好地理解原始做者的思路。为你的变量选择更具描述性的名字,为你的函数、属性、结构体和枚举都添加上说明文档。

4. 测试

接下来,我要谈论一下测试,特指单元测试。为此我还要介绍一下Marshall, 他是咱们Swift和开发工具的布道师,一个很是聪明和友善的伙伴,刚好也是一部Swift领域的Lint 对讲机

每当我提交代码进行评审的时候,我都作好了迎接海啸般深入看法和反馈的准备,这帮助我从形式和功能上改进所写的内容。前几天, Marshall在单元测试的另一个主题上也把我引向了正确的方向。如今,我必须认可,我在写单元测试方面并无无懈可击的记录,我并非不欣赏它们带来的潜在价值或者是对它们不熟悉,而是我老是倾向于在写完实际代码以后再来写单元测试,我老想把它放到最后来作。

然而,有一天我在为某APP 的新功能实现数据模型层的时候,Marshall跟我说:“你在作这些事的时候,最好添加一个单元测试来确保字典和结构体这两种表示之间的来回转换可以正常工做”。

个人真的想不通这在未来怎么可能会出问题,不过我仍是遵从Marshall的意见给这个简单的流程加上了单元测试。跑了下单元测试,看到绿色的复选标记表示测试经过时,我感到无比的知足,因此我提交了代码进行评审。我再次想起这个测试是几周后咱们须要给这个结构体添加额外的数据,修改以后运行时也没有问题,个人工做作完了,对吗?就准备签入代码了,而后我想起来运行一下那个单元测试,果真我由于忘了修改字典反序列化的方式被单元测试抓了现行。这个Bug可能会在咱们实现UI的时候才会暴露出来,那样毫无疑问会浪费咱们至关多的时间去找到缘由。因此感谢Marshall提醒我将单元测试做为平常实践的一部分,Marshall:"不客气,Josh!"

编写单元测试至关重要,即便那些看上去貌似比较简单的代码正如我碰到的这个例子同样。代码的易受影响性带来了潜在的回归bug,鉴于此咱们并无那么多的时间进行完全地测试,让咱们将Xcode做为一组额外的“眼睛”。

所以,将单元测试的实现做为常规开发实践的一部分,并在每次提交以前运行它们。单元测试也是持续集成的关键组成部分,因此你能够为此作好准备。 测试是用户永远不会真正看到的隐藏细节之一,可是可能会带来不一样的后果,给用户带来极致的体验或是APP重要数据受到破坏形成的使人沮丧。

5. 分析

现在有多种形式的分析能够做为你部分平常工做流程,其中一些须要额外时间的投入,也有一些能够在后台中为你工做,你甚至都不须要去管它。

一个叫Network link Conditioner的工具很是有用,APP开发每每在网络性能良好的家中或办公室,却不是你的APP一般被使用的典型环境。

所以,经过启用 Network link Conditioner能够人为地将网络性能限制为相似典型蜂窝网络的性能,甚至是较差的网络环境,你会惊讶于在这种加载和争用条件中产生的问题数量,这样你的客户就能够避免。

在你的Scheme设置中有一些Sanitizer选择器,经过它们能够在开发周期里发现多种多样的错误。Address Sanitizer将监视相似内存错误和缓冲区溢出的问题,内存问题一般是致使安全漏洞的缘由,所以使用Address Sanitizer能够帮助你确保不会将这些问题暴露给线上。

经过启用Thread Sanitizer能够在你使用模拟器测试或调试你的APP时发现数据竞争问题。数据竞争是指两个未同步的线程,并且至少其中一个试图对同一块数据进行写操做,这可能的恼人错误会让程序运行出现不可预料的问题甚至出现内存异常。

Undefined Behavior Sanitizer能够捕获诸如除零错误、浮点数的转换超出范围或溢出、以及未对齐指针等bug,当程序出现未定义的行为时它可能会崩溃,也可能不如预期的方式工做,又或者看上去没问题,但在不一样的时间看似没有任何理由的不一样结果。Sanitizer能够在帮助你摆脱使人沮丧的bug,在它们对你的项目形成严重破坏以前。

最后要介绍的是Main Thread Checker,它确保你没有在后台线程中对AppKitUIKitAPI的无效调用。举个例子,若是你在主线程以外的线程上去更新界面,它可能会致使界面更新丢失、视觉错乱、数据丢失和崩溃。有时候这些bug由于间歇性地出现而变得很是难以追踪,而启用这个功能对性能的影响很是少,因此咱们推荐你尽量就留着启用它。

在调试你的App时请时刻关注性能和资源利用率,确保app尽量高效地利用系统资源。首先可使用调试仪表盘,这些仪表盘能够在你构建和运行项目时随时在Xcode中的Debug Naviagtor中找到,你能够经过它们查看整个App生命周期的CPU内存磁盘网络利用率,快速了解你的App是否经过网络正在链接未知的服务器或者不断地轮询某个端点,消耗大量的带宽和电量。

最后你能够经过Profile中的Instruments按钮进行进一步的深刻分析。我常用的其中一个是Time Profiler,它容许你查明代码的哪些段落占用了最多的周期,而且容许咱们缩小那段也许应该变成异步或者被不可扩展的方式实现的代码的范围。

分析是一个至关普遍的主题,但我在这描述的大多数工具只须要你记得启用就好了。使用Newwork link Conditioner模拟典型的或者较差网络条件;常用SanitizersCheckers,只要把它们打开就行了;按期的查看调试仪表盘,并密切关注你APP的足迹和性能;利用Instruments分析你的App,深刻研究并更精确地解决那些问题。将这些小小的努力转化为习惯后将大大提升你APP的性能和可靠性。

6. 评估

我住在多伦多的时候有一个车库,后来将它改为了个人木工车间,这是一个温馨的空间,它彻底都属于我。

可是自从搬到湾区之后,我就再也没有属于本身的空间了。我去过这里的各类共用的社区木工店,由于如今必须与其余人共享工具和空间因此有时候会感到沮丧。可是我没有意识到我反而应该感谢的是有机会向商店里的其余人交流想法以及问问他们对于在作事情的意见。

我以为这在App开发中的类比就是代码评审。过去几年我都是以独立开发人员的身份完成许多App的开发,这就好像我拥有本身的工做间同样,难以想象得快速和灵活,只有本身的意见才重要。缺点是你本身没有从同事或同行中学习更好地使用语言、框架和SDK的机会。

虽然解决问题的办法一般有多种,但总有更好的那一种。好比那种更简洁或者在性能、可维护性和可靠性方面更突出的方法。不能由于它起做用了就意味着它必然是正确的,就不能经过某种方式能够去明显地改进它。(译者:结合我的工做间 vs 共享工做间, 我的开发 vs 团队开发的优缺点来理解这段话)

苹果的全部团队都有一项未经评审的代码不能并入项目的政策。咱们团队经过这个过程互相学到了不少东西,代码风格更加一致,更不用说在可靠性方便的改进了。它还确保咱们整个团队更熟悉更普遍的代码库,使得咱们能够解决的bug和功能的范围也更广。我有幸处在这么一只经验丰富的团队,这让事情变得简单。可是若是你经营着本身的公司或者是独立开发者,试着找找你所在地区或者来自世界各地的伙伴,并与他们互相进行代码评审。或许还能够从聚会、当地会议或者共享办公室去找找。因此,如今你已经打算将代码评审归入你的开发实践了吧。

好的代码评审是怎么样的?首先,意味着须要花时间去理解每一行变动的代码,匆匆一瞥是没有意义的。其次,构建项目并跑起来看看,不要假设原做者以前作过,特别是在你记录中看到最后的提交是一次合并时。运行这些测试,首先这么作是提醒你去检查其实是否有这些测试以及测试是否经过,记住编译经过不表明不存在某种方式上的破坏。完全阅读这些注释和文档,个人意思是它们有的,对吧?接着寻找是否有拼写和语法错误。继续查找变量名的拼写错误,做为一个加拿大人,我有长期使用colour做为颜色变量名的习惯,这让个人团队在查找color变量时简直抓狂。确保代码库中的函数、变量名的一致性能够更容易的查找,也节省时间。

可能会以为这个过程在短时间内也许减缓了您的速度,但从长远来看,经过减小潜在的错误和问题,将毫无疑问地为您节省时间、金钱和客户。你做为开发人员的经验在未来处理相似的模式或挑战时受益不浅。

7. 解耦

开发人员致力于建立小而精的可重用、可测试的代码,毕竟咱们不想老是一次次的编写重复代码。

包和框架给了咱们更集中的方式来维护代码的机会,而且以便携的方式提供功能,不只仅是你当前的 App,其余的 App也能利用这些成果。 若是你的 App包含 Extensions而且将它们的共享代码打包成 Framework,那么你的应用二进制包大小会减小,由于你的主 AppExtensions能够共享这个 Framework。固然,建立包也给你了在社区分享你努力成果的机会,特别如今与 Xcode 11包的集成更紧密了。可是除了你 App、共享框架、包和库中的代码外,还须要附带优秀的文档才能让其余人更好去使用。

所以,将框架和包做为你拆分代码库的一种方式,这可让你的成果做用于多个正在开发或维护的appFramework能够帮你减小二进制包的大小,而后你能够将成果与社区共享,但请务必附带优秀的文档。

8. 管理

最后一个我想谈论的是依赖管理,尤为是搞清楚它给你的项目带来的好处和风险。使用Swift包、框架和其余库有不少好处,可是在你开始使用以前,了解库里面包含的内容以及在带来潜在的问题是很是重要的。

你要确保了解依赖包对数据的影响,你要对App的内容负责,包括对用户数的所做所为。 确保Framework没有收集没必要要的指标或设备信息,确保它没有把数据从你的设备发送出去。

一样也要了解和研究给定依赖包的依赖。 毕竟引入包含依赖的依赖包后意味着你App的安全和成功与这整条链挂钩了。

最后还有另一种可能性会破坏你的App,若是依赖包不维护了怎么办?或者直接就消失了呢?重要的是你要有一个计划决定你在任什么时候候遇到这些情形时该如何去处理,毕竟你在项目中引入了一个新的依赖后,项目的将来就真的依赖它了。 那么是你准备本身来修复这个公开的bug呢?仍是将它转为内部的项目并维护它,又或者你计划不得不把那个依赖在之后所有清除出去以及包括所以带来的必要工做?

使用外部依赖包(如Swift包)可让你更快地完成工做,并避免重复创造社区中已经存在的工具。本着掌握它们用途的态度, 确保它们只按照你指望的那样作,务必要它们尊重使用你App的用户的隐私。作好它们在将来出错或者消失的应对措施计划。在项目中添加新的依赖时问问本身这些问题,把这件事变成你的习惯,你将最大限度地发挥出它们的长处并获得长远的回报。

总结

对于App开发项目,有时候以为项目的最后10%的工做花费的时间与前90%的时间同样长。可是我认为尝试经过将这些实践转化为习惯以后,你能够避免这种感受。

经过有效的组织你的工做区,让你更快更高效的工做,专一于实际代码。 利用源码控制追踪你的代码库,能够减小回归bug的概率,加快调查可能致使bug的缘由。 编写有帮助有意义的注释和文档,你能够在将来阅读这些代码以及每次使用本身编写的类、结构体、函数时减小负担成本。单元测试能在最后一刻拯救你,在引入一些回归bug的时候。 Sanitizerscheckers提供对你的代码持续分析的能力,它们在后台运行,你都甚至不用去操心。仪表盘和Instruments确保你高效地利用系统资源,容许你精确地追踪性能和其余问题。代码评审不只仅是评估代码样式和功能,更是一个巨大的学习机会,让你提高你的开发技能并与你的开发团队在社区进行分享。将你的项目分解为更小的、可重用的包和框架,帮助你让你的成果延伸到多个项目,并容许你共享它,这样作一样有利于减小二进制包的大小。最后,使用外部依赖(好比Swift包)能够重用社区中已经开发好的功能,帮助你更快完成工做。可是必定要把关好它们的所做所为, 记住了吗?包括它对你用户数据作了什么,也要作好没有它们的准备。

将这些实践做为你工做的一部分,只会给项目每一个阶段增长一点点时间,可是从长远来看将会为你节省难以想象的时间,确保你的项目基业长青。我但愿今天为你提供的想法和建议可让你思考如何进一步提高做为开发人员的手艺。你正在想归入的这些实践能够提高你工做质量和稳定性,把这些自觉的努力转换为习惯将容许让你将精力投入到更重要的领域。那些使用你APP的人也许不能说出个因此然,可是能感受到你投入这些工做所带来的关爱,你能为本身打造的这些而自豪。谢谢!

【全文完】

相关文章
相关标签/搜索