本文内容基于 WWDC19 - 239 Great Developer Habits 整理。
首先来说一个词,提到 "craft",大家会想到什么,【其实我这种英语渣渣啥都想不到甚至还有点不会发音。。。。咳咳咳】这个词翻译为 "工艺",此时脑海中是不是会有一个思路:规划、制作和执行的技巧,用心、熟练或创造性地制作和生产。其实开发人员和工程师的工作也属于一种工艺,既然属于一种技艺,那么也逃不脱一个词:熟能生巧。当然在App开发中随着时间的推移,我们或许已经将某些事物例如思路亦或是处理能力等转换为自然而然的习惯,从而节省了我们的开发时间,但是这更加意味着要拥抱好习惯抛弃陋习,否则不完美细节的累加最终会影响成品的性能、可靠性和稳定性,让它变成失败的作品,相信这是我们都不愿看到的。本篇即为帮助开发者梳理编程时的小习惯,从而帮助开发者达成更流畅、正确的前进目标。
1. Organize
1.1 文件分组
有人说【桌面混乱的程序员才是好程序员】那么请看下面一张图,你觉得哪个能更快的找到你所需要的工具呢?是杂乱无章还是分组有序的标签?
Xcode 为我们提供的 Group 已明确区分代码结构和组织。让你程序各部分的代码文件一目了然,在你尝试修复 Bug时,快速地为你做好准备。相信工作空间的干净整洁,能够让你以最好地状态投入工作。特别是当你在协作团队工作时,分组对你或他人都是一种更友好的管理方式。
1.2 Storyboard分组
另外 Xcode 还提供了 Storyboard 这一非常强大的工具,通过可视化的方式构建用户界面。但实际使用中或许你会看到有些项目将所有的 UI 全部放在一个 Storyboard 中,emm少年你可能是在玩火,合并冲突就可能让人头秃。。。iOS 9 以后引入了一个StoryBoard Reference特性,Storyboard 之间可以引用,所以就像对你的文件进行分组一样,应针对应用程序的主要部分分别创建各自的Storyboard,然后通过引用将它们连接起来,这样可以很好的隔绝各自独立的变化,减少合并冲突的风险,详细了解可以点击查看这篇文章:Xcode中StoryBoard Reference 新特性的使用
1.3 保证项目文件最新
将项目文件保持在最新状态是确保 Xcode 帮你解决并避免问题累积的关键方法。其次,确保你的项目使用新的构建系统New Build System,它在性能、依赖管理方面作出了重大改进,对采用 Swift 包起到至关重要的作用。详细了解可以点击查看这篇文章:探究Xcode New Build System对于构建速度的提升
1.4 删除无用代码
请注意此处用的是删除这样一个比较强硬的词,而不是注释!很多时候会有一个错觉,这段代码将在某一场景下被用到,留着它吧无伤大雅,但实际上你完全可以通过源代码管理的历史版本中找到他们,而不是让多个这样觉得"有用的代码块"影响你代码整体的简介。当断则断。
1.5 关注并避免 warning
应该像对待错误一样对待警告,尽快地修复它们。如果我们的项目有着成千上万个警告,其大部分的原因都是因为开发人员并不在意也不去修复它们而逐步累积的,那么如果你在维护这样的一个项目,当新的警告产生时你也根本发现不了。而从一开始就关注并着手解决 warning,那么一旦有新的⚠️出现,你会第一时间关注并解决掉它,而不是任其累积。
2. Track
目前绝大部分的项目中都会加入源码管理控制,例如 SVN/Git 的版本管理,相信代码管理工具带给我们的好处不言而喻,分支管理、代码修改记录等等等等此处不再赘述,想进一步研究的小伙伴,请点击我的另一篇文章:Git分布式版本控制
3. Document
注释和文档对代码清晰度和可维护性贡献是毋庸置疑的,或许有人会说我不需要代码注释,我的代码是自记录(self-documenting)的,实际上从算法角度看,良好编写的代码确实清晰的描述了它所做的事情,确实是自记录的。但是它并没有说明为什么,为什么会有这些代码的原因,这些代码该如何在更大的上下文中进行适配,也没有描述当时编写时采取这种方法的背后原因,而更完善的注释和文档不仅可以帮助协作开发人员理解你的思路,也可以帮助你回忆代码这样编写的理由,节约你回忆的时间,甚至不得不提有些时候太久远你可能回忆都回忆不起来。
另外请不要吝惜的使用 option+command+/ 来进行文档注释的编写,这样你下次再见到以前编写的大段代码时就不用绞尽脑汁去重新回顾一遍所有实现细节以搞清楚这段代码的目的是什么了。
4. Test
正如我们的开发需要业务黑盒测试一样,编写单元测试以进行代码白盒测试也相当重要,即使那些看上去貌似比较简单的代码,因为测试是用户永远不会真正看到的隐藏细节之一,将问题及早的暴露在内部远远好过为隐藏过深但最终在线上爆发的 bug 要好得多,具体使用此处不再赘述感兴趣的欢迎点击另一篇文章:iOS开发之XCTest ,此处我们仅关注该环节的重要性,另外单元测试也是持续集成的关键组成部分。相信当你看到成功标志✅的时候会笑的像个不到两百斤的孩子(o)/~
5. Analyze
5.1 网络状态模拟
苹果官方提供了一个名为 Network link Conditioner 的工具来帮助我们在开发时模拟各种网络环境已测试代码在不同环境中的表现,你可能会惊讶于在较差的加载和争用条件中产生的问题数量,但这也意味着外部实际用户可以避免掉这些问题。可以参考Mac模拟慢速网络 - Network Link Conditioner
5.2 Scheme设置
可以在 Scheme 设置中勾选一些选项,通过他们在开发周期里发现多种多样的错误:
Address Sanitizer:帮助监视类似内存错误和缓冲区溢出的问题,内存问题通常是导致安全漏洞的原因。
Thread Sanitizer:调试你的APP时发现数据竞争问题,即两个未同步的线程,其中至少一个试图对同一块数据进行写操作。
Undefined Behavior Sanitizer:可以捕获诸如除零错误、浮点类型之间超出范围的强制转换、溢出和未对齐指针等错误。
Main Thread Checker:主线程检查可以确保没有在后台线程上执行无效的AppKit、UIKit和其他API使用。
5.3 关注性能和资源利用率
如上图所示,Xcode 本身已经给我们提供了调试仪表盘来帮助我们时刻关注 APP 运行时的资源占用,从而帮助定位问题。
最终武器 Instruments 更是详尽的覆盖了性能测试的方方面面,具体使用不再赘述,感兴趣的小伙伴可以点击iOS性能分析工具简介与简单应用
6. Evaluate
关于评估这个话题,演说者讲了一个其自身经历的故事:他曾拥有一个完全属于自己的木工车间,在那里没有人会干扰他的思路,但是搬到另一个地方后由于环境条件限制,他不得不于他人共享木工车间,这一开始让演说者感觉很沮丧,但慢慢地他发现,跟别人交流意见听取别人的看法对他的提升有很大帮助。同理,在编码时我们可能习惯于独立开发,这时代码评审显得那么多余,但是换个角度想想,你的同事可能会发现你代码中隐藏的问题,给你提升代码质量或思路的更好的方法,这个时候不是比自己一味地满足现状要好得多么?所以代码评审是必不可少的。
那么好的代码评审是怎么样的?首先,意味着需要花时间去理解每一行变更的代码,匆匆一瞥是没有意义的。其次,构建项目并跑起来看看,不要假设原作者之前做过,特别是在你记录中看到最后的提交是一次合并时。运行这些测试,首先这么做是提醒你去检查实际上是否有这些测试以及测试是否通过,记住编译通过不代表不存在某种问题。彻底阅读这些注释和文档,emm有第三章节我想这些应该是完备的,对吧?接着寻找是否有拼写和语法错误。继续查找变量名的拼写错误,例如很多加拿大人,有长期使用colour作为颜色变量名的习惯,这让团队在查找color变量时简直抓狂。确保代码库中的函数、变量名的一致性可以更容易的查找,也节省时间,更能够有效缩短协作开发的时长。
7. Decouple
高内聚,低耦合,相信各位开发者都听过这个概念,那么在实际开发中,利用解耦有效地将各个模块拆分成为小的组合包,而不是做代码的搬运工是不是更让人有成就感?当然共享代码打包成Framework,那么有效减少应用二进制包大小,当然,创建包也给你了在社区分享你努力成果的机会
8. Manage
当进行开发时你可能会选择依赖很多或第三方或公司内部成型的组件库,那么此时依赖管理的重要性就体现出来了。在你开始使用之前,了解库里面包含的内容以及在带来潜在的问题是非常重要的。特别是对于第三方开源库如果依赖包不维护了怎么办?或者直接就消失了呢?重要的是你要有一个计划决定你在任何时候遇到这些情形时该如何去处理,毕竟你在项目中引入了一个新的依赖后,项目的未来就真的依赖它了。那么是你准备自己来修复这个公开的bug呢?还是将它转为内部的项目并维护它,又或者你计划不得不把那个依赖在以后全部清除出去以及包括因此带来的必要工作?
当然使用外部依赖包可以让你更快地完成工作,并避免重复创造社区中已经存在的工具。本着掌握它们用途的态度, 确保它们只按照你期望的那样做,务必要它们尊重使用你App的用户的隐私。做好它们在未来出错或者消失的应对措施计划。在项目中添加新的依赖时问问自己这些问题,把这件事变成你的习惯,你将最大限度地发挥出它们的长处并得到长远的回报。
总结
细微之处见真章,只有处理好细节,将优秀变成一种习惯才能收获成功。
参考
【翻译】WWDC 2019 :优秀的开发习惯