写给刚入行时的自己的建议
原始链接: blog.pragmaticengineer.com/advice-to-m...
回顾十多年前,我希望自己能早点养成一些习惯,这些习惯本可以帮我成长得更快、更专注。以下是我给刚入行做软件工程师的自己的一些建议。
1. 每年花时间读两本软件工程方面的书
每次我认真读完一本推荐的软件工程书籍,我的水平都会得到提升。所谓"认真读",指的是做笔记、和别人讨论章节内容、画图帮助理解、动手实践,并且反复阅读。
我真希望在刚做开发的头几年就去读这些书。 我直到工作第 5 年左右才开始这么做。当时,《C# In-Depth》、《Clean Code》和《Javascript: The Good Parts》等书大大提升了我的技术能力。当然,不是说非要读这几本(有些现在已经过时了),我的建议是:去找那些能让你在现有认知上继续深挖的书,无论是特定技术还是工程实践都可以。
我读书很慢,一次通常只读一两章。我会做笔记或划重点。读完后会做总结,并经常和别人讨论。这几年,我也开始在博客上写书评来反思所学。这些习惯不仅帮我成长为优秀的研发经理,对工程师阶段也同样有用。想找点灵感?可以看看我的阅读清单。
为什么推荐看书而不是看博客或视频?因为短篇幅的内容通常只停留在表面。书籍包含的是深入且系统化的知识。写像这样的一篇博客只要几个小时,但我写一本关于软件工程师成长的书却花了一年多。读书是一种缓慢但极其深度的吸收方式。
目标不用定太高:半年读一本书就很棒了。选定一本书,然后花时间好好 读透。读完一两本后,我还强烈推荐你读读《如何阅读一本书》(我是认真的)。
2. 深入掌握你工作中使用的编程语言
我最早兼职写代码时用的是 PHP 和一点 JavaScript。大学里学了 C 和 C++,但我都不太喜欢。第一份全职工作我开始写 C#。当时我表面上懂很多语言,但没有一门精通的。
工作两年后,我开始对一件事感到苦恼:每次调试 C# 代码还要依赖高级开发人员。一位经常帮我调试的前辈似乎对这门语言的底层细节了如指掌。他推荐我学习《C# In Depth》。我照做了,花了大把时间钻研线程、垃圾回收、泛型的工作原理,硬啃下了协变、逆变等难懂的概念。
深入学习工作中所用的语言,是我做过最正确的决定之一。 虽然这是受前辈启发偶然开始的,但这门手艺成了我在公司和后来面试时的巨大优势。在随后的职业生涯中,我会刻意深入研究新语言和框架。比如在 Skype 时,我本来是去写 C# 的,但后来团队转向 JavaScript 和 WinJS,我就顺势深挖 JS 并精通了 WinJS,后来甚至在 Pluralsight 出了相关教程。
你掌握的语言越多,就越能客观评估它们的优缺点。 后来我转做 iOS 开发时,已经精通了好几门语言。当 Swift 刚问世时,我参与了语言的讨论,还提议把读写反射加入路线图。因为了解语言特性,我在帮团队制定从 Objective-C 迁移到 Swift 的策略时更加游刃有余。掌握的语言越多,学新语言就越快,也更容易深挖底层原理。
3. 多和同事结对编程
现在结对编程似乎不太流行了。但在我刚入行时,极限编程(持续结对)、TDD(测试驱动开发)和群体编程很火。我职业生涯中几次最大的飞跃,都是在和别人结对编程后发生的。这比看任何书都管用。
让我记忆犹新的是,有一位同事给所有人的代码审查(Code Review)都非常严苛。有一天我受够了,决定不在工具里回复他,而是直接坐到他旁边,让他当面解释他的意见。结果我学到了很多东西,同时也直接告诉他我觉得有些评论不太公平。他接受了,并建议我以后只要觉得有争议就直接来找他结对编程。我照做了。这位同事极度追求性能,通过结对,我学到了很多关于性能瓶颈的细节;作为交换,我也教会了他很多关于代码可维护性的知识。
另一次美好的回忆是和另一位工程师做 TDD。我们轮流交接键盘,一个写测试,另一个写实现代码。为了完成一个复杂的系统模块,我们整整干了两天。这次经历让人大开眼界,在中途梳理边缘情况时,我们甚至完全推翻并改变了最初的方案。我们因此建立了深厚的友谊,在此后的几个月里合作得非常愉快。
4. 编写单元测试,并在 CI 中运行
高级工程师经常强调单元测试的重要性。但这看起来很违背直觉:为什么要花更多时间去写那些看起来微不足道的测试代码呢?我曾有很长一段时间都是这么想的。
想要真正体会单元测试的价值,你需要经历一次"顿悟(aha!)"时刻------也就是你自己写的测试挽救了整个局面的那一刻。但在此之前,你必须耐着性子去写测试,并让它们在 CI(持续集成)中运行。通常你需要坚持几个月,才能等来那个"顿悟"时刻。
我经历过两次。第一次是我接了个私活,给一个小型的在线赌场写后端引擎。API 涉及真实的金钱交易,我极其害怕出错,所以给所有代码都写了单元测试。项目最终延期了,部分原因是写测试太费时间,但我心里觉得这样做是对的。两年后,客户告诉我,好几次团队差点把致命 Bug 发到线上,全靠那些测试报错才拦了下来。
另一次是在开发网页版 Skype(web.skype.com)。当时我们团队很强,代码有全面的单元测试和集成测试覆盖。项目做了三个月时,一位工程师提议重构整个项目结构。这风险太高了,大家都投了反对票。
但他反驳说,有这么好的测试覆盖率,重构应该是小菜一碟:"只要测试通过,代码就没问题"。我半信半疑,结果还真是这样。花了一周重构后,他提交了一个巨大的改动,而什么都没坏。当时没有,后来也没有,所有测试都顺利通过。就在那一刻,我意识到了强大的测试套件能提供多么可靠的安全网,让你再也无惧重构。
5. 养成重构的习惯,并掌握重构工具
很多年来,在团队代码库里,我只敢做最小范围的改动。在个人项目里我敢大刀阔斧地重构,但对于不是完全由我负责的代码,我一直不敢动手。
后来在 Skype,我遇到了一位工程师。他总是不断地进行各种大大小小的重构,代码变得越来越好,而且他从来不把代码搞坏。他是怎么做到的?
在和他结对编程时,我发现他非常熟悉自己的 IDE,装了各种重构插件。提取方法、重命名变量、提取常量......这些操作他一秒钟就能搞定。
我意识到,我不敢重构是因为我缺乏练习,而且没有掌握好工具。 当我开始把重构作为每周的习惯后,我在实操和工具使用上都变得更强了。这个习惯让我受益匪浅,我只后悔没有早几年开始。
6. 优秀的软件工程能力源于经验,去多多积累吧
刚入行时,我很怕高级工程师。他们能一眼看出我没发现的 Bug,对我不懂的问题对答如流。我以为他们就是比我聪明、比我强,这就是现实。
现在,我和许多顶尖的软件工程师共事过,也指导过不少人,我发现完全没什么好怕的。最优秀的软件工程师不过是"学到的知识"加上"真实世界经验"的结合体。知识可以学,而经验需要你自己去争取。
多去寻找机会,接触不同的技术栈、不同的业务领域,去接手有挑战的项目。 我花了七八年才达到所谓的"高级"水平。但在 Uber 这种高速增长的公司,我看到有些人只用三四年就做到了。区别在哪?这些人一直在做有挑战的项目,拼命想跟上周围人的步伐,甚至中途换团队从零开始。他们总是主动要求做新项目,并在团队中率先尝试新技术。我后来也变成了这样的人,只可惜前几年不是。
7. 把学到的教给别人
学习一样东西最好的方法就是去教别人。我一开始是误打误撞这么做的。2010 年,我开始在 .NET 和 Windows Phone 的用户组做分享。虽然我讲得不好,但为了准备演讲,我学到了很多。
现在,每当我想彻底学懂一个东西时,我就会报名去参加公开演讲。 2017 年加入 Uber 一年后,我主动提出去讲"Uber 如何大规模发布后端更新"。报名时其实我并不完全了解公司是怎么做的(我之前主要做移动端开发并管理移动团队)。为了这次演讲,我别无选择,只能把所有细节都扒个底朝天。而且压力相当大:大约有 100 名本地开发者报名参加了那场活动。
许多人都证明了这种方法很管用。Shawn "Swyx" Wang 就是 #LearnInPublic(公开学习) 理念的代表人物。他的成长故事比我精彩得多:转行仅仅四年,就当上了 Netlify 和 AWS 的高级工程师,还写了一本关于学习心得的书。教别人的好处在于你稳赚不赔。你不仅自己学会了知识,还能帮助和启发他人。
我认识的优秀工程师,没有一个不是出色的老师和导师。你越早开始分享和教学,日后做起来就会越自然。
欢迎订阅我的每周邮件通讯,获取类似的文章。内容值得一读,这也是 Substack 上排名第一的技术类通讯。