原文地址
本文csdn地址
本文公众号地址

关于本文

作者以10年在谷歌的开发经验,总结出了一套通用的方法论。译者这里对文章进行粗略的翻译,希望能对从事软件行业的同学有一定帮助,引起大家对平时所做、所看和所学的思考

  • 注1: 本文保留原文的章节架构,为易于理解,再对内容做适当的筛减和补充,偶尔扩展译者从自身经验角度的理解
  • 注2: 原文很长,章节也比较多。建议大家分批次阅读,每次读两三个点,偶尔记下自己的思考,这样读起来不会这么枯燥
  • 注3: 翻译和技术水平都有限,不一定能把作者的原意传达非常到位。因此建议有余力的同学去品一品原文,当然如果你读了我的翻译能有点共鸣,那也算是我的荣幸

作者介绍

Addy Osmani[1] 是一位 爱尔兰籍 软件工程师和领导,目前在谷歌浏览器团队工作。他已经在谷歌工作10年,致力于让网页(访问速度)更快。他还曾在 AOL(America Online,美国在线) 和 Fortune 500(500强) 站点工作。 Addy 还是 《Learning JavaScript Design Patterns》、《Learning Patterns》和 《Image Optimization》等书籍的作者

作者博客首页[2]

前言

今天我将会介绍软件工程中,关于 通用技巧[3](soft skills)的部分。这些技巧是我在谷歌浏览器的前10年学到的,在这里我还成为了高级工程师。在工作10周年纪念之际,我想回忆一些一直伴随自己的课程,也希望这些技巧对读者的职业发展有所帮助

成为一名优秀工程师的过程是不断积累经验的过程。每个项目,不管多大多小,都是你学习技术、丰富自己工具箱的好机会。随着不断积累,当你能够把 从一个项目中学到的技能包,应用在另一个项目 去解决问题的时候,将会有事半功倍的效果

还需要说明:我说的话可能都不重要,一切以你的理解为准(YMMV):)

所有章节一览

  • 精通
  • 批判性思考,提出关键因素
  • 巩固基础知识
  • 通用知识点
  • 效率
  • 做出更好的选择
  • 专注于用户(需求),其他事情会跟着走
  • 提升自己的能力
  • 利用参与新项目的优势,学习新技术
  • 保持好奇心,保持学习
  • 经常做笔记
  • Leader承认自己不知道的方面,将会很有感染力
  • Leader 也需要承认自己犯的错误
  • 做开源项目的caretaker(管理者),而不是owner(所有人)
  • 技术的广度和宽度
  • 从实践中学习
  • 通用代码 vs 专用代码
  • Deep module (模块化) 思想
  • 学会管理一个项目
  • 从新项目(green-field)中学习
  • 定义完成事项
  • 分阶段发布
  • 系统性调试
  • 设计文档的重要性
  • 文档审查
  • 定义你的沟通方式
  • 耐心、深思熟虑
  • 学会说“不”
  • 接受与尊重
  • 信息分享
  • 灵活性
  • 保持记录
  • 真诚
  • 资历和战略思维
  • 以身作则
  • 提升你的影响力
  • “不能胜任”综合症
  • 指导他人
  • 面向领域层面进行指导
  • 组织层面的指导
  • 学员的职责
  • 构建信任
  • 理解业务模型
  • 提升你的影响力
  • 时间管理
  • 过度工作并不是好的工作素养
  • 不断尝试超越自己的标准是不现实的
  • 你不需要知道每一件时事
  • 通过学会说不、了解什么时候该停下来、以及规划好自己的时间(包括工作间隙的休息),主动把自己从焦虑中解放出来
  • 鼓励你和你的团队成员进行休息、旅游和调休
  • 随着对问题的了解深入,更新(排期)评估
  • 有时取消项目是正确的选择(即便是让人感到不舒服)
  • 关于技术债:预防远远 > 补救
  • 如果没有充足的休息,和 work-life balance(的习惯),你的团队将会产生职业倦怠
  • 大型组织/公司中流程会比较缓慢
  • 专注于 问题 VS 专注于 项目

学习新知识

这部分内容能帮助大部分初级和中级工程师 成长,结合软件行业的基本流程和业界的最佳实践,构建复杂系统。尽量跟随业界的第一原则[4]。比如将大问题拆解成一个个小问题,就是你职业生涯中非常重要的技能之一

精通

对技术的精通,能帮你在工作时间产生更多的价值

你可以发现产生价值的工作点,并帮助你的团队将精力放到这件事情上来。同时,也能避免时间花在产出低效的事情上,优秀的工程师甚至可以带领团队从低效事情中解放出来,把工作放在最有价值的事情上

作者经常被(请教)问到:“如何知道我在充分使用自己的时间?”。你可能总是会有 能让自己变忙的各种任务,但真正的诀窍是确保你所做的是“对的事情”。如果你想移动整座山,那么你应该关注如何移动土堆,即使移动很小(即:愚公移山)

一些你可以经常问自己的问题:

  • 我的目标是什么?我所做的事情是否都是为了目标服务?
  • 是否有其他途径 能更快地实现目标?

即使是自己对自己问这些问题,也能够很有作用

批判性思考,提出关键因素

批判性思考是利用足够的认知,进行独立思考,并做出成熟决策的一种技能

有时为了快速响应用户,我们可能会急于用一些快捷方案去解决用户问题。这样看起来会进展很快,但如果对结果和问题原因欠考虑,可能会引起后续出现问题的风险
与之相对,批判性思考就是带着强目的性去思考,发现问题的本质,规避风险
这种带着目的思考的方式,能帮助你更关注到问题的本质,规避那些 因为没仔细分析 根因和结果 而在未来会导致的问题

概括来说,以批判性角度,我会给自己提的问题有:

  • 我们是否在解决真正的问题?(问题是什么)
  • 我们是否在用正确的方式解决问题?(可以从平衡严谨性和效率出发,比如时间不太够的时候,是否可以用更快的方式解决,一般适用于故障解决)
  • 如果暂时找不到问题根源所在,如何找到定位根因的主要思路?(排除法是个不错的选择)
  • 如何把核心问题拆解成一个个可以快速分析的问题?
  • 如果我们有多种解决问题的假设,如何组织工作评估他们?
  • 如果分析问题的时间有限,但是又不宜影响分析问题的严谨性,可以用什么捷径?(参考社区经验)
  • 得到的结论,是否有充分的证据和现象能够支撑?(需要过程)
  • 怎么知道把事情做完了?解决方案足够好吗?(适当回顾,确保不会有新的问题出现)
  • 怎么把解决方案解释给故障影响方?(一般用于故障回顾,将故障具体原因、具体解决方式提炼出概括性的技术说明,保证对方能理解,并认可方案)

这些问题经常能起到帮助作用。有时我们还会遇到这种情况:定位一个问题,结果从表象深入后发现了更多问题;采用一些可以快速解决问题的方案,但是在系统运行一段时间后,发现又因此产生了新的问题
通过进行一段时间的批判性思考,我们不断挑战假设,对收益和风险看得更细致,找到现象之间的矛盾点,评估(现象的)可信度,收集更多的数据,以确保我们现在做的是对的事

举个例子,很多程序员常犯的错误是,误将一个关联关系当成是因果关系(两个事情关联,但并不是说其中一件事发生,就一定会导致另一件事)。一个具备批判思维的人能将思路放回到假设中,并抛出问题:为什么我们会认定这个假设是对的?
这种(带批判性思考的)人还会做的事情有:

  • 提出更具体的问题(比如解析一个大需求:优化接口查询性能,可以拆解成,参数怎么优化,数据层过滤条件怎么优化等)
  • 查询更多资料,寻找和问题之间的关联性(很适合初学者,资料总是不嫌多)
  • 得到合理的结论和解决方式后,按照相关标准和规范进行测试(突出复现和测试)
  • 通过不同的思维方式进行思考,对假设、影响和结果再次评估(形成适用于其他问题解决的方法论)
  • 面对复杂问题,高效交流,找到最终解决方式(面对有复杂上下游的服务)

扩展阅读: 批判性思考是通用技能吗? [5]

巩固基础知识

牢固你的基础知识,并通过不断(在工作中)使用它们,来掌握新技能

从长远角度来看,基础知识长期不变,学到了就能用很久,而且很通用,你在一个领域学到的基础知识在其他领域也用得上

短期来看,基础知识能让你面对问题时,提出更好的解决方案,并让自己的代码更加高效

通用知识点

通用知识是那些可以在不同项目之间都能使用的知识点。让我们从它们和基础知识之间的关系开始说起

基础知识是贯穿整个软件工程师职业生涯的基础。它可以分为两层:宏观和微观。宏观层面是软件工程师的核心(基础知识),微观层面是实现(如:技术栈、库、框架等)

在宏观层面,你能够学到编程相关,高度抽象、和语言无关的概念。它们在各个领域的描述可能不同,但背后的核心思想都是一致的。包括:数据结构(数组、对象、模块、hash)、算法(排序、查询)、架构(设计模式、状态机)、性能调优(及早求值和惰性求值、内存、缓存、懒加载)等。这些概念你会在工作中经常用到,了解它们背后的原理将很有意义

在微观层面,你能够学到宏观概念的具体实现。包括:编程语言(JS、python、ruby)、前端框架(react、angular、vue)、后端框架(django、rails)和应用技术栈(谷歌 app engine、谷歌云平台)等。它们会涉及到很多能帮助你学到专业知识的细节,能让你变得高效, 但并不总是那么通用

通过学习基础知识,你能够收获技能包和工具包,让你(在之后)可以忽略技术实现细节并成长

务实地说,没有人可以在职业初期就学到所有东西。由此再延伸出一个观点:你不应该过多关注基础知识,反而应该学习在现实中搭建项目时需要用到的知识/技能。这也是“在实践中学习”理念的来源

译者:宏观知识帮助你了解技术原理,微观知识帮你把技术具体实现出来。不管是哪一种知识,都需要我们 learning by doing 边做边学,都是需要过程的
不能太过神化宏观知识的重要性(比如各种面试八股文),它容易让你陷入底层,脱离工程
实际情况中,工程相关技能(即微观知识)更重要,毕竟这些才是能在当下帮你赚钱,帮公司赚钱的技能
​不管怎样,两种技术最终还是相互依存的。谁都很重要,谁也离不开谁

效率

理解服务的架构,能帮助你写出更高效的代码,这包括 时间复杂度(运行代码的时间)、内存使用率、以及性能和可维护性之间的平衡
这些考虑点能让你在构建稳定的大型应用的时候,做出有用的权衡。另外对现代应用程序来说,速度非常关键,通常能特别显著地影响用户体验

做出更好的选择

对宏观和微观基本知识有更好的认识,能帮助你做出更优的决定

基于项目的目标和约束,以及你所学的知识,你能够在选择应该用什么技术、不应该用什么技术这两个问题上做出更好的决策,避免在工作中因为选择了错误的技术方向或工具,导致陷入陷阱中

“You haven’t mastered a tool until you understand when it should not be used.” -
你永远没有真正掌握一个工具,直到你知道什么时候不应该用它
@kelseyhightower(谷歌云平台部门谷歌的首席工程师和首席员工倡导者)

软件工程师思考问题时需要考虑很多方面:核心语言、实现、架构、工具和人。只有在你带着敬畏之心,去认真学习这些方面的知识,才能让你更快成长。真正了解基础知识(包括 O(n) 时间复杂度(的算法))能帮助你走得更远,特别是在语言和框架(的具体实现)随着时间不断变化的背景下

扩展阅读:
The value of fundamentals in Software Engineering[6]

Why learning the fundamentals matters[7]

Learn the fundamentals of a good developer mindset in 15 minutes[8]

专注于用户(需求),其他事情会跟着走

从用户体验开始,实现时回归你需要用到的技术

乔布斯说过:”you’ve got to start with the customer experience and work backward to the technology. You can’t start with the technology then try to figure out where to sell it.”
“你需要从用户体验开始,再回归到技术中。你不能先基于(选择)技术,再尝试去找到哪里可以卖出你的产品”

这句话深深地触动了我:作为工程师,我们很容易就会有这种思维:先找方案,不管是社区流行的技术、其他开发者的经验,还是个人喜好,找到方案之后再去找哪里用得上
相反,我们其实更应该专注于我们所服务的对象、需要解决什么样的问题,以及当前的方案有什么不足之处
好的用户体验来自 用户和技术 两个角度的结合。和用户沟通,表达你的观点,你认为他们有什么需求,并认真分析他们说的需求。在用户需求实现上,会有很多细节能导致巨大差别,比如选择什么样的服务架构,能在用户手机端有比较好的体验;以及什么因素会影响工程开发、规模扩展、招聘等的效率?
总结来说,坚持不懈地关注用户需求,在工作条件限制下,坚持以实现用户需求为导向,能够让我们长期受益

最优秀的软件,是由 带着用户同理心的工程师开发出来的

软件能成功,取决于用户满意度,而满意度又体现在用户使用软件的体验上。我们需要了解最终用户侧的体验;确保我们的方案不会影响用户使用产品的同时,完成他们自己的工作
如果你有渠道可以和终端用户直接交流,就尝试去理解他们的需求和痛点吧

译者:理解用户需求并不简单,现实中总会遇到各种问题,译者经历过的主要有:

  • 和用户的沟通渠道不通畅
    • 大部分是平台问题导致的,比如产品首页缺少反馈按钮,用户想反馈问题只能靠投诉(想到了之前遇到的一个产品,想反馈一个bug,甚至要跳转另一个平台才能提,体验极差)
  • 用户需求和产品规划矛盾
    • 大部分用户需求都是站在短期实现的基础上的,和产品的长期规划不一定吻合。比如我想做一个笔记软件,长期来看,体验便捷 和 云端同步 可能是我首先考虑的功能点。对于 画图、共享这种功能,可能就不会排在很高优先级。但如果用户又站在强势地位,要求开发优先实现额外的需求,那开发就要受累了。后面可能就会能看到 产品、开发和测试 天天battle,需求赶着时间做出来,质量很差,转测的时候测试又提一堆bug,开发迫不得已边改bug 边开发,陷入恶性循环中
  • 用户也不清楚真实需求
    • 产品发展初期容易出现。用户对产品没有特别具体的认识,需要产品经理和用户进行更多的沟通,去发掘需求

提升自己的能力

选择适用于你的场景的技术,而不是当下流行的(flavor of the month)

对比两种观点:使用“无聊”的技术(经过充分测试和体验的)也是ok的 VS 跟上潮流技术

语言、框架和库 都在经常发展。选择能帮助你顺利交付最终产品的就好。开始一个新项目时,建议从“无聊”的技术(但非常了解)开始,然后基于这个技术,有意选出最好的工具来帮你解决问题

即使是选择了新的技术来学习和使用,也不要害怕选择一些看上去无聊、不属于“社区”上主流的方向。FOMO[9](Fear of missing out 错失恐惧症)面对 语言、框架、库 和 工具这些技术的时候,可能就不是很有效了,因为更重要的事情是为了交付优秀的最终产品,你需要对自己所用的东西更加了解。请不要盲目为了追求新颖、漂亮的技术,除非你确定它们能为你的方案添砖加瓦。当然,也不要因为某个事情还没有被讨论充分,而忌讳提到它

利用参与新项目的优势,学习新技术

了解 个人开源项目和黑客项目 是学习新技术的好契机
对我们大部分人而言,基于现有项目是很难了解到新技术的,因为技术选型已经基本定型了
刚提到的两种项目,能让你以低风险、低成本方式研究新技术,了解新技术的优势和不足,以及了解可能在未来对你有用的一手知识

译者:另外,对初学者而言,还是要有对做什么项目的期望和思考,先有对项目的初步设想,再去找实现思路(如社区demo)。想法也不一定要很具体,有一个大体想法也可以,比如想做一个自定义规则的天气预报,想写一个小程序等
不是盲目找一个看起来很火的开源项目,随便搭起来就好了。因为并不是每个项目都适合你,越是花里胡哨的项目,越难应用于实际。带目的性的去找开源项目就是最好的甄别方法
再提一点自己的感受:当有一个新技术摆在你面前时,学习它的最好时候永远是现在。错过了现在,你后面就可能花费更多的时间精力去重新捡起来

保持好奇心,保持学习

经常做笔记

写下所学的东西,能帮助你更好的理解知识点。有的时候只有你尝试把自己所了解的知识讲给别人听,才能真正把你不懂的点弄清楚
如果你写的东西(博客)没人看,那也没关系。做笔记主要还是为了自己,(只是记下)你已经从中收获很多了

学习还应该是一个持续坚持的事 – 那些号称自己对特定领域无所不知的人通常都不是真正的专家。真正的专家精通一些技术,但他们能够意识到,总会有(继续)学习和改进的地方。好奇心驱动学习 - 所以如果你对一个新框架感兴趣,那就去谷歌它、阅读它的文档、尝试新手教程、以及阅读源码!学习并不只是出现在教室中,学习可以在任何地方、任何时候发生。每天花半个小时阅读一本书的一小章节,听一次技术广播,阅读技术博客,学一门新的编程语言等

Leader承认自己不知道的方面,将会很有感染力

Leader 需要降低期望:即使是高级工程师,也没有了解方方面面的必要。承认自己对一些细节不了解的同时,并致力于找到 和 团队一起解决问题的方法(即合作),这个比了解技术细节更重要

Leader 也需要承认自己犯的错误

教导下属 用虚心的态度承认和解决错误,愿意从错误中学习和提升自己,是很重要的。告诉下属现实世界并不完美,我们需要对可能发生的错误做好准备

译者: 理想状况下,我们提供的服务还是应该具备高可用、故障后可快速恢复的能力。这样就算是一个刚接手服务的同事,也能有快速上手的自信。遇到问题也能冷静处理
当然,不得不说,基础设施、服务维护工具和服务架构设计等,也是达到这种理想程度的基本条件。做到如上所述完全理想的情况不是不可能,只是确实有难度
如果你所维护的服务正好没有做到上面几点,那就根本别指望不会出问题,更别指望能不被用户投诉、领导责备了。不过这个时候,也只能想办法去尽量改变现状。每次犯错都去责备团队或者责备自己,对现状不会有任何改进

做开源项目的caretaker(管理者),而不是owner(所有人)

在项目发展的初期,以 owner 的角度去思考是没问题的。你会经常去思考项目的价值,开发新特性和回复 issue。对为项目争取社区支持、赞助是好事,但随着项目人员的变化,以及个人时间受限,这种模式对项目的发展就不是最好的了

经过初期的项目规模收缩之后,另一种参与项目的方式是成为项目的管理人,而不是所有人。管理人的角色更专注于扩大自身的影响力。比如和其他项目所有人、贡献者和社区之间 分享知识(通过文档、代码注释、最佳实践文档化等)。这对扩大项目的 reviewer 规模同样有用,有助于后续不再参与项目的时候,项目也能朝着正确方向发展

技术的广度和宽度

考虑成为一个全才和某一领域的大师,哪一个更适合你?

你应该掌握的一个很重要的技能,就是掌握 如何学习 的方法。这比你怎么说更重要,(你需要做的)只是深入到编程语言或者框架的底层。另外这也有助于保持好奇心。一旦你经历了这种学习方式,你可能就会提出刚刚说的问题:是追求成为某个领域的专才,还是全栈的多面手(a jack of all trades)
我个人更喜欢成为 T型工程师[10](T-Shaped Team Members) 的想法。这种工程师会在一个或少数几个领域有深入研究(T 的纵向深度),但对构建和运行大型项目需要的多个领域的技术,也有基本的认识(横向宽度)。有的团队会愿意将团队成员定期相互交换,来培养这种 T型工程师
我已经发现在中-大型团队中,如果有那种在某一领域专长的人员,能够很有效地补充其他人的技能、全面性和合作能力

译者:初学者还是建议以技术宽度为主。宽度能帮助你快速定位和解决问题(打开思路、用好工具),然后能更专注于研究深度。因此确实不要放过任何一个能学到新东西的机会
而最理想的状态,就是在对大的领域,比如后台,所有热门技术栈都有实践性的认识,同时对1-2个领域有非常深的实战经验

从实践中学习

学习一门新语言的时候,需要专注于构建有形的结果,能让你有更深刻的一手体验
不一定要完整阅读新语言的官方文档,记住所有的特性、关键词。了解这门语言如何解决问题更重要。从demo项目中,或者亲手写代码来获得经验。正如《Why Bad Software Happens to Good People》[11]这里所说,“软件的主要价值并不是产生的代码,而是创造这个语言的人传递的知识本身”
也要注意:不要在生产环境进行新技术的试验

技术复杂度

通用代码 vs 专用代码

解决手头问题的时候写专用代码,但也尝试能让代码变得更通用的地方

当我们为了解决一个问题的时候,往往会因为紧急程度、升级复杂程度等,写出一些比较不那么通用,只是为了快速解决问题的“专用”代码。
通常,我们会先尝试写出尽可能通用的代码,最后写出那些看似高效的代码,但并不能解决问题。实际上,(应该)先是为了解决问题写代码,再去找到可以让代码变得更通用的地方,这样能在更迅速地解决问题的同时,减少后续再回顾和重构的时间(译者:解决手头问题的时候,短期效率还是排在第一位的)

关于设计复杂度上,有一些通用的原则:
YAGNI(You aren’t gonna need it)[12]、Do the simplest thing that could possibly work[13]
这两点说的其实是一个事:不要过度设计[14](overengineering)。尽量通过最简单的设计完成工作,让后续的需求通过快速迭代实现,而不是一开始就把所有特性都规划好。不过滥用这两个原则,也容易导致设计出过于抽象和简单的方案,后续不能很好地实现和集成

另一方面,你还会经常听到抽象原则[15],旨在通过抽象和通用化思想,减少重复代码。我更喜欢在极端抽象和极端简单中找到平衡点,AHA[16](Avoid Hasty Abstractions)(避免过度抽象) 体现了这种思想

Deep Module (模块化) 思想

解决复杂问题,并通过开放清晰的接口给其他开发者使用

如果你是一个API 的设计者或者开发者,你的职责就是提供能简化功能的接口。如果接口过于难懂,让其他程序员调用需要花费过多成本,那这个接口就是不合格的。这个理念同样能在 Deep Module[17] 的思想中体现:“最好的模块能够同时提供最好的效果和最低的成本。效果就是它的功能,成本就是它的接口”

尽管让接口变得简单是可行的,但代码不一定,复杂问题有时就是需要复杂的代码来实现(这是一个通用规则,但不一定总是正确)。复杂度最好是内嵌到代码中。复杂的功能抽象程度越高,作为接口提供给最终用户的价值就越高
API 使用越多的函数和类,就越难被搜索到。随着函数和类的新增,将会增加 程序员的维护和接口使用的成本

译者:接口设计规范也是老生常谈的规范了,这里简单提一下

  • 接口的入参不应超过3个
    • 接口入参 其实就能体现给用户调用这个接口的成本。参数越多,也意味着这个接口越复杂,甚至不是复杂在功能,而是理解成本
  • 用更少的类实现接口
    • 这里就涉及到模块架构的设计了,比如一个 http 接口,最普遍的分层方式就是 api 层 + controller + service + 数据层
  • 接口名称
  • 接口返回值

学会管理项目

处理旧系统的代码时,应该理解需要保留的代码,和需要废弃的代码之间的区别

大型、年久失修的项目往往会有一些不好的、没有好的理由再保留下去的代码。应该去深入了解这些代码,分析留下的理由、去除的理由。去除坏代码,留下好代码

我曾经在很多公司中遇到过这种情况:同事们认为旧的代码是不可动的,或者是出于一个好的理由设计的,导致这些代码流失于历史之中(译者:即没人敢动,也没人能动的状态)。这会产生对修改旧系统代码的畏惧感,只能在一个脆弱的基础上继续添加功能

软件行业已经发展到了一个阶段:很多团队都需要维护或者迁移 旧系统。当你发现自己就在这样的团队的时候,不要灰心,你可以从这些旧代码中学到很多特定领域的知识。尽管旧的代码在生产环境中继续保留 会有充分的理由,你还是可以怀疑不是每一行都有存在的价值

有的软件开发者会对修改在线上环境运行的代码很谨慎,担心会导致bug。所以他们会根据现有的系统的代码,通过重复代码来添加新功能(译者:比较典型的情况就是修改接口,对旧系统存在 bug 的接口不敢改,而是添加一个新的接口,但这个接口绝大部分代码都和旧接口一样)这种解决方式在当时会很省时,但随着时间推移,维护就会变成噩梦了。不要假设现有的代码都是可靠的,它们在可扩展性和效率上可能会有问题,你可以去尝试发现这些问题

从新项目(green-field)中学习

实验、创新、快速失败和更好地解决问题

当你的任务是从头开始搭建一个系统的时候,你的学习之旅就将很不同。在迭代制作原型、实现特性的时候,你将能学到什么能起到作用,什么不能
敏捷方法论快速失败 [18](fail-fast)的原则,将帮助你通过很少的资源就能确认你的想法是否正确。它们能帮助你拆解并解决复杂问题

译者:敏捷开发这块,现在已经有很多开源的工具,可以帮助我们在本地实践。简单列几个:

  • 代码仓库:gitlab(需要使用体验)
  • 发布:jenkins
  • 镜像仓库:harbor
  • 服务管理:k8s、istio、etcd等

定义完成事项

定义什么算是“完成”事项能节省时间,因为它能帮你评估所需要的工作、制定开发计划、并避免不必要的调整

在解决复杂问题时,有效的敏捷原则是对 “完成”事项(The Definition of Done[19]) 达成一致。除了用户需求列表和验收标准外,还包括代码审视(code-review)、测试、文档化等

译者:这里体现一种“闭环”思维:在手头事情很多,需要来回切换的时候,事情做得稍有疏忽很正常。因此需要特别注意 “完成” 事项的明确
比如刚给用户改完一个bug,在用户群回复用户、知会受影响方、提交fix代码,都是需要“闭环”的事情。可以先稍微花点时间先把它们写下来,避免忘记

分阶段发布

单个大的版本可以拆解成一系列低风险、容易理解的小版本来发布

在大型生产环境系统 进行 版本发布的时候,版本发布计划的重要性不亚于 架构、代码实现等。通过迭代开发、分阶段发布版本,能帮你更好地管控因重大更改而导致的风险。你还可以制定版本发布策略,包括开发、测试策略,来保证在发布复杂特性的时候,有(完整的)端到端计划

系统性调试

当你在 debug 的时候,你应该系统地、严谨地解决问题,确保覆盖到了所有的测试条件

总是阅读错误和堆栈信息。那里大概率会有关键信息,能帮你定位和解决问题
惊人的是,很多工程师在调试之前,都会忽略错误信息能提供的线索。我们应该假设 机器/软件能告诉你发生了什么问题,而不是假定 稍微做点修改、重启服务就能解决问题。如果你还没有仔细阅读程序抛出的异常,就开始写解决方案,你可能会浪费时间。大部分情况下,异常信息中就包含了真正错误的提示

文档

设计文档的重要性

设计文档不应该放在后面来考虑,而应该是软件开发过程的一部分

设计文档能帮助你和 同事 或者 其他需要和你的系统进行交互的团队 之间获得共识,是一个无处不在的工具。从他人获得的反馈,又可以让你认识到差距,并改进你的设计。设计文档还可以为后续加入团队的工程师提供宝贵的帮助,可以帮助他们理解问题,在设计解决方案的时候考虑到权衡点、替代方案等。设计文档也提供了一个团队空间,能够记录所有设计的参与者,以及它们的贡献,作为历史文档的一部分,以方便他人找到具体解决方案的贡献者,以及方案具体解释的负责人

译者:一个成熟的项目,团队空间中包括的文档应该包括而且不限于:

  • 项目 milestone
  • 公司权限申请帮助文档
  • 服务设计文档
  • 服务环境、部署文档
  • 内部服务和第三方服务的接口人

文档审查

协同检视设计文档,比较当前文档和历史文档,确保所有依赖项都被记录了

尽管每个人都可以在文档中记录设计思路,但实际的设计过程通常出现在白板会议、随机面对面讨论、空闲时间段 或者 邮件/手机讨论(这种随时发生的场合)中。在这之后,只有通过文档把设计记录下来,你才能确认 结论之间的矛盾点,并确认(现在讨论的结论和)之前讨论过的点是否吻合。初稿完成后,需要进行审视,确保所有相关人员都参与进来。另外,随着项目发展,还是可能存在代码实现 和 文档中记录的设计思路 变得不吻合的情况(因此文档需要定期审查和更新)

沟通

谦虚、清晰沟通、并尊重他人。保持亲切 本身不计成本,它产生的影响却是无价的。有的人会认为 沟通需要消耗能量和思考。正是因为如此,我们需要以更多的能量和热情来和他人沟通

沟通是一个非常关键的通用能力和社交能力。成为一位有用、高产、和高效(effective, productive, and efficient)的软件开发者也离不开(和他人)沟通。沟通不通畅会导致(开发出)不正确的功能、不兼容的代码、冲动的团队氛围等。沟通能帮助开发者更好地理解需求,避免问题继续升级
理想情况下,软件开发者是把(大部分)时间花在编写代码上的。但是为了保证我们的产品真正对用户有用,我们还需要和团队成员同步工作(进度)、业务需求和用户期望。这让协作和沟通成为我们工作很重要的一部分
初级工程师主要的沟通对象是 其他团队成员、测试工程师和项目leader,分享想法和解决问题的方案。随着我们职业发展,为了有效完成工作,需要的沟通量将会越来越多。邮件、会议和公开演讲也会变多。我们必须和 业务leader、项目经理、利益相关人员沟通。然而沟通越多,产生误解的风险也会越大,因为不是每个人都能轻松理解你的表达方式

定义你的沟通方式

和沟通对象 确定好 语言、概念 和 沟通细则的相关性

不管我们对问题或者情况有多么理解,和别人沟通的时候,我们还是应该设计好沟通关键词,保证沟通对象能够快速get到 和自己相关的内容:

  • 和业务人员沟通的时候,谈论你所做的事情在业务层面的影响。避免使用过多的技术术语
  • 和工程管理人员沟通的时候,说明技术影响和挑战
  • 和决策者沟通的时候,描述你期望的可行方案,以及这些方案的影响和风险,不要谈到方案实现的细节
  • 提供状态更新的时候,需要特别关注随着更新可能导致的周边影响,以及你的更新和目标之间的关联度

这些原则 同样适用于写邮件和举行大型分享。你需要写下和沟通对象相关的事项。在分享的时候,还需要保卫你的观点,以深思熟虑的态度回复问题,膝跳反应(knee jeck)的回答方式通常不适用于沟通

耐心、深思熟虑

亲切是一种超能力,尝试用好它

成为冷静、亲切和乐于助人的人,能让你走得更远,而不是切断自己和其他人的联系。善于帮助团队内的同事,能帮助你的团队变得更强大和更成功。对团队外的成员也保持友善,对公司的职能部门同事(hr、财务、市场)也给予同样的尊重,(在工作上)你可能不会直接帮助到他们,但你可以理解他们的工作,对他们拥有同理心。当他们在工作上有所成就,或者获得赞誉的时候,也同样送上你的祝贺和赞赏。善良是能传递下去的,那些你曾经善待的同事,在未来可能也会积极回应你的需求

不要吝啬(be liberal)称赞他人

产品需要改进的时候,(问题的)反馈很重要。产品体验很优秀的时候,正面的反馈同样很重要。这能帮助你的团队(成员)明白 正在做的事情是能带来改变,并且是有价值的

学会说“不”

说“不”比工作过度要更好

很多时候在工作逐渐累积的时候,我们都不是很擅长说“不”。要么是因为没有意识到说“不”其实是一种选项,要么是我们沉迷于挑战之中。但是过度工作是一种负担,它可能会导致交付延迟。让其他人也知道你正在进行的计划,以及一个合理的时间预估,也是一种尊重的态度。因为这能够让其他人调整他们的选项:向其他人寻求帮助,或者推迟时间表。如果 leader 能了解到(过度工作)会明显影响产品交付质量,他们也不会强行要求你在很紧的时间内完成工作。如果你是高级经理,请让你的团队成员有权利对坏主意说“不”
高级工程师是很擅长于说“不”的。人们会试图占用你的空闲时间。你可以平静而又坚定地说不,将他们指向其他思路,或者让他们找你主管,确认你到底是否可以将更多的时间,花在帮助他们身上(而不是手头的事情)” - 观点来源[20]

你不可能让所有人感到满意:不管是说 “yes”还是 “no”都要格外小心

领导对一切事情说“no” 的对应面,就是对一切事情说“yes”,并且两者没有明显的边界。承担超过 利用现有的资源(人力、时间等)能承受的工作范围,可能最终会导致你自己、你的团队和客户都受伤。向下属制定 什么时候应该说 “yes”,什么时候应该直接拒绝 的规范,对 leader 来说是特别重要的

接受与尊重

敢于承认你不了解的东西。开放地接受别人寻求帮助的请求,包括初级工程师(的提问)

承认你不知道的事情,是很ok的。对软件工程师来说,最重要的技能之一就是找到问题的答案,并从中学到东西
作为一名 高级leader,需要学会接受 身边的下属 可能比你更了解工程的技术细节。承认你不了解一些细节是 ok 的,让下属负责解释他们。下属会因为你的诚实,以及对学习的兴趣,对你更加尊重,你也会对当前团队正在做的事情有更清晰的画面,并在这些事情上增添更多的价值。作为初级工程师,你应该向更高一级工程师把技术概念和方案细节解释清楚,可以是开放式(交流会),也可以是在会议室,取决于你觉得哪种方式比较舒适

信息分享

通过会议 或者 问答 的形式,提出合适的问题,交换所学,并在团队中分享

举行会议的时候,不要只是一个人在说。会议是一个很好的 分享想法、提供真实反馈的机会,除了表达自己,也应该给别人一些空间去发言,并认真倾听
初级工程师可能会羞于提出过多的问题。如果你是高级工程师,你可以通过提出(需求)上下文,来提示他们提出正确的问题。筛选问题之后,也要让提出问题的同学知道,你对(真实)问题的抛出感到高兴

灵活性

捍卫你的观点,但是发现新的观点,和自己的观点对立的时候,也要懂得审视它们

审视其他观点,也是交流的重要过程之一。有不同于自己的观点是很正常的,因为一个问题的解决方法本来就可能不止一种。与其固执于自己的观点,不如去倾听、审视其他观点。说不定这些不一样的想法,还能让你的观点在之前忽略的方向更进一步。Paul Saffo(斯坦福大学工程学院的咨询教授) 的原则 “Strong opinions weakly held[21]” 告诉我们要捍卫自己的观点,同时也要在发现新的对立现象之后,及时更新观点。这是一种科学、通用的方法论,不管提出观点的人是谁

保持记录

非正式会议之后的一封邮件,有助于我们确认讨论的关键点和关键进展

完全口头的交流有一个缺点,就是会后 (讨论过的事情)很容易忘记,或者是记错。保持会议过程所发生事情的记录,以及所有讨论点的总结,能降低这种风险。如果你和另一个同事已经确定要参与一项任务,你需要通过邮件将 ddl 知会到所有相关人,包括你的导师。在事项的(排期)评估讨论过程中,对尚未具体排期的计划进行记录也会很有用

真诚

了解在什么时候应该保持冷静,观察正在发生的事情

有的时候,你对团队讨论做出的一些决定 会不太理解,或者是这些决定无论从技术还是业务角度看都不合理。这在跨团队讨论过程中可能会出现。(尽量)表现出你的真诚,并假定人们不会冒着 带有恶意 的风险。可能你只是对整体背景还没有完全的认识,或者是参与讨论的人们有各自的优先级考虑。你需要提出你的疑惑,列出你的观点,而不是对最终决定直接表示愤怒和消极

译者:“沟通”这一章节所说能否应用到现实,建立在团队有开放的交流氛围、leader和其他成员乐于听取你的想法的基础上。当然,现实情况并不总是那么理想,但不管怎样,保持冷静,少冲动做事是总没错的

资历

我们期望不断提高自己的资历,不管是从角色还是能力方面。有的人会对高级工程师职位感兴趣,有的人会更愿意往团队leader或者部门管理方向发展。不管是哪种选择,在我们职业发展的过程中,总会有一些关键特征,是会慢慢展示出来的。在你的成长过程中,你可能会由你的导师来带领你,下面是我的一些方法,可以帮助你在走上高级职位之前,准备好必要的素质

资历和战略思维

不要害怕做决定,或者表现得很不确定

大部分时候你会发现,做决定的结果比不做决定要好很多。至少你的决定能让别人知道,你在朝哪个方向前进。作为leader,我们往往没有花足够的时间审视 整个团队到底期望我们做什么样的决定。即便如此,我们也不会这么去审视,因为我们不可能掌握 100% 的事实。我们确实应该在做决定前,尝试描述所有的依据和细节,但不可能做到面面俱到(特别是时间紧张的情况下)。(过度注意细节)这可能导致团队 长时间陷入 停滞、不确定的状态。通过有限的信息,在有限的时间作出的决定,效果反而会更好(译者:感到没事做是最不好的状态,对个人和对团队来说都是如此)

leader 负责补充自己的知识库,来让自己全方位、战略性地思考,并为他人制定前进路线图

随着经验成长,你的战略性规划、将想法应用于更多领域 的能力,也应该提升。从独立开发者角度出发,你可能会专注于你所负责的任务,还有需要实现的功能。但随着你的进步,你的影响力就不仅体现在工作任务和负责项目上了。在权衡选择时,你将学会根据选择带来的 效益和限制 两个角度,去思考更多的东西(即权衡利弊)。举个例子,在早期 你只是为了自己的团队,指引组内其他同事 去做决定,随着你的成长,你的选择和交流将会影响到多个团队

以身作则

向团队传授学习方法。不要只是为了解决手头问题而去行动,耐心地指引他们 去锻炼一些能力,并让这些能力为自己服务

工程师行业的领导善于授权。随着你的职位越来越高,尝试下放原来属于你的工具、权限、责任等,让团队成员自己去用这些资源并取得成功,(对下属)会很有帮助。这也是你继续提升效率的方法。还可以通过 提出好问题 来提升,而不只是回答问题

在别人提供解决方案的时候,以身作则地 负责具有挑战性的任务,并提出(过程中遇到的)相关问题

技术领域的高工 需要负责 团队内和团队外的协作、沟通和共识建立。他们致力于提高团队的整体产出,而不仅是自己的。作为高级工程师,你可能偶尔是为了学习新技术,或者是了解行业现状 去写代码,但这种事情并不会被写在工作内容中(需要自觉去做)。现实中,你还需要自觉去审视代码,确保架构图中没有疏漏。你还应该为自己的决定 如何带来技术或者商业价值 收集好依据和原因
高级工程师还应该熟练管理软件系统和团队。你可以领导一个多元化的工程师团队,分配给他们 注重代码质量、性能、复杂度 的任务,及时给予反馈和指导。同时,你还应该适当展示你的能力、工作和技能,让自己未来有能力解决具有挑战性的问题,在团队甚至公司获得知名度。总而言之,你应该培养和团队内同事、公司内领导层的关系

提升你的影响力

伟大的软件项目通常是由团队创造的,而不是个人。所以 如果你想实现更多的目标,或者在公司展示 你已经为成为 高级工程师 做好准备了,你需要通过合作和指导力来展现自己。提升影响力,不仅仅是为了自己,也为了团队的其他同事

当我意识到需要扩展自己(的能力)的时候,就是我在google公司内向着成为高级工程师的时候。我必须在考虑 “我”和 “我们”的模式之间切换。通过和其他人协作、分享所学、专注于提升身边同事的经验和技术,我们深刻意识到做了更多有价值的事情

如果你是从独立开发者开始,你可能不会专门领导一个团队,但你可以寻求更多志同道合的小伙伴来和你共事,实现一个人难以实现的项目。随着你的技能、职位越来越高,你会通过建立团队,进一步提升工作效率,来继续贯彻这种(合作)思维

“不能胜任”综合症(Imposter syndrome[22]

尝试接受 犯错误、难以找到答案、需要寻找指导 的工作过程,可以帮你克服“我不能胜任”这种心理负担

我们在工作中几乎都遇到过,对特定的工作或者是角色,(一开始)会感到自己并不能胜任。这种心理是非常普遍和真实的,甚至在一些已经获得明显成就的人身上也会出现。即便是别人会找自己咨询意见,你依然可能会觉得自己不适合。甚至你永远也不会放下这种内心负担,但它确实能激发你的好奇心,推动你去学习新东西

指导

指导他人

及时提供信息和指导建议,让你的学员不至于陷入完全不正确的方向,而是通过做好自己的事情来掌握技能

在你职业生涯的发展过程中,你可能会发现自己时而是导师,时而是学员。作为导师指导别人,不一定非要很正式的过程。非正式(日常工作)情况下,你也可以寻求指导别人或者获得别人的指导的机会。指导别人可以锻炼自己的人际交往能力。下面是一些指导的关键点:

指导别人是引导别人去发现答案,而不是直接给他们最终答案。允许你的学员在解决问题的时候多尝试,多实验,因为他们有直接感受解决方法的风险和收益的最佳机会。不过,你也应该及时把解决问题用得到的工具(比如方法论)告知给他们,如果是一个技术问题,也可以参与讨论,提出你所建议的想法和方案,具体实施还是交给他们。让学员也分享所想,提出问题,进行对话讨论

如果你的学员发现自己很难找到问题的解决方法,你可以分享你会怎么去分析问题,接近答案,以及为什么你会用一个特定的模式来解决问题。教会他们分析问题和debug的方法,分享你在 诊断问题、提出解决方案、实现解决方案 和 debug 时候的思路。分享如何解决问题的技巧,而不仅仅是答案

组织层面的指导

指导别人是作为高级工程师的职责之一,有助于在组内成员变化之后,依然能保留关键领域的知识

假设你在很投入地指导别人,而且也是你日常工作的一部分。这种情况下,你就需要安排一部分工作时间,专门用在指导活动上。这能让你指导的效果更好,在指导生涯中做出更有意义的事。有的公司还会根据职责发展阶段和要求,在员工发展的每一阶段都会对 导师/学员机制 有一定的流程规范

学员的职责

导师可以给你建议,但真正评估和实施方案的还是你自己,你需要对自己的职业生涯发展和成长做好规划

假设你是期望在团队内成长起来的初级工程师,我只有一条建议给你:找到那些能帮你规划职业发展的优秀导师
你会在职业生涯中,遇到仰慕的教练、导师和同事。他们会给你如何培养技能的建议,但真正实践还是得靠自己。吸收别人的建议时,也要注意技术层面的条件,不同场景,有效的法则也会不同。在一个项目有效的理论,换个项目就不一定适用了(具体情况具体分析

高效的团队

构建信任

信任可以将团队人员拧成一股绳,朝着共同的目标努力工作。相反,官僚主义会让彼此产生隔阂

当工程师一起参加一个开放、公正的头脑风暴会的时候,(这种形式)为能够驱动创新 的新的想法和不同思维角度(的提出)铺平了道路。(这种开放的氛围)确实能驱动团队变得高效和高产出。不过团队内成员能高效合作的基础,还是健康的沟通和关系。下面是一些构建和管理高效团队的关键点:

构建起信任,是团队构建中最重要的事项。跨越不同级别的同事之间的信任,对工作事项能快速完成、团队能高效运作很必要的。团队成员可能会使用不同的开发工具,比如为了检查工程质量而使用的代码检视工具,或者是测试工具。然而如果没有信任作为基础,这些(开发)过程都会变得乏味和官僚主义。举个例子,如果你信任一个工程师和他的代码,那么在进行代码检视的时候,就会更少地吹毛求疵

译者:确实有的公司盲目追求编程规范,搞了各种可信认证,已经让编程完全变了味。译者认为,可信的目的并不是让大家都变成“一样”的人,写完全相同风格的代码,用同样的工具,甚至用同样的开发语言。如果是这样不如开发一个机器人来写代码,而是相信他的代码上线之后能稳定运行、代码风格比较规范、代码具有可扩展性等

真正开放、有彼此促进的开发氛围,是需要靠实际的团队合作培养出来的,比如分享、代码检视会等,而不只是各种枯燥的考试和认证

理解业务模型

理解变更会对业务侧带来的影响

当你(从业务侧)接到一批需求时,你需要了解它们背后的动机。一定不要跳过需求文档中的“目的(或背景)”和“业务目标”章节。你还可以通过(向产品经理或用户)提问来了解业务模型,以及它和需求之间的关系。通过(检视)现有的代码,或者是一次和SME(subject-matter-experts 行业专家)之间的交流,可以让你对领域和架构有更深入的视角。在进行系统流程和数据工作流(data flow)的时候,请参考业务文档、特性地图 以及 使用示例等

“大部分软件工程师都喜欢带着技术上的挑战去解决问题。然而当你理解业务的角度(去思考)时,你会收获更多,比如成本更低的解决方案。要记住你的用户/客户 使用你的产品,也是为了去完成他们自己的工作,就像你完成每天的工作方式一样。尽量不要让他们的工作比使用你的产品之前还要困难” - 来源[23]

提升你的影响力

对业务-软件之间的关系 保持一定的洞察力和敏锐度,能提升你的工作影响力

对业务和产品进行360度的审视,能帮助你对团队和项目有更积极的贡献。如果你能够从销售和市场人员的角度进行思考,你将能够有更好的方式去做出正确的选择和高产出的工作。随着你对团队的影响力的提升,你对工作的满意度和工作给你的收获也会更多(译者:当然这是一种很理想的情况:工作和成长是相互促进,正相关的关系)。领导会注意到,你有能力自我驱动,不需要过多的监督,就能够做出对团队、项目和业务都有促进的事情,来提升整体效率

Work-Life balance

如果你已经掌握了 技术能力、人为因素和领域方面的知识,作为软件工程师,你将会更受欢迎。团队内部的同事也会经常向你请教。除了工作本身的工程任务之外,你可能还需要承担过多协作相关的事情,导致协作过载(collaboration overload[24])。过多的临时请求会侵占你的时间,导致你没有精力去做真正想做的事

时间管理

Deep Work(沉浸式工作)规划好你的时间表

你需要在日程中专门留出一部分时间,用来做 Deep Work。坚持了几年,我发现这个方法对编写设计/策略文档,或者钻研一个技术问题是非常有效的。Deep Work 是一种远离干扰、深度集中(注意力)的工作模式,能够在有限的时间创造出很多价值。Cal Newport(乔治城大学计算机科学系副教授)的《Deep Work》[25]也谈到了这一点

注意力残留”(Attention residue)是 Cal 提到的一个观点,也是 为什么 持续的 Deep Work 能如此高效的原因:每当你从一件事情切换到另一件事的时候,内心注意力的“残留”,会让你依然陷入对上一件事的思考上面,很难重新集中注意力去做当前真正重要的事

Deep Work 通过让你专注于一件事情上,最大程度地提升你在有限时间内的产出。期间没有打扰,没有推特,没有会话或者邮件。我非常推荐你尝试一下,对那些认知工作比较重的任务(译者:需求方案设计、技术问题定位等),放在 Deep Work 的时间去完成它们

我还发现偶尔换一个工作位置,对 deep Work 很有用。我们可能会陷入到(“过于习惯”)一些特定的工作地点和特定的工作任务,如 一个桌子、一个房间、高楼里面(需要完成老板日常吩咐的任务)。适当进行一些改变,可以帮助我们重振活力

译者:有意思的是,我有个导师也经常这么做。一开始还纳闷怎么每天他下午3点多都要出去工位一段时间,后来接了个茶才发现,原来他正在茶水间摆着电脑沉浸式敲代码呢

尽量不要打乱自己的工作时间

如果你的一个小时因为分心,被分割成几分钟的时间块,你可能会感到焦虑。找到让你分心的原因(不管是因为自己还是别人)并解决他们。否则你的一天将会变得很低效

译者:这里提几点比较具体的建议:

  • 每天都固定留至少1h 用于专注做1-2件事情上(尽量是做有长期价值的事)
  • 专注模式下,尽量关闭社交软件的通知,眼不见心不烦
  • 通过公司内部的聊天工具备注,或者是其他方式,把自己的专注时间也告知别人,让别人尽量尊重你的时间的同时,提高彼此沟通的效率
  • 专注模式尽量用在精神状态比较好的时候,这个因人而异,对译者来说就是下午3-4点的时间
  • 也分配一个“杂事模式”,专门用来处理bug、回复、部署等这一类偏流程或运维的事情
  • 临时的事情超过3个,一定要排个优先级,防止安排不过来(毕竟人类大脑在“多线程切换”这件事上可没有计算机这么灵活)
  • 进入专注模式前,对自己要做的事尽量拆细,做到万一真的被打断了,能快速切换状态
  • (作者)切换工作地点,给自己寻找不一样的灵感。译者就发现有的大佬喜欢到茶水间/会议室专心写代码,远离嘈杂的办公位

过度工作并不是好的工作素养

你不可能比所有人都更努力工作。很多公司都以“加班”作为工作态度的“标准”,并将他们和良好的职业道德挂钩。然而成功来自很多因素,绝不仅仅是加班

不断尝试超越自己的标准是不现实的

我对此感到很惭愧。如果你想保持平静的心态去开发,避免疯狂的工作环境,你需要有“知足心”,对现状保持满意。作为领导,你应该领导你的团队形成这样的氛围,有“足够好就可以了”的心态,树立好的榜样

译者:说白了,就是“反对无休止的内卷”。对个人来说,不断追求更好的自己是好事,但是对团队来说,看不到努力的天花板,不知道做到怎样算是足够,绝对不是好事。Leader 在给员工审核目标的时候,也应该给每个下属明确“达到足够”的指标

工作时间是有限的,与其花更多的时间,不如减少没有必要的工作

(市面上)已经有很多关于如何更好地重新梳理工作的指导(书、文章),然而真正的问题可能是在一开始就规划了太多需要完成的事情。你完全可以毫不犹豫地消除没有必要、浪费时间的事,而不是试图管理本来就有限的工作时间

你不需要知道每一件时事

很多人会对没有跟上实时热点感到焦虑甚至害怕,这也是人们会沉迷于每个小时都去刷推特、reddit、instagram 等等(社交软件)的原因。我肯定也经历过(这种心态)
大部分信息对我们来说都没有那么重要,(与其关注时事)应该尝试更多地阅读读总结类的新闻,或者是减少查看时事的频率
Jason Fried 的 《It doesn’t have to be crazy at work》[26] 里面提到了关于这方面的更多思考

通过学会说不、了解什么时候该停下来、以及规划好自己的时间(包括工作间隙的休息),主动把自己从焦虑中解放出来

时间管理和把握好工作-生活的平衡,对每个级别的工程师来说都至关重要。长期加班可能会让你倍感压力和失去动力。压力(过大)还会导致其他身心健康并发症。在一天结束之前把问题都解决完,会很诱人,但慢慢地这可能会变成一种(坏)习惯(加班)

扩展:压力对身体带来的影响[27]
(建议在医学生的陪同下阅读)

鼓励你和你的团队成员进行休息、旅游和调休

你的健康和家庭都是很重要的。如果你能意识到这点,并作为高级工程师给团队其他成员做好示范,这将会很好地提升职场整体的幸福感。反之,筋疲力尽和倦怠(的工作氛围)会导致职场氛围非常不健康

随着对问题的了解深入,更新(排期)评估

在工作中,总是会有客户或利益相关者 这样的角色,会想要了解产品什么时候可以交付,以及所投入的成本(人力、机器等)是否值得。这是非常合理的。有时他们想要对齐DDL,或者确定 为了支持你的工作,需要进行的依赖项(准备)的规划

众所周知,软件层面的 DDL 很难准确预测。只有在项目进入特定时期的时候,才能给出预估性的截止时间。随着时间推移,了解了团队解决问题的能力之后,(leader)应该更新预期。初次预估通常是最不靠谱的,但它作为起点,可以在之后不断被修正初始预估还会比较保守 — 当产品需求、用户体验或者是依赖关系不清楚的时候,一个更宽松和保守的预估,对项目发展是有帮助的。我还发现,通过和 PM 合作,保证我们都在讨论同一件事情,来制定预估,能经常获得成功

软件预估的问题在于,初次预估被固定下来之后,是当做计划,而不是初稿。当团队处在关键阶段,将初步预估当成计划(之后),却不注意及时修正,就可能会带来问题(译者:也不必做惊弓之鸟,需求排期大概2-3天左右更新一次即可)。一旦项目获得批准,细节更是需要留意 — 随着对如何实现需求有更加清晰的认识,原本3个月的预估可能就要变成2个月(或4个月)

你几乎总是尽可能想要让预估驱动你的计划,或者是让计划驱动更新你的预估。在我的团队中,如果我们确实有一些不可推迟的 DDL(如会议),(其他需求)预期超过ddl 可能也是可以的 — 我们可以通过修改提示(如:预览,或在界面提示:该功能将在不久之后实现)、将需求推向更久之后的未来完成等,这些都是可以和领导商量的选项。当然,我必须确认,这些(变化)并不总是这么微小(所以需要谨慎考虑)。当工作计划变得紧张的时候,我们可以把工作拆解成 “必须实现(must-have)” 和 “如果有会更好(nice-to-have)” 两部分,将后者移到后续的迭代中去,并确认前者是否能赶上 DDL

(在做了这些调整之后)如果计划还是太赶,你还有其他问题可以确认:比如 “我们是否还可以增加项目人手?” 以及 “是否有一大部分(工作)范围可以削减,之后依然能实现(令用户)满意的交付水准?”

译者:对 leader 来说,还应该注重的点是备用方案的制定。需求在实现过程中不可能所有事都一帆风顺,对中间环节可能遇到的问题,leader 应该要有准备意识,对各种情况都有一套备用方案,保证需求能够按时交付

有时取消项目是正确的选择(即便是让人感到不舒服)

我讨厌(取消项目)这件事,但长远来看,对项目和组织来说它确实可能是最健康的选择。特别是在项目获得支持、准备正式上线之前,却因为团队成员要解散,而最终不得不停止之前做这个(取消项目的)决定,(提前取消项目)是尤其正确的。如果大家想知道,建议阅读 《Killed by Google》[28],这篇文章旨在尽量减少因为大环境问题,导致需要裁减项目的情况。最近我就停止了一个经营了 好几年的项目,感到很艰难

什么时候会出现需要停止项目的情况?你可以决定投资一个在当时看起来方向正确的新项目,各种事情看起来都完美契合(市场需求、公司投入、人力投入承诺等),使得整个项目也是完全有价值有意义的。但一年之后,市场、领导层、项目的重要性等环境因素,可能就变了。定期检视 项目成立初期的假设,随着项目的发展,是否依然成立 (对保障项目稳定)很关键

当你越能为你的假设支撑起更多的信心时,你就越有机会让项目成功启动,并继续获得支持。有很多原因 让停止项目很艰难,包括参与项目的同事们,已经投入了真心实意的情感,希望能看到项目成功落地。作为leader,将被解散团队的成员引导到其他已经成功落地的项目 也是一个艰难的选择,因此让他们重新感觉到 内心的安全、信任和幸福 是很重要的。从客户角度来说,(作为leader)也需要留意 用户的信任度,你需要认识到你的长期决策 会如何影响到用户感受

关于技术债:预防远远 > 补救

Titus Winters[29] (Google c++ 代码负责人) 将技术债定义为“系统(效果)和代码之间的差距,在当下的情况 vs 我们预期的情况”(译者:这里提到的“差距”,其实就是需要“补救”的工作,在项目起步阶段容易被忽略的事情,比如单元测试、调试工具、故障处理机制等)。这些差距会有具体的体现,并且会比其他债务的影响更深。技术债有的来自早期没有出现的软件异常(疏忽),有的来自事后发现(后见之明),还有的来自技术的变化(环境因素)

持续优先应对技术债还是很难的,因为你不是总能将还没出现的bug 或者 还没发生的 服务故障 量化,因为你还没“还清足够的技术债”。因此 保持住团队对 修补技术债 这种事情的兴趣,并在评估绩效的时候(适当)奖励这种事项,是很重要的。问题随着时间的积累,“补救”的成本也会越来越大,就像解决污染问题一样,因此对技术债的预防,永远是比在之后再进行补救的成本更低

那么,我们该怎么避免技术债(过度)积累呢?技术 leader 应该在迭代中,除了新功能的需求之外,也定期安排 整理和“弥补”技术债的工作。检视者需要意识到,(过于)追求短期成效,可能会在之后导致问题。管理者和董事会也应该特别小心 用新项目替换(覆盖)已存在项目。除非权衡利弊之后,觉得替换值得的(比如需要对比:解决当前项目技术债是不值得的 vs 构建新的项目)。另外,监控项目的健康状态,是在这里讨论如何解决技术债的 基础

如果没有充足的休息,和 work-life balance(的习惯),你的团队将会产生职业倦怠

Burnout职业倦怠[30])是一种 由于压力没有被成功管理好,而导致 精力耗尽的状态。我见过很多程序员,在大环境导致的工作压力下,产生职业倦怠。在科技领域,这种情况总是会出现。最近我采访(同事)会按 1:1 的比例问两个问题:“你的压力等级现在怎么样?”、“我可以怎么帮助你?”

我对职业倦怠的体验是:这种感觉来得不知不觉,又很难消散。你会慢慢地感觉能量开始变少,失去动力,甚至还要继续尽力应付工作压力。你开始怀疑自己出现了什么问题,但没有意识到,你的身体已经在过度工作,来弥补能量的不足。你还会继续让自己工作强度越来越大,但最终会发现(身体)已经没有多少可以付出的了

大概5年前,我经历过这种职业倦怠,不过我感到欣慰的是现在走出来了。是什么让我走出来的呢?有很多因素。(职业生涯)前几年,我把工作放在第一位,工作时间越来越长,并总是说做得还不够。从来没有进行足够的休息的假期。晚上平均只睡5个小时。到家之后,我已经是“低能量”的状态了,没有给家庭足够多的陪伴
所谓的“修正”,就是做和这些相反的事:工作之余多休息、晚上多睡觉、在工作时间内挤出更多价值(即 提升工作效率),更好地委派(工作),并有一个明确的“非工作”时间

对主管来说,为了避免下属产生职业倦怠,我们应该鼓励团队成员多用上假期时间,获得休息,并定期(沟通)确认下属在有压力情况下,依然能顺利做好他们的工作

大型组织/公司中流程会比较缓慢

我和工程师们进行过很多对话,最后(主题)都可以归结为“为什么在大型组织中进行 X moon-shot(谷歌内部形容 “创新性的、难以实现的项目” ) 很困难?”Alex Komoroske[31](前谷歌产品经理) 对此有一个很好的比喻:黏菌[32](slime mold)。背后的意思是,即使是(在公司中)执行一件很小的工作,可能都会因为 协作阻力,比你理想中进展要慢很多。随着直接参与、或者合作参与项目的人变多,组织的系统、架构和内部动态 变得复杂,这种阻力就会变大

还有很多因素对这种阻力起着作用,包括对其他同事的工作事项复杂度的低估(比如:这些事情之间有依赖关系的时候),你不能忽略这些因素,因为它们会让系统故障(影响面)扩散开。解决这种阻碍的唯一方式就是尽可能地解耦[33],这样才能让(功能)能按正确的时间节点交付,最终收敛于目标需求

与其一开始就追踪所有的不确定(X)因素,你可以避免只关注“对月亮射击”(成功风险较大的努力)的问题,而更多地关注“对天花板射击”(完成每一步的风险更小)的问题,能让你更容易地接近目标。如果你遇到的问题和这个章节非常类似,非常建议你阅读 Alex 的 分享《Coordination Headwinds》[34] (PPT)

专注于 问题 VS 专注于 项目

想象你的用户有一个未解决的需求(比如 一个问题),当你是具体负责一个项目的工程师的时候,思考你的项目会如何解决这个问题是很正常的(局部最大值)。在一个拥有几个类似项目的大型组织中,很可能会看到工程师们独自思考“我的项目如何解决这个问题”。如果你是一批项目的管理者,(这种解决问题的思考方式)就不是那么清晰了。如果你的用户表示希望用到你们好几个产品的时候呢?如果每个项目都独立地按几乎相同的思路,去解决问题,不会觉得很奇怪吗?相反,你真正想提的问题可能是 “什么是解决这个问题 端到端 的方案?”,并探索需要如何对多个项目进行修改/升级,才能够全面地解决用户需求。这种方式可能需要参与了多个相关项目的开发者,进行更深入的合作。(虽然人力成本会提升,然而)这种方式能最终给你的用户一个更清晰、更全面的解决方案(场景故事)

译者:作者的出发点主要是在有多个成熟方案的基础上,保留最优解。但在项目还处于探索阶段,需要跟紧开源社区、竞争对手的时候,产品之间出现重叠并不算大问题,甚至公司还会有意保留产品功能类似的团队,促进竞争

作者总结

Brian Staufenbiel(Opera Parallèle 的创意总监和设计师) - “多和专家在一起(共事),多和那些在特定领域有专长的同事一起工作”

(将时间)投资于 那些 能够让你学到东西的同事的关系和友谊上,对他们的指导、领导和成功保持开放态度。永远不要羞于提出问题或者咨询意见。在很多情况下,(你离正解)只是一个问题的差距。

不管在什么阶段,对技术、商业领域和 人脉资源 技能的掌控(能力) 都是需要持续培养的。一个企业不可能期待 从别的企业招来的 高级别人才,从第一天就能非常适应公司并高效工作。如果你是一个优秀的工程师,你将会对公司的成长也有所帮助。作为回报,你也会获得一些新的途径,它们将指引你 继续吸收新的技术,不断成长

最后,感谢 Leena Sohoni, Joshua Cruz, Kara Erickson, Jeff Posnick, Houssein Djirdeh and Sriram Krishnan 对本文积极的帮助和贡献

资料

[1] Addy Osmani

[2] 作者博客首页

[3] 通用技巧

[4] 第一原则

[5] 批判性思考是通用技能吗?

[6] The value of fundamentals in Software Engineering

[7] Why learning the fundamentals matters

[8] Learn the fundamentals of a good developer mindset

[9] FOMO

[10] T型工程师

[11] Why Bad Software Happens to Good People

[12] YAGNI

[13] Do the simplest thing that could possibly work

[14] 不要过度设计

[15] 抽象原则

[16] AHA

[17] Deep Module

[18] 快速失败

[19] The Definition of Done

[20] Help Your Team Stop Overcommitting by Empowering Them to Say No

[21] Strong opinions weakly held

[22] Imposter syndrome

[23] 来源

[24] collaboration overload

[25] Deep Work: Rules for Focused Success in a Distracted World

[26] It doesn’t have to be crazy at work

[27] 压力对身体带来的影响

[28] Killed by Google

[29] Titus Winters

[30] 职业倦怠

[31] Alex Komoroske

[32] 黏菌

[33] 解耦

[34] Coordination Headwinds