下面的内容是我在作为一名程序员入职之前阅读的由Gergely Orosz写的The Software Engineer’s Guidebook。我将将阅读时得到的重要的信息总结成中文以供大家分享。
高级软件工程师的工作负荷与初级职位相比,有着明显的区别。他们通常需要处理更多的入站请求、频繁的上下文切换,以及更为复杂的工作内容。
要成为一名被视为”能够完成任务”的工程师,不仅仅局限于第二部分中讨论的”如何完成任务”。当然,该部分提到的许多方法在这里同样适用,例如:
你认为你的经理会如何描述你和你的同事中谁是”能够把事情做好”的工程师?是你自己,还是那个看似轻松自在的同事?
对你来说,你可能清楚地知道自己在完成工作,但你的经理能看到多少?如果你在沟通工作方面做得不好,而你的同事在这方面很擅长,那么很可能你的经理会认为他们更善于完成工作。
“把事情做好”的要求可能与通过解决难题来完成工作的过程不同。你的经理看不到你为了在重要项目的截止日期前完成工作所做的努力,比如你采取的步骤来追踪和修复棘手的bug,或者你使用的创造性变通方法和捷径。有时,没有知识渊博的同事可以配对观察和协助你的努力,所以你独自工作以完成任务。
要被视为一个能把事情做好的高级工程师,需要两个条件:
随着资历的增加,沟通你的工作变得越来越重要。不要假设你的同事或经理理解你的工作中什么是”容易”或”困难”的。相反,在状态更新、一对一讨论和团队会议中明确表达这些内容。例如,如果你解决了一个复杂的问题,在每周会议上告诉你的团队:
"上周,在进行迁移脚本的进一步验证时,我发现约2%用户的支付请求的影子输出与预期不符。这些差异主要出现在巴西的货币转换中。如果我们直接推出这个变更,就会导致那里的客户被多收费。
在调查差异原因时,发现新的货币转换系统漏掉了几个国家,包括巴西。我与负责该系统的团队合作,添加了这些国家,并帮助他们设置了警报,以防出现未设置转换的货币请求。我相信这项工作将大大提高新服务的可靠性。
虽然新的货币服务不是我们团队负责的,但我还是用Go语言帮助实现了这个变更,并审核了该团队的代码。变更完成后,我编写了两个集成测试来验证这个功能。
通过多花一两天时间,我们现在有了一个安全网 - 包括单元测试和两个集成测试,同时也帮助新的货币服务变得比以前更可靠。
我一直在监控影子系统和生产系统,现在已经没有输出差异了:在过去4天里,我们的响应100%一致。"
这个描述比原来的更加详细和具体,清楚地解释了工作内容、遇到的挑战、解决方案以及最终结果。它展示了你的专业能力,以及你如何超出预期地完成任务。
关于"少承诺,多交付,多沟通"的建议也很重要。要善于判断自己能确保完成的工作量,避免过度承诺。同时,当你超出预期完成任务时,别忘了告诉同事和经理。这不是炫耀,而是让他们知道你付出了额外的努力。例如,在完成项目并构建了一个可能在将来有用的工具时,你可以这样说:
"我已经完成了PayPal集成。我还创建了一个可能在将来有用的工具。"
"我在上周完成了PayPal集成,符合之前一周的估计时间。然而,在开发过程中,我发现自己花费了太多时间手动测试功能是否正常,这让我思考:'我们能否将部分测试自动化?'
因此,我开发了一个简单的脚本,使用UI自动化来验证支付方式是否有效。最初是为PayPal开发的,实际上这加快了开发速度,因为测试变得更加容易。现在我们有了这个工具,很容易就能修改它来测试其他类型的支付方式,比如银行卡。我已经创建了一个wiki页面,详细说明了如何使用这个工具以及如何修改它。"
软件开发过程中经常会遇到意外问题,例如库不能按预期工作、需要长时间修复的奇怪bug、突然出现的新依赖项阻碍进展等等。
被认为不可靠的工程师通常不会沟通新出现的障碍。相反,他们试图自己解决问题,但往往进展缓慢,直到其他工程师介入帮助才能取得进展。
相比之下,高效的工程师善于自我解困(正如第二部分”完成工作”中所讨论的),同时也能识别可能延误项目的障碍。
当意外工作出现时,应与团队、经理和项目负责人分享这一情况。但不要只是分享障碍,还要提供其他可能的替代方案,而不是简单地推迟工作。例如:
要在提供替代方案时发挥创意。通过强迫自己考虑各种选择,你可能会找到更聪明、更快速的解决方法。
高级工程师通常会收到大量的各种请求,例如:
作为高级工程师,如何妥善处理这些源源不断的请求,是一项重要的能力。这不仅关系到个人工作效率,也影响团队整体的运转。合理安排时间、设定优先级、学会适度拒绝,都是应对这种情况的有效方法。同时,培养和指导其他工程师也能帮助分担一些工作。高效处理各种请求既是一种挑战,也是展现领导力和影响力的机会。
这些都是合理的请求,你的经验对此很有帮助。然而,它们也可能分散你对更重要工作的注意力。
来自他人的请求和需求总是源源不断。随着时间推移,这些请求的数量可能会变得令人不知所措。虽然没有一种最佳的应对方法,但以下是一些经验丰富的工程师成功使用的策略:
根据任务的紧急程度和重要性,我们可以将任务分为四类,并采取不同的处理方式:
对于重要但不紧急的工作,创建一个记录系统很有必要。你可以尝试以下方法:
尝试找出最适合你的方法,不要害怕改变。
对于不重要的事情,学会说”不”。你可以用以下方式礼貌地拒绝:
• “我很想帮忙,但很遗憾我必须完成最高优先级的工作,所以无法参与。”
• “很抱歉,我已经有太多工作要做,无法接受这个任务。如果你有正在进行的项目列表,最好展示一下。
通过合理安排任务优先级,你可以更有效地管理时间和精力,专注于真正重要的工作。
工程师应该学会适时清理待办事项清单。许多工程师在清除”不紧急但重要”的任务时会感到挫败,但我建议将这种做法视为一种 重置 的方式。
实际上,对你来说重要的事情会随时间变化。你创建的任何重要工作清单最终都会过时。当这种情况发生时,你有两个选择:
第二种方法更快,它迫使你通过只记录最重要的任务来重新确定工作的优先级。它还能减少对其他任务的压力,并减轻未来的心理负担。只是不要忘记通知那些请求未能进入你新的精简清单的相关同事。
要知道感到不知所措是正常的。高级及以上工程师常见的抱怨是,无论采取哪种方法,他们最终都会感到工作负荷过重,没有足够的时间做”重要”的工作。这种情况很普遍。如果你遇到这种情况,以下几点可能会有所帮助:
当事情完成时,要确保它是真正完成的。有些软件工程师能够”正确地”完成工作,这是值得一提的。有很多工程师看似能快速完成工作,但后来发现他们发布的代码存在问题,如bug、未覆盖的边缘情况,或匆忙拼凑的用户体验。
被认为高效的工程师并不一定是完成工作最快的,但他们的工作速度足够快,而且最关键的是,最终结果能如预期般运作。
问问自己以下几点是否适用于你的工作:
很少有工程师能够做到以上几点都不适用。这是因为快速行动、部署到生产环境,然后在需要时修复问题是很自然的做法。由于许多人都是这样操作的,那些不会将问题部署到生产环境,并且能够很好地意识到边缘情况并在代码进入生产环境之前解决这些问题的工程师就会更加突出。
那么,如何成为一个能够正确完成工作,并且工作成果能得到同事和利益相关者信任的工程师呢?以下是一些方法:
制定详细的产品规格说明书对于软件开发至关重要。许多产品缺陷源于利益相关者的期望与工程师实际开发内容之间的误解。为避免这种情况,我们应该坚持制定一份描述功能工作原理、边界情况以及范围界定的规格说明书。在实施阶段之前,与产品经理和业务相关人员充分沟通,明确所有细节。
在完全理解产品和客户的需求之前,不要轻易开始工作。将讨论结果以书面形式记录下来,以避免误解。规格说明书不必冗长,也不一定要由产品经理编写。如果没有现成的规格说明,可以与产品或业务人员讨论功能的预期工作方式,用一两页的要点总结,然后让他们确认。这个简短的过程可能会节省数天的工作时间。向产品人员展示书面规格时,他们很可能会指出错误、遗漏的细节或边界情况。
在开始实施非平凡功能之前,先做好规划并草拟你的方法,例如要创建和修改哪些组件,如何修改架构,不同方法的权衡以及你的选择。
你将如何测试实施的功能是否按预期工作?有哪些手动测试用例?哪些部分将通过单元测试、集成测试或端到端测试来自动化?哪些部分只能在生产环境中测试,在功能宣布就绪之前如何进行测试?
许多工程师跳过前期的测试规划,因为直接进入实施阶段更令人兴奋和有动力。然而,考虑如何测试和测试什么的最佳时机是在规划阶段,而不是在实施过程中被带偏。
当你有了测试计划后,与产品经理、业务相关人员、其他工程师或质量保证人员分享,征求反馈。你会惊讶于他们指出的被遗漏的边界情况或建议的替代测试方法!
将测试、监控和警报作为估算的一部分。在处理较大的代码库或构建可能对业务产生严重影响的产品功能时,测试和监控应该是"正确完成工作"的一部分。
然而,许多工程师忘记为功能添加自动化测试和监控/警报,或者在估算时没有将这部分工作考虑在内。将这部分工作视为单独的问题在于,产品人员和业务相关人员往往想跳过它,因为他们认为这是节省时间和加快进度的机会。
正确完成工作与确保你的工作在生产环境中得到测试和监控之间存在联系。跳过测试和监控,你的工作将变得不可靠。因此,不要对这部分工作进行协商;直接去做。
不要将工作"扔给"质量保证(QA)团队。如果你有幸在工作场所有专门的质量保证人员/团队,不要简单地将你的工作"扔给"他们。我观察到的一个反模式是,一些与QA人员合作的工程团队倾向于认为测试和质量保证完全是QA团队的责任。因此,他们倾向于构建功能然后将其传递给测试 - 将其扔过栅栏 - 而不考虑边界情况或如何测试,也不进行简单的手动测试。
毫不奇怪,这意味着事情需要更长的时间。QA发现明显的问题 - 任何工程师通过基本测试就能发现的问题 - 并将其发回给工程师,工程师修复这些问题,然后再次交给QA。然后QA发现更微妙的bug,这些bug可能逃过了工程师的注意,并将它们交回修复。最后,在工程师解决这些问题后,QA进行第三轮测试,宣布功能按预期工作。
从一开始就让QA人员参与规划,并与他们一起制定测试计划。QA工程师往往对特殊的边界情况和难以捕捉的问题有很好的感觉。
要善于从bug中学习,理解它们如何”压力测试”系统,并利用这些知识来制定更完善的测试计划。不要简单地把工作”扔给”QA团队,而应该与他们并肩工作,避免在等待测试结果时闲置。
同时,不要把QA视为理所当然。许多工程团队没有专门的QA人员。如果你有机会与QA合作,要充分利用这个机会学习,提升自己的QA技能。在未来的工作中,你可能需要自己承担QA的职责,掌握这些技能将帮助你交付更高质量的成果。
衡量你的工作效率:从构思到原型展示,从发现bug到修复上线,通常需要多长时间?如果答案是几周而不是几小时或几天,那么你可能不被视为高效的工程师。最好的情况下,你可能被认为是”慢而稳定”的;最坏的情况下,可能只剩下”慢”了。
高效的软件工程师几乎每天都能发布代码。这种情况在小公司和大公司都存在。以Google为例,平均每个工程师每天会有两次代码变更发布到生产环境。
要实现如此频繁的发布,关键在于短周期迭代:
鼓励团队成员也采用这种方式工作。小的变更意味着不会在单个代码审查上耗费太长时间。
虽然快速迭代通常是一种好方法,但并非适用于所有情况。以下是一些需要长期投入的任务例子:
长期任务通常是一系列短期迭代的集合,工程师决定不为每个迭代创建单独的PR。可能是因为在这些迭代中,产品的某些部分被刻意破坏,或者工程师认为短期迭代会打断他们的工作流。无论出于何种原因,这种工作方式总是有其道理的。
长期任务意味着较少的反馈:
长期任务适用于不需要反馈的情况,如创建新公司、新产品或验证概念的原型。然而,大多数涉及团队合作、咨询产品人员、业务相关方或客户的情况都需要反馈。
作为高级工程师,你的关注点通常在项目层面。确保你理解整个项目需要完成的工作,并将其分解到必要的程度。这项工作与技术主管的职责有重叠,我们在第四部分”务实的技术主管”中会深入探讨这方面的方法。
为他人编写文档是一项重要技能。当向同事解释某事时,考虑记录下关键信息,这样下次有人询问时,你可以直接指向这些笔记或图表。如果你的团队已经有wiki或内部知识库,就往里面添加文档。如果还没有,那就创建一个并带头添加内容。我们在第三部分”软件工程”中会详细讨论文档编写。
解决团队的阻碍也是高级工程师的重要职责。 你应该能够发现同事遇到的障碍并帮助他们解决。可以通过结对编程等方式提供帮助。在解决问题时,要避免直接给出答案,而是通过引导性问题帮助他们学会自己解决问题。对于外部阻碍,可以主动介入并解决,同时向团队成员解释处理流程。这不仅能解决问题,还能建立良好的跨团队关系。
“跳出框框”思考是富有成效的工程师的重要特质。 例如,Uber的移动平台团队发现Android应用内存泄漏问题日益严重,但逐个修复很困难。一名工程师提议将修复内存泄漏变成一场比赛,同时教育工程师如何发现、修复和避免内存泄漏。这个创新方法不仅解决了问题,还提高了整个团队的技能。
要提高”跳出框框”的思考能力,可以尝试以下方法:
最富有成效的工程师不一定是编码最快或最了解计算机系统的人,而是那些工程能力足够好,同时对产品、客户和业务有深刻理解的人。要成为这样的工程师,可以考虑以下方法:
作为软件工程师,我们的工作不仅仅是写代码,更重要的是为企业解决问题。要理解企业关心什么,以及你开发的软件如何帮助公司实现业务目标。我们在第五部分”理解业务”中会详细讨论这个主题。