在「大厂」工作的体验就像当一颗螺丝钉?读过很多软件工程的书却仍会犯下里面的典型错误?感到自己工作效率低下却不知如何改进?要成为一名高效的软件工程师,在理论和实践之间是存在不小的距离需要我们通过广泛学习、勇敢试错和不断反思去跨越的。在 Grow @ Google 这个系列中,我会结合自己在 Google 的工作经历来分享一些经验和教训,帮助大家少走一些弯路。系列中的其他文章请见:
首先让我引用一句出处不详1的话:
Source code is a liability, not an asset!
站在工程师的角度,代码最终是为解决实际问题服务的。不论它们有多么优美、能给人带来多少理性愉悦,更多的代码就意味着更高的维护成本和更多的潜在 bug。
能够明确和认同这一点,在我看来是作为一个工程师迈向成熟的标志之一。这意味着不再对代码本身持有过度甚至病态的执着,也就能够不带(关于编程语言、工具链和技术栈等的)偏见地去欣赏特定场景下特定解决方案的美。
《A Philosophy of Software Design》是继《The Effective Engineer》之后又一本我相信每个工程师都应该读的书。这本书主要讨论了软件工程中的复杂性(Complexity)从何而来,以及如何降低一个软件系统的复杂度。书中对比了两类不同的工程师在解决问题时会采取的不同思路:Tactical Programming 和 Strategic Programming。
第一类工程师就像战术家,只着眼解决当下的问题:可能是抢修一个 bug,又或者是扫除新 feature 上线的障碍。为了在最短时间内达成目标,他们往往会放宽对代码质量的要求,或是违背工程上的最佳实践;第二类工程师就像着眼全局的战略家,能持之以恒地投入资源从而在完成开发目标的同时逐步地、系统性地提升整个 codebase 的可维护性、可拓展性以及测试覆盖率等。
第一类工程师将复杂性和技术债务带入软件系统,而第二类工程师则是我们应该效仿的对象。在现实中,第一类工程师却往往是多数。我们总能找出理由来为自己辩解,比如「能用就行了」,又比如「上一个维护者的代码就写得稀烂,我没有义务去为了下一个维护者的开发效率而牺牲自己的时间」。然而,这样看待问题的结果往往是搬起石头砸自己的脚。
试想你开发了三个月的项目上线在即,PM 突然告知需求有改动。你一边在心里问候 PM 一边翻阅新的需求,发现得在代码层面上做比较大的重构。这时如果先前的设计使得系统的一些行为难以修改,或是没有投入足够的时间来写全面的测试,这个重构可能就会大大推迟项目的上线时间,甚至发展成不得不重写部分模块的情况。没有谁能打包票说自己绝不可能遇上这样的情况。所以,即使仅从自己的利益出发,多用 strategic 的视角考虑问题也是有益处的。以下是基于个人经验的一些具体操作建议:
当然,Tactical Programming 和 Strategic Programming 之间并不是完全对立的关系。除了由于迫于生计而不得不在工程质量和开发速度之间寻找平衡以外,我们对一个实际问题的认知也是在不断发展的。在信息不充分的前期,积累一些技术债务是不可避免的。学会定期偿还这些债务以保持系统的可持续开发,则是成为高效的工程师的关键。
在这个系列的第一篇文章中我写道:
高效的工程师们有一个共性是会强迫症般地投入时间来缩短 feedback loop,从而达到更快的迭代速度。但一个常见的误区是,在身上已经背满工作时,我们最不想做的一件事情就是给自己再创造更多的工作。如果已经存在一个可用的 workflow,即使中间有可以优化的部分,很多人都会倾向于不加改进地继续用下去。
事实证明,这个误区的确是很难彻底摆脱的。从那时以来,我又犯了好几次类似的错误。究其根本,缩短 feedback loop 往往需要先做一些看似比较大的时间成本投入,人在做决策的时候则往往只关注眼前的问题,从而低估了一笔一次性的投入能带来多少的长期收益。
以我最近一次跨入这个误区为例,我在使用了十几次一个耗时 5 分钟的测试流程后幡然醒悟,花了约 2 小时将这个流程优化到了耗时 5 秒钟。只要新的流程能被使用超过 24 次,这笔投资就可以回本。很显然,24 是一个轻易就会被超越的数字,更不用说优化的成果对团队的其他成员以及未来的维护者们也有帮助。
以下是一些更具体的技巧,希望能对打消大家对先行投入时间来缩短 feedback loop 的抵触有一些帮助。
很多人可能都听说过这样一个说法:如果你是一个团队里唯一懂某件事情的人,这就会成为你的核心竞争力,使你成为不可被取代的人。
而如果你是一个像我一样在科技行业的所谓「大厂」工作,觉得自己的日常是在当「螺丝钉」或是「润滑油」的工程师,这个说法就不适用了。做团队中唯一熟悉某个模块(服务、工具、专门领域……)的人并不见得会是一件好事。因为:
跟许多同行一样,Google 对工程师的基本要求之一就是能够独立完成工作。但与此同时,我们也会通过 design review、code review 甚至闲暇聊天的方式去有意识地跟 peer 们 share context。这样做有许多好处: