翻译-软件工程师的通用技巧

文章目录

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

前言

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

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

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

所有章节一览

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

学习新知识

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

精通

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

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

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

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

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

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

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

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

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

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

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

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

扩展阅读: 批判性思考是通用技能吗[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.”
“你需要从用户体验开始,再回归到技术中。你不能先基于(选择)技术,再尝试去找到哪里可以卖出你的产品”

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

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

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

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

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

提升自己的能力

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

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

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

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

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

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

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

保持好奇心,保持学习

经常做笔记

写下所学的东西,能帮助你更好的理解知识点。有的时候只有你尝试把自己所了解的知识讲给别人听,才能真正把你不懂的点弄清楚
如果你写的东西(博客)没人看,那也没关系。做笔记主要还是为了自己,(只是记下)你已经从中收获很多了
学习应该是一个持续坚持的事 – 那些 称自己对特定领域无所不知的人通常都不是真正的专家。真正的专家精通一些技术,但他们能够意识到,总会有(继续)学习和改进的地方。好奇心驱动学习 – 所以如果你对一个新框架感兴趣,那就去谷歌它、阅读它的文档、尝试新手教程、以及阅读源码!学习并不只是出现在教室中,学习可以在任何地方、任何时候发生。每天花半个小时阅读一本书的一小章节,听一次技术广播,阅读技术博客,学一门新的编程语言等

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

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

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

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

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

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

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

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

技术的广度和宽度

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

你应该掌握的一个很重要的技能,就是学习 如何学习 的方法。这比你怎么说更重要,(你需要做的)只是深入到编程语言或者框架的底层。另外这也有助于保持好奇心。一旦你经历了这种学习方式,你可能就会提出刚刚说的问题:是成为一个领域的专才,还是成为全栈的多面手(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)称赞他人

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

学会说“不”

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

你不可能让所有人感到满意:不管是说 “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 时候的思路。分享如何解决问题的技巧,而不仅仅是答案

组织层面的指导

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

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

学员的职责

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

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

高效的团队

构建信任

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

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

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

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年10月5日
下一篇 2022年10月5日

相关推荐