工程师的懒惰

懒惰被视为七宗罪之一,是个贬义词,但在一定场景下,懒惰变成了褒义词:在我看来,懒惰才是人类进步的关键,正是因为懒,才创造出各种各样的工具来提升效率。人们懒得走路,发明了自行车,后来懒得蹬车,就发明了汽车,最近连开车都懒得开了,于是出现了自动驾驶汽车。对于工程师而言,懒惰也分两种,这两种类型的懒惰会使工程师的成长出现截然不同的道路。

有利的懒惰

有利的懒惰是指讨厌重复而低效的任务,自己懒得做,就让工具做,将重复任务自动化。有利的懒惰能够极大地提高效率,节约时间。下面举几个例子:

CocoaPods

CocoaPods 是开发 OS X 和 iOS 应用程序时一个第三方库的依赖管理工具。在 CocoaPods 出现之前,需要添加一个第三方库需要以下操作:

  1. 下载第三方库的代码。
  2. 将第三方库的代码引入工程,并添加第三方库所需的 Framework。
  3. 解决库与库之间、库与工程之间的依赖关系,检测重复添加的 Framework。
  4. 如果第三方库有更新,需要将库从工程中删除,并重复上面的步骤。

哦买噶,这些重复繁琐的工作能把人烦死,有些“懒惰”的工程师无法忍受这种情况,于是 CocoaPods 出现了,它能够自动下载配置文件中指定的第三方库,处理库与库之间的依赖关系,并通过新建一个 xcworkspace 的方式将第三方库同工程连接起来。哈利路亚,感觉整个世界清净了。

ARC 与 Block

ARC 为什么会出现呢?因为在 MRC 下每次都要 retain/release 真是太麻烦了,而且还容易不配对导致内存泄露,估计苹果的工程师都写烦了,既然编译器能够识别出对象的生命周期,那就让编译器去做内存管理吧,简单省事。有人可能不放心把内存管理交给编译器,你放心,在识别对象生命周期这件事上,编译器比你厉害,再厉害的开发者也有可能因为一时疏忽而遗漏,但编译器不会。另外,会有人认为 ARC 会影响性能,这其实是不理解 ARC 的原理:ARC 不是垃圾回收,只是自动帮你写 retain/release,而且写 retain/relese 时不再经过消息传递,是直接调用对应的 C 函数,这会提升性能的。另外,对于工厂方法返回值,ARC 也会做优化,不再将返回的对象放入 AutoReleasePool 了,而是直接返回,相当于调 alloc + init。所以放心的使用 ARC 吧,这种提高效率的东西为什么不用?

Block 为什么会出现呢?在我看来,是因为在使用回调函数时,每次使用变量都要将变量整合到一个结构体中,用 void * 指针的形式传递给回调函数的 context 参数,真是太麻烦了。编译器既然能识别出在回调函数里使用了哪些变量,就自动地跟回调函数整合成为一个对象吧,这样在回调函数中就能直接使用了。

《iOS 开发进阶》中的脚本

唐巧《iOS 开发进阶》中让我印象最深的是实战技巧里的一些脚本,例如删除未使用的图片资源、检查图片长宽是否是偶数等,虽然都是些简单操作,但是能提升效率,感觉很棒。

我写过的一个自动部署工具

在中科院实习的时候,曾经负责开发维护一个嵌入式系统,代码是跑在一块 ARM 开发板上的,因此每次交叉编译过后需要通过 FTP 将包传到开发板上解压,并配置一下 rcS 启动脚本。开发阶段只是一块 ARM 板,手动部署就还好,后来变成了十五块 ARM 板,这下我不干了,手动部署会死人的,而且一旦程序有 Bug,就要重新部署一遍。于是“懒惰”的我写了一个自动部署工具,思路就是轮询目标 ARM 板的 IP 地址,针对每个 IP,先通过 FTP 将程序包上传,再通过 Telnet 输入解压程序包以及覆盖 rcS 启动脚本的指令,将整个过程自动化。由于懒得每次 IP 地址改变就重新编译程序,因此将 IP 地址、FTP 账户密码等信息从程序中抽出来,放到一个配置文件中,每次启动时读取(也算是一种依赖注入了)。同时也懒得每次 Telnet 输入的命令改变就重新编译程序,将 Telnet 要输入的命令也写到一个文本文件中,动态读取。写好了之后,手动部署估计要两个小时的活,一行命令搞定,感觉生活顿时美好了许多。

如果仔细观察,还有非常多的例子,其实要做到这一点与能力无关,与方向无关,与规模无关,只跟态度有关,包括个人与团队的态度。对于个人而言,遇到重复工作,是就这样低效地重复下去,还是思考用自动化提高效率?对于团队而言,是否给成员时间来完成一些能够提高效率的工具?工程师文化越是浓厚的团队,各种工具就越多,效率就越高。总之,人并不擅长做重复枯燥的工作,而这些工作恰恰是机器擅长的,想办法交给机器去做吧,遵循 DRY:

Don’t Repeat Yourself!

不利的懒惰

下面这些不利的懒惰会极大地妨碍我们成为优秀的工程师(在写下面的内容时,我也在不断反思自己,发现其实自己许多地方依然犯了懒惰的错误,边写边出汗,膝盖各种中箭。。。):

懒得搜索

我记得微博上有过一张亚一程 Laruence 一段群对话的截图,里面是这样说的:“不是我说你,这么简单的问题,你不 Google,不百度,来群里问,简直是舍近求远”。其实真正原因就是懒。在现在这个时代,搜索是无比强大的工具,想想看,世界那么大,就去搜一搜,你不会是第一个遇到问题的,也不会是最后一个遇到的,我觉得,Google + StackOverflow + Github + Dash 基本上能解决99%的问题。

我们经常会遇到搜索不到答案的过程,于是很多人就放弃了,回到了到处去问的老路上。其实搜索不到答案的原因有2点:1,我们没有正确描述以及抽象问题,找对关键字。2,我们没有用搜索引擎的思维思考。遇到搜索不到的情况时,不要放弃,努力思考如何修改关键字与描述,多试几次,虽然很痛苦,但痛苦说明我们的大脑在形成新的思维模式,一旦形成,我们的搜索会越来越准确,效率也会越来越高。

哦,对了,最后提醒一下,对于技术问题,还是避免使用百度吧,真的搜不到什么有用的东西。有人会说用 Google 还要科学上网,多麻烦,相比搜索到有效答案带来的收益,翻墙这点工作真不算什么,我们可是工程师啊,反思下是不是因为懒所以不愿意用 Google?

懒得思考

我们在学习一个知识的时候,要积极思考,不能死记硬背。一种框架/特性出现时,一定有它的原因,多想想为什么会出现?解决了什么样的问题?为什么要这样做?这样做的好处是什么?原理是什么?到底是如何实现的?保持强烈的好奇心,这会使我们不断发问,在回答问题时会不断思考,而只有不断的思考才能真正理解一个知识,从而能够更好的使用。

另外,我们在遇到问题后,往往会搜到解决方案只是简单的拷贝,不分析背后的原因,不分析解决方案会造成哪些影响。Bug 是那磨人的小妖精,这次不彻底搞清楚原因,下次它还会来烦我们,我们就会成为传说中的救火队长,哪里着火灭哪里,疲于奔命,但火却越灭越多。

懒得阅读

现在不是知识匮乏,而是知识爆炸,如果想学习,有太多的东西可以学了:

  • 书:iOS 的经典书籍,随便一本都能让人受益匪浅。
  • 博客:有太多优秀的博客了,那都是别人深思熟虑的精华,花了数个小时写出来的。
  • 文档:很多时候,StackOverflow 回答问题的方式就是贴上一段官方开发文档上的文字,或者接口 API 的说明,在看不到源码的情况下,官方文档可以看出源码的接口说明,很值得一读。用 Dash 或 Xcode 自带文档工具,遇到不清楚的点就去看一看。
  • 源码。Reading the Fucking SOURCE CODE 不是一句空话,源码之下无秘密。有些效果不知道怎么做,到 GitHub 上搜一搜,看懂了自己不就会了。

总之,Stay Hungry,Stay Foolish!

懒得动手尝试

看看这篇《Leveling Up》,纸上得来终觉浅,绝知此事要躬行,动手才是学习最有效的方法:

  • 在看别人教程时,把 Demo 下载,自己跑一跑,改改参数,或者自己尝试重新写一遍,效果绝对比只看要好。自己有疑问时或者有想法时,都可以写个 Demo 实验一下。
  • 在看 Objective-C Runtime 原理时,亲自用 clang -rewrite-objc file.m 将 .m 文件转成 .cpp 文件看一看。用 Associated Object 给 Category 加属性时都自己写段代码试一试。
  • 想看系统函数的调用情况,可以用 Method Swizzle 给一些系统方法加一些“装饰”,或者还可以用符号断点。没事干找台越狱手机用 Reveal 看看别人家的 App。

懒得改进优化

唯一不变的就是变化。代码在最初时由于业务简单一般都很不错,但往往在增加新需求/需求变化时开始出现坏味道,因为需求的变化经常导致大环境变化,而不同环境下的实现是不同的,例如网站支持100人访问与支持100000人访问是两种实现方式,控件只支持一行显示与支持多行显示也是两种实现方式。PM 有时候意识不到需求变化背后隐含的环境变化对技术实现的影响,觉得不就是简单的改一下,有什么难的?对啊,把大象装冰箱里也只需要三步,有什么难的?为了应对这些变化,工程师有时需要对结构进行调整,保证结构的灵活,在下次变化来临时更从容,这种调整就是重构。重构不是洪水猛兽,重构可以很大,也可以很小,一切在于时间点,修改的时间点越早,成本就越低,不然就会欠下技术债。在逻辑的世界里,只分对错,欠下的一定会还。不要为了一时便利而忽略了可持续性,切记技术债是高利贷,利滚利,拖得时间越久,成本就越高,到最后一定会连本带利让欠债者赔个精光。

因此工程师在实现需求时一定要留出 Buffer 来处理结构变化引起的重构与遗留代码带来的技术债,不能懒,这样以后的需求才会更好做。而团队在每个迭代中也应考虑将一些技术债与优化作为需求加入到需求池中,不然代码的坏味道就开始在工程中弥漫,需求越做越慢,Bug 越做越多,为了速度,开始拼命加班招人,效率却越来越低,进入恶性循环。

懒得总结

在我看来,经验从来不是比拼总时间,而是比拼效果。有些人多年经验却不如有些人一年经验,这是为何?关键在于总结。就拿圣斗士星矢来说,如果单论时间,他能当上青铜圣斗士都很勉强了,为什么他能打败黄金圣斗士,因为他说过:圣斗士不会败给同一招两次!犯错掉进坑里不要紧,谁没有犯过错?但掉进同一个坑两次就不太好了,而有效的经验能让我们以后不再犯相同或类似的错误。

如何克服这些问题

我仔细观察过一些优秀的 iOS 工程师,发现:

  • 每年都有 WWDC,大家都能看,但喵神 onevcat 总能写出高质量的笔记与总结
  • 同样是学 Objective-C,阳神孙源能玩出花来,挖掘出各种特性与原理。(我曾经在阳神的博客上问过一个问题,阳神告诉我他是通过反解汇编代码得出的,我就意识到自己犯了懒于尝试的错误了)
  • 动画狂魔叶孤城_与动画小王子 KITTEN-YANG 的动画屌炸天,不用问他们为何如此屌,去他们的 GitHub 上看看他们各种尝试动画的 Demo 就知道了。
  • 唐巧《iOS 开发进阶》让我收获最多的不是里面的知识,而是他学习与总结的方式,我不断的反思自己,我平时学习时,是否能像他一样总结出一本自己的 iOS 学习笔记。

还有许多优秀的 iOS 工程师这里就不一一举例了,我认为,这些优秀的 iOS 工程师并没有比你我聪明,跟我们一样只是普通人,但他们在上面这些事情上不懒惰,积极思考、尝试、总结,在同样的条件下收获多一点点,日积月累,于是他们变得优秀。不要小看这一点点,我们要相信积累的力量,水滴石穿啊,tinyfool 说过,这种积累所达到的层次,很难被人短时间追赶上,需要别人同样去积累,是非常具有竞争力的。

面对这些优秀的 iOS 工程师,我们经常会犯另一种懒惰的错误:我们总想加好友,攀交情,甚至用拉低姿态的方式,总觉得自己抱上大腿就能迅速成长,迅速变牛。这其实是种假象,是自己不自信不独立的表现。即使加了好友,他们能够答疑解惑,甚至手把手教,亲自帮忙解决问题又怎样,那还是别人的东西,自己没有任何成长,自己不就犯了懒惰的错误吗?

学习与成长从来没有捷径,也只能靠自己!

除了欣赏与钦佩这些优秀的人外,我觉得更重要的是默默地观察与努力,观察他们是如何成长的,学习他们的好习惯,努力提升自己,向他们看齐,当有一天达到了他们的水平之后,无需刻意培养,同他们自会相熟,因为优秀的人总是互相吸引互相欣赏,“臭味相投”,不是吗?

总之,借用《学 iOS 开发的一些经验》里的一段话来激励自己,努力成为一名“懒惰”而不懒惰的优秀工程师:

我觉得支撑我们不断探索和前进的动力不是兴趣,而是永不满足的好奇心,和对优雅代码的追求。

与技术无关的懒惰

最后提一下工程师非常常见的懒惰:懒得锻炼,不注意自己身体。在我看来,我们可以热爱编程,热爱自己的工作,热爱自己的事业,热爱自己的公司,但这些不是最重要的,最重要的是我们自己的身体与我们的家庭。为什么呢?因为对于公司而言,我们是可以替代的,无论我们多么牛,多么重要,少了我们,公司依然可以运作。但对于身体与家庭而言,我们是不可替代的!身体不是程序,不能重置,一旦身体坏了,就很难恢复,甚至继续恶化,伴随一生。一旦我们走了,我们的父母、配偶、子女就失去了唯一的我们,这带来的伤害与损失对于家庭而言是无法估量的,甚至为持续一辈子(看看那些失孤的老人,让人心碎啊)。孰重孰轻,我相信理智的工程师会做出自己的决定。

我这里不是说我们不要奋斗不要拼搏,这跟锻炼身体完全是互不影响的,锻炼身体甚至能让我们能够更好的拼搏与奋斗。我们不能学习现在敏捷的一些错误做法,只强调快,却忽略了可持续性(敏捷强调的是可持续性的快速迭代),所以不要拼一天的工作时长,留出点时间锻炼健身,我们都加过班,长时间加班加到后面其实脑子已经不够敏锐了,效率极低,对编程这种强脑力劳动是很不利的,易出问题,还不如回去跑跑步,早点休息,明天更高效完成就好了。有时候公司或团队的氛围就是不把工程师当人看,疯狂加班,幻想着靠十个女人怀孕一个月就能把孩子生出来,我觉得实在受不了就换一家吧,没什么大不了,开心健康地活着其实就是在赚钱。(医院才是真正的销金窟,钱到那个时候就是个数字,医院里充斥着痛苦、无助、绝望、麻木,唯独没有幸福,谁经历过谁知道)

另外,在工程师的眼里,既然一切都是逻辑,为什么不把自己的身体当做程序来调试与优化呢?一样的都有输入输出,对高热量食物防御式编程等,我曾经这样试过,成功减肥30斤,当我能够穿上一条许久都穿不上的裤子时,相信我,那种成就感比写100个牛逼程序或 GitHub 上有一个10000+ Star 的仓库都要强。

版权申明:我已将本文在微信公众平台的发表权「独家代理」给 iOS 开发(iOSDevTips)微信公众号。扫下方二维码即可关注「iOS 开发」: