其范围包括学习方式,思维路径,横向管理,团队建设和新人指导等多项内容。
由于文中所诠释的均为通用技能,因此对于其他非技术类岗位,也有借鉴意义。
原文请见:AddyOsmani.com – Software Engineering – The Soft Parts
成为一个好的程序员的过程可以认为就是在职业生涯中不断收集经验的过程。每一个项目,无论多小,都是一个增加新技能、学习新工具的好机会。如果能够把在不同项目中学会的新技能结合起来解决新问题,将会收获更多。
在开始之前,请容我赘言:我的经验只做参考,您的方式也可采纳。
学习新事物
以下列出的几点应该会帮助大多数初级或者中级程序员,在遵循软件工程标准范式的同时,发展出新的最佳实践,包括应对技术更新,构建复杂的系统等。第一时间应用第一性原理。学习对问题进行分解也是生活中最重要的技能之一。
掌握
技术能力的掌握,意味着在同样工作时间之内攫取更多的价值
对于技术的掌握意味着你能够辨别哪些工作是具有更高价值的,并且有能力帮助你的团队将精力集中于有价值的方向。反过来说,你能够分辨出哪些工作并不能给团队/公司带来价值 — 最好的工程师甚至可以引导整个团队避开那些没什么用处的工作。
经常有人会问到这样的问题:我如何判断我的时间真正做到物尽其用?毕竟在工作中总有各种任务让你填满时间,从而“感觉”忙到不可开交。这没有什么技巧,唯一能做到的是确保你正在做对的事情。如果你要愚公移山,那么就要聚焦于如何移动一块碎石,即便相对于山来说它是那么微不足道。
可以时常问问自己这些问题:
即便只是内省,也会产生巨大的能量。
批判性思考,并提出合理的论点
批判性思考是使用认知能力进行独立思考的能力,以便能够得出合理的决定。磨练这一能力会让思维变得更加清晰。
作为程序员,我们可能经常会迫不及待地冲入解决问题的细节中,这让我们显得比较有进展或者让其他利益相关者能感受到我们的积极态度。但如果在动手之前没有完全考虑清楚问题的原因和相应的结果,这种行为反而会引入新的风险。换句话说,批判性思考即应首先对目的进行思考,然后形成自己的结论。这种目标导向的思考方式有助于把精力集中在分析根因上,而不是不顾原因和结果的莽撞实操——这也许会在未来带来隐患。
概括来讲,我经常使用的批判性思考的提问如下:
这些问题经常会帮助到我们。有时,我们可能修正了解决方案中的一个问题,随后却会有其他问题陆续蹦出来;有时,我们可能会很迅速地交付一个解决方案,但随后却发现解决方案引入了更多的问题。在批判性思维的显微镜之下,我们可以对假设发起挑战,近距离观察风险与收益,寻找反证的论据,评估可信度,以及查找更多的数据来佐证我们当前方向的正确性。
比如一个常见的错误就是,一些工程师会想当然地假设相关就意味着因果(相关不蕴含因果)。批判性思考的人则会后退一步至那个假设:为什么我们认为这个假设是真的。
批判性思考者:
构建强大的基础
掌握基础能力,然后不断的应用它们,以便获得新的技能。
学习基础能力的长期价值在于它们是可以转移的。短期价值在于足以让你做出更好的决定,以及让编码工作更高效。
可转移技能
可转移技能是指其可以在不同项目之间通用的能力。接下来我们谈谈可转移技能与基础能力之间的关系。
基础能力是每一个软件工程师职业生涯的基石,可以分为两个层次——宏观层面和微观层面。宏观层面是软件工程的核心,微观层面则是具体实现(诸如技术栈,库,框架等)。
在宏观层面上,关于编程的概念,其中大部分都不受具体语言的桎梏,是可以转移的。语法可能有所不同,但核心理念总是一样的。包括数据结构(数组,对象,模块,哈希),算法(搜索,排序),架构(设计模式,状态管理)以及性能优化(贪心求值 VS 惰性求值,记忆化,缓存,懒加载等)。这些概念会在工作中频繁出现,所以知其然并知其所以然,会大有裨益。
在微观层面,则是学习对这些概念的实现。这包括:使用的编程语言(Javascript, Python, Ruby等),使用的框架(React,Angular,Vue等),使用的后端(Django,Rails等),以及使用的技术栈(Google App Engine,Google Cloud Platform,AWS,Azure,Aliyun等)。在这些领域中各具有价值的细节可供钻研,但一般不具备转移性。
通过学习基础能力,掌握技能和工具,然后忽略基础,最后成长
这是指,在实际中没有人在职业生涯的初期能够学尽所有再开展工作。所以总有一个节点,不再继续过度追求完备的基础知识,转而学习用于为真实世界构建应用的具体本领。也就是所说的,该开始在干中学了。
效率
对于基础知识理解得越深入,越有可能写出高效的代码。所谓高效包括很多概念,比如说时间复杂度(运行代码的时间),内存占用,以及在性能与代码可读性之间的权衡取舍。在构建任何大型应用的过程中,这些理念都有助于做出如何权衡的决策。运行速度在现代应用中占据非常重要的地位,流畅与否会显著影响终端用户的使用体验。
更佳的决策
对于宏观和微观基础知识的良好认知有助于做出更佳决策
站在坚实的基础知识之上,在任何项目中,当面对给定目标和约束条件时,你足以胸有成竹地做出更好决策,诸如使用或避免使用什么样的技术。具体来说,这些知识可以帮助避免选择错误的技术或者工具。
“当你不知道一个工具在什么时候不应该使用时,那说明你还没有掌握这项工具”
-@kelseyhightower
软件工程师涉及很多不同层面的思考 – 核心编程语言,实现,基础架构,工具,以及团队。仅仅在表层对这些问题有所了解绝对会让开发走的更快。但只有真正对于基础知识(包括O(n)时间复杂度)的理解才能让开发走的更远,尤其是在编程语言和框架演进越来越快的当下。
相关阅读:
专注于用户,剩下的问题自会解决
从用户体验入手,再回到技术层面寻找解决方案
Steve Jobs曾说过一句名言:“必须要从顾客的体验出发,然后回头寻找能够解决问题的技术。而不是从技术出发,再想办法弄清楚去哪兜售。”
作为工程师,太容易从使用特定的技术方案展开工作了——可能是因为技术的流行性,或者开发者体验,甚至仅仅是个人喜好——然后再尝试为技术方案寻找合理性。恰恰相反,我们更应该专注于为谁创建产品,他们有什么问题,现有的方案不能满足他们的原因是什么。
优秀的用户体验来自于两个视角的结合——用户和技术。向人们展示你认为他们需要的东西,然后仔细倾听他们的反馈。当然这个问题的答案会受大量因素的影响产生各种细微差别——工程师选择什么样的技术能够在移动设备上为用户带来优秀的用户体验?哪些选择会对开发效率造成影响?或者对负载扩容有什么影响?甚至对招聘有什么影响?但最终,我们会获益于对用户优先的不懈专注,并以此指导我们在客观约束下应该采取什么方式满足用户的需求。
最好的软件是由对用户有同理心的工程师构建出来的
商业的成功取决于用户的满意,在软件开发行业则意味着用户体验。从这点出发,要明白用户是如何使用我们提供的产品或者服务的。确保我们的解决方案没有妨碍用户高效地完成自己的工作。如果你所在的位置能够直接与终端用户接触,尽可以尝试去弄明白用户的需求和痛点。
升级你的技能
根据用户做正确的选择,而不要追求时髦
选择“无聊”的技术(当然是要经过测试的)而放弃超音速列车,这没问题。语言,框架和库每天都在升级。但我们应该确保的是选择了能够保证交付最终产品的技术。当一个全新项目开启之初,从无聊的技术方案开始(但需要你已经对它了然于胸),然后在每次碰到特定问题时,有目的性地选择最佳工具。
回归技术层面也是一样,每当我们选择学习或者使用一个新技术的时候,即使选择的不是最近的技术也不用担心。FOMO(错失恐惧症)在技术领域不一定是好事。这一判断放在语言,框架,库或者工具上也是一样的。尽管技术选型非常重要,但你的主线目标仍然是向用户交付出色的最终产品。所以从这个意义上来说,如果不能给产品带来附加价值,那么就没有必要刻意追求最前沿的技术。同样的,也不应因为某项技术已经不再是热点了就特意回避。
利用新项目来学习新技术
与此同时,个人项目或者黑客马拉松项目倒是学习新技术的大好机会。在工作中大多数人都没有什么机会从零开始一个全新的项目,通常都是在一个业已存在的代码库中做着墨守陈规的日常工作。而在新项目中研究、使用新技术,小范围地评估它的强项和弱点,并在使用中得到一手的评测结果,一则对个人的未来很有价值,另外也没有什么风险。
保持好奇,学习不止
写下你学到的知识。这会促使你对问题理解的更加透彻。有时候脑子里知识的模糊地带只有在向别人解释的过程中才变得越来越清晰。没有点击量也没有关系,仅仅因为写下来而得到的收获已经值回票价。
学习是一个持续的进程——那些 称自己对某一个特定技术了如指掌的人,大概率到不了专家级别。真正的专家,是那些即便已熟谙某种技术但仍然明白还有进步的空间的人。好奇心是学习的源动力——如果你对某个框架产生了好奇心,接下来就去搜索它的官 ,阅读他的文档,跟着教程边玩边想,甚至打开源代码看看。学习不是非得在教室里,在任何地方任何时间都可以。每天花半个小时阅读一章教科书的内容,或者听半个小时科技类的Podcast,阅读开发类的博客或者学习一门新的编程语言。
作为Leader敢于承认自己有不了解的东西
有足够的自信心承认自己有些东西并不了解,能够降低他人对于资深工程师必须了解所有事情的期望值。即便是资深工程师也绝对没有必要知道所有事情,但能够承认这点,同时承诺与团队一起想办法找到解决问题的方法才是重要的。
作为Leader也要敢于承认错误
作为Leader一个重要的任务是要带领团队成员学习如何以谦逊、渴望学习和进步的精神来应对错误。这个世界不完美,所以要让团队内的所有人能够理解这种不完美,但我们应该做好准备。
作为团队的守护者,而不是团队的拥有者
通常在一个开源项目的早期阶段,容易把自己定位为一个拥有者。经常是开源项目的发起人自己评判功能的价值,开发新的特性,处理技术问题,以及运营 区。这种做法适用于产品推广阶段,但恐怕在后期有人员变动或者自身时间无法保证时就不是个好方法了。
在经历过一次这样的捉襟见肘之后,另外一种应对方法是把自己的定位转换为团队的守护者,而不是团队的拥有者。一个守护者的角色会想办法淡出舞台。通过与其他维护者,贡献者以及整个 区共享知识(比如设计文档,代码评审以及其他的知识共享最佳实践)可以做到这一点。这也有助于让其他人成长为了解足够背景知识的评审人,即便当你无法再参与了,项目也仍然会正常发展。
如果希望一个项目在多年以后仍然保有活力,这一点必须做到。
技能的深度和广度
更想当一个万金油还是领域大师
能够掌握的最伟大的技能之一是学习如何去学习。它的优先级我想不用赘述,例如相比于仅仅钻研一个特定的编程语言或者框架。这能让你保持好奇。一旦当你已经具备了这方面的经验,你会想问问自己应该成为一个专家还是万事通。
我个人很喜欢T型人才的理念。这是指在某个或者某几个领域(T字的竖线)作为深度专家,同时对研发产品所涉及的众多领域都具备基本知识和技能的人才。有一些团队喜欢在团队内部不同岗位之间进行人员轮转,以便培养更多的T型人才。
我发现在一些中等大小的团队中,如果其中有这种同时具备专业知识和多种其他领域技能的成员时运转会非常有效,因为这样的人才具备技术能力、多样性和适应性,能够在必要时对其他岗位进行补位。
体验就是学习
当学习一门新语言时,侧重于制作一些有形的东西,这样可以让你获得一手的经验
如果要学习一门新的语言,不是要记住所有的语法或者文档内容才能成为一个好的开发者,更重要的是学会如何用它解决问题。通过用新语言写相关代码或者学习已有的项目代码来积累经验,会让你有效掌握新语言。正如这篇文章所说:“软件的主要价值不在于编写的代码本身,而是制作软件的人所积累的知识”。但是,可不要在生产环境来实验新技术。
技术复杂度
通用和专用代码
先编写为了解决特定问题的代码,然后尝试改进一些地方让它变得更通用
我们经常会尝试把代码写的尽量通用,但最终结果却产出了一滩稀泥,它们什么也干不好。相反,先从解决特定问题开始,然后尝试在其中找出一些地方进行修改让它稍微更通用一点,反而减少了我日后重构的次数。
关于设计复杂度有几条常见原则,而在编程领域,则有下面这两条:
这两个原则的目的都是为了防止过度设计。然而这些原则也会被滥用,使得整个项目最终变成若干个不能很好整合的简单方案。
在另一个极端我们看到抽象原则,即在任何可行的情况下,通过抽象和泛化减少代码中的重复结构。我倾向于站在极端抽象和极端简化的中间位置,对于代码我选择少量的泛化。AHA (避免仓促的抽象)原则提倡的是类似的想法。
深模块
为其他开发者编写解决复杂问题的代码,但提供简晰的接口
如果你是一位API设计或开发者,你的职责就是向其他开发者提供接口以简化背后的复杂功能。如果接口太难理解并且增加了使用者的成本,显然目的就未达成。深模块这个概念对此理念有所阐述 – “最好的模块是那些收益最大且成本最小的模块。由模块提供的收益是其功能,而成本是其接口。”
尽管人们总是想要简单的接口,但是有时候复杂的问题确实需要复杂的代码(这并不总是对的,但大部分时候是)。这种复杂度最好能嵌入在代码内部。对终端用户来说,当复杂功能被抽象成简单接口后,其价值就变得更高。
一个由多个可见的函数和可见类组成的API,相比于另一个具有同样功能,但仅由少量几个公开函数和类组成的API而言,显得更加复杂和难以掌握。新增的函数和类会同时增加类库使用者和维护者的成本。
从处于维护期的项目中学习
在维护老系统中的代码时,理解应该留下的代码和应该舍弃的代码之间的区别
任何资深的工程师都应该努力去理解应该留下的代码和应该舍弃的代码之间的区别。
理解他们之间的区别很重要。大型且已长期运行的生产系统总会携带一些坏的、或者是留存原因并不正当的代码。为了保持系统的健康,需要能够理解这些代码为什么还保留在这里(是正确的原因?还是不正确的原因?)。然后移除坏代码,留下好代码。
很多公司的工程师对于历史代码都会先假设这些代码不能动,或者这些代码原本好的设计初衷已经遗失在时间之沙中。这会导致人们害怕修改,只是不停地在沙子上垒石头。
软件行业已经到了需要很多人投入到维护或者迁移老系统的阶段了。如果你正在这样一个团队中,不要气馁。通过阅读旧代码会获得很多领域的知识。尽管老旧代码可能因为某些正当理由依然健在,但也不要假设老旧代码都是应该原样保留。
一些软件工程师因为害怕引入新bug所以对于老旧代码总是很警惕。于是他们会为新的用例引入条件分支然后重复一些逻辑代码。这种变通方法可能会在当时节省一些时间,但随着时间推移最终会变成维护代码的噩梦。不要认为老旧代码是得到保佑的、万无一失的。现实可能是这些代码在某些扩展性或效率方面有潜在问题,只是当时并没有被发现,这个可能性现在到你手上了。
在全新项目中学习
试验,创新,快速失败然后获得更强的解决能力
当你被指任到一个全新系统的开发工作时,学习的旅程会完全不一样。在你开始进行快速原型或者功能实现的迭代过程中,你会学到什么方式可行,什么方式不可行。敏捷方法论和快速失败原则帮助你使用尽可能少的资源就可以验证想法。利用这些方法论可以分解并战胜复杂的大问题。
完成的定义
提前对“完成”进行定义会节省时间,因为它能够帮助你预估所需投入,对开发进程进行计划,避免日后不必要的版本规划
另一个可以趁手地应对复杂度的敏捷原则是完成的定义。除了为满足用户需求进行的开发投入和验收之外,关于完成的定义还应包括Code Review,测试,以及文档等等。
滚动发布
应该尽可能把一次大型的发布分解成一系列风险更小,更易理解的滚动发布
滚动发布计划对于大型生产系统的发布节奏来说,其重要性几乎相当于架构设计之于代码。与迭代开发同步的分阶段发布可以让我们更好的掌控由大型变更带来的风险。除此之外对于复杂的大型变更发布,也可以根据开发和测试策略来制定发布策略。
系统性调试
进行调试时,应该尽可能从系统层面精准的解决问题,从而能够通过所有测试条件
调试时请务必阅读错误信息( 包括错误栈信息)。在这些信息中很可能有有价值的信息帮助你定位问题的真正所在。令人吃惊的是在工作中我发现有不少工程师甚至在调试之前根本没有阅读过错误信息究竟都说了些什么。碰到异常发生时,难道不应该认为机器在告诉你是什么地方出现了错误然后按图索骥的找到问题吗?为什么要认为不断做各种小修改然后一次又一次地重跑流程会更快的修复问题?如果代码抛出了异常信息但没人仔细去阅读,那就是在浪费时间。通常来说异常信息是代码到底哪里出了问题的重要提示。
设计文档
设计文档的重要性
设计文档不是事后诸葛,而应该贯穿于整个软件工程过程
设计文档无处不在,可以在团队成员协作时作为记录共识以及对接系统的工具。他人的反馈让你能够识别偏差并完善设计。设计文档还可以成为未来加入的新伙伴了解项目的有力帮手。在设计文档的帮助下,新伙伴会对设计之初的问题定义、设计取舍以及其他可替换的解决方案有所了解。设计文档中凝练了所有在项目中贡献过的记录。这也让他人能够迅速了解具体决策是由谁做出的、进行协作时应该联系谁。
文档的过程
在文档进化的过程中,需要对其组织评审,以便比较设计文档与原始文档之间的差别,验证当初的约束条件在新版本中是否依然能被满足
尽管设计文档可以由一个人完成,但实际的设计过程却发生在会议室中的白板上,夹杂在面对面的讨论中、聊天软件的对话中,或者email/电话中。只有当你把这些结论都落在纸上之后,才能发现结论中互相矛盾的地方、不同的部分是否协调一致。创建最初版本之后,应组织所有参与者进行一次评审,以保证所有人都拉齐理解。不过,最终实现的设计可能并不能与原始设计保持100%一致,因为在进程中总会发生一些变化。
沟通
谦虚,沟通明确,并且尊重他人。对他人保持善意没有什么成本,但影响却是无价的。可能有人会说良好沟通会消耗精力,还得费心替他人着想。但我们难道不应该抱有更多的同理心吗?
成为一个高效多产的工程师所要具备的软技能中,沟通是关键一环。沟通不畅会导致功能不正确、代码不协调,甚至团队氛围带有攻击性。沟通能让人们更好的理解需求的本质,并且防止问题升级。
外界对于程序员的一大误解就是认为他们每天的工作内容就是坐在那里写代码。然而,为了保证产品是有用的,我们需要与团队其他成员、业务人员以及用户的期待保持同步。这使得协作和沟通成为我们日常工作的砥柱。
初级开发者经常与团队其他成员、测试工程师和团队leader进行沟通,分享想法、讨论不同的解决方案。随着我们在职业生涯中不断成长,工作中必要的沟通也越来越多,email、会议、公开分享的数量都会同步增长。我们需要沟通的对象也越来越多,例如业务leader、其他部门经理、利益相关者以及团队成员。原因在于,你的工作内容越专业化,其他人越不容易理解你。
个性化沟通
因人而异地使用语言、概念和描述层次
无论我们自身对问题或现状的理解程度如何,当与他人探讨时,我们必须对使用的语言进行量体裁衣,才能让对方以最快的速度获得与他们自身相关的信息:
以上原则同样适用于写email或者做大型 告。内容应与接收信息的受众相关。在 告中你需要想办法捍卫自己的观点。因此,更应该对可能出现的疑问,以及相应的回答和遣词造句进行认真的准备。放任本能反应的回答,通常不利于进行有效沟通。
表现出善意和周到
与人为善是一种超能力 —— 利用这点
相比于冷漠,冷静、和善、乐于助人会让你走的更远。对团队内部的成员表现出善意能让整个团队更加强大和成功。但别忘了,对团队外部的人们也要如此。对于其他功能性团队(HR,财务,或者市场部门)也应表现出同等尊重,也许你无法直接为他们提供帮助,但总能更好的理解他人的工作,做到感同身受。当他人取得成绩时应不吝夸奖和祝贺。友善是会传染的。你能够友善对待的人,在未来也会向你的请求作出同样友善的回应。
慷慨地对他人的成就作出肯定
不仅仅当需要改善时给予反馈很重要,当一切顺利时,给予他人积极反馈也同样重要。这会让团队成员得到自身改变的正向反馈,并感到被人认可。
说不的权利
拒绝也比过度承诺好
当大量工作突如其来时,我们中的大多数都不很擅长拒绝。要么是因为我们不清楚拒绝也是其中一个选项,要么是因为我们喜欢挑战。然而由于可能会造成延迟,过度承诺可能是个麻烦。让他人明白你正在应对的事情,并且提供合理的预估工作量,是对他人判断力的尊重。这能给予他人一个考虑其他选项的机会——问问别人或者延长截止日期。合格的管理不会在明知会显著影响产品质量时,还仍然坚持按期交付。如果你是高级管理者,我建议你能够授权团队成员对不合理的想法说不。
资深开发人员(或者任何卓有成效的员工)都擅长拒绝。人们总会向你提出超出你时间安排的需求。遇到这种情况你尽可以温和但坚定地拒绝,或者向他们指出应该找寻其他什么人(代理),或者让他们与自己的经理讨论是否可以分配更多的时间来帮助他们。[1]
你无法取悦所有人 —— 所以准备接受或者拒绝时应思考地非常周全。
与拒绝相对应的,是leader总是接受任何事情,导致没能成功设置清晰的边界。承诺的工作范畴过多,而又不能仅以当前的资源合理执行,最终都会导致你的头疼,团队以及客户的胸口疼。这一点对于团队leader来说尤其需要揣摩,因为团队其他人会跟随你的标准来制定自己接受或者拒绝的边界。
接受和尊重
承认自己对某些事情不了解,以开放的心态寻求帮助,即便是向初级工程师
承认自己对于某些事情不了解不是什么大事。在软件这个行业内,最重要的技能之一就是想尽办法找到问题的解决方案,并且学习之
作为高级leader,学着接受对于某些项目的细枝末节,身边的初级工程师可能比你了解的更多。对于不了解的事情坦然承认,然后欣然接受初级工程师的解释,这没什么大不了的。他们会因为你的坦诚而产生更多的尊重,并因此更乐于学习,与此同时你会在此过程中获得关于项目更完整的图景,并进行更有效的指导。反过来作为初级工程师,应视场合而定,公开或私下向高级工程师解释具体的技术概念。
信息共享
利用会议或者Q&A环节向团队提出关键问题,相互交换知识,并且告知整个团队
在组织会议时,不要让它变成你的独角戏。会议是让他人分享想法或者提供真实反馈的机会——所以你主要是倾听,并且找机会让他人能够贡献真知灼见。
初级工程师可能会因为害羞而不会提出太多问题。如你作为一位高级工程师,可以通过提起适合的语境来激发他们提出有价值的问题。做现场问答时,让提问的人能够感受到你真心因为他们的提问而感到高兴。
灵活性
要能够捍卫自己的观点,但也应在每次有新的反正出现后重新审视一遍这些观点。
倾听他人的观点是沟通的关键一环。本质原因在于,一个问题可能有多种解决方案。不要执拗于自己的观点,应听取并评估其他可能性。没准他们会提出你之前忽略的方面。Paul Saffo’s 原则:“意见虽强烈,同时弱化固守”告诉我们应该捍卫自己的观点,但同时也应该在任何反面意见的佐证出现时重新审视自己的观点。基于证据的科学方法论不会在意一个想法或者观点来自于什么人。
维护沟通记录
在非正式会议之后的一封友善email能够敲定讨论过程中的关键点和承诺事项。
纯口头沟通的劣势在于很容易被忘记或者记错。但如果能够形成一个落在纸面的记录,并且能够得到相关参与人的确认则会避免这种风险。假设你和其他人关于某个任务达成一项约定,然后通过email进行了确认,便能够保证所有人,包括你的主管全都意见一致。维护这种临时工作记录也有助于对于每个人的评估讨论。
相信他人
明白何时应该观察动态并保持沉默
有时候你会困惑于某些决策,这些决策无论在技术上还是业务上都讲不通。这种场景容易出现在多个团队共建事项时。此时应怀有信任,并且假设人们不会在公开场合表现恶意。很可能仅仅是因为你并没有看到事情的全景,或者其他人有着与你不同的优先级而已。对于最终的决定不要表现出生气或者失落,但仍尽情提出你的疑虑和观点。
资历
在职业生涯中我们渴望成长,无论是角色的成长还是能力的成长。一些人对于资深技术岗位更感兴趣,其他人则会对领导和管理角色表现出热忱。无论哪种情况,资历较高的人都有一些共通的品质。在职业生涯中,你也可能有幸能够遇见导师指引你的成长。下面是我关于为资深角色做好准备的一些方法。
资历以及策略性思维
面对不确定性,不要不作决定或不采取行动
你经常会发现,无论对错,作出决定总是比不做任何决定来的好。作出决定至少能够让人们了解你正在向哪个方向努力。有时候作为leader,我们没有如团队所期那般花费足够多的时间来作出决定,因为我们无法100%确保已经知悉所有事实。理论上,leader可以也应该尽可能了解完整图景的所有细节,以便有足够的信心作出完美的决定,但这并不总是可能的。所以即便是在已知信息少的可怜的情况下,相比于让团队陷入漫长的等待,我们也应该积极行动起来,在过程中逐渐完善自己的决策。
Leader应该拥有更广阔的视野,能够从战略的角度进行思考,并制定战略路线图
理想情况下,随着经验的增长,全盘策略性思考的能力以及将其应用于更广阔范畴的能力亦应水涨船高。作为独立贡献者(Individual Contributor),你可能仅需专注于功能开发中被指定的任务。但随着职级的爬升,你手头工作的影响范围会逐渐扩展,直到超越具体任务和项目。当权衡各种选择时,你需要学着从收益和约束的角度去考量更大的图景。软技能的应用范围也随之扩大,比如早先你的决策无非影响自己的团队,当你成长之后你的决策以及沟通会影响多个团队。
以身作则
授人以渔而不是授人以鱼。不要总是替他们解决问题,而应不厌其烦的指导他们提升自己解决问题的能力。
作为leader学会赋权。随着你个人资历的增长,更应该扔下手头的玩具,转而使用教授、委派等手段为你的团队赋能并走向成功。唯有如此才能提升你的效用。在使用这些手段时更应该思考如何提出正确的问题,而不仅仅是给出正确的答案。
当评估出问题有挑战时,以身作则冲向一线;当有他人已经提出解决方案时,则仅需提出相关的问题
技术领域的资深人士应该为协调、谈判以及团队内外的共识建设负责。你的职责应聚焦于提升整个团队的输出,而不仅仅是自身的输出。作为资深工程师可能偶尔需要在尝试新技能或者了解基层现状时做些编码工作,但这些并不是工作目标。相反,资深工程师的职责在于保证项目架构中没有缺失,或者代码中没有漏洞。你应该具备为你的决策有理有据地解释其技术或者业务价值的能力。
一个优秀的资深工程师不仅擅长进行软件开发的架构设计,还应具备团队和人员的架构能力。你需具备能力带领一个人员构成多样的团队,对不同的人委以不同的任务,引导他们关心代码质量、代码性能和编码简约性。你还应当在必要的时候给予他们反馈,或者在需要时维护自己的队员。与此同时,你需要不断向外推广你自己、你的工作内容、你的团队,以及你们团队对于解决难题的能力,彰显团队在整个组织中的价值。总而言之:你应当管理的是与团队内人员的关系,以及团队与外部之间的关系。
放大个人力量
工程师世界中最伟大的成就都是由一只伟大的团队完成,而不是某一个人。所以如果你希望成就更多,或者展示你能够胜任更“资深”的角色,应该通过协作与辅导他人来加倍放大你的效率。并向大家展示这些措施不仅仅为你自己增光添彩,同时也提升了团队其他成员的价值。
当我意识到要提升自己而必须将自己的心态从“我”转变为“我们”时,我感觉我正在成为更加资深的工程师。通过向他人分享我的所学,专注于提升身边人的技能和专业度,我们开始一起达成更多的成就。
当然一开始作为个人贡献者时,也许没有什么团队需要由你来带领,但你总是可以去寻找与你思路相近的人协作(比如跟你目标相同的人们),与之一同工作会发现这样能够获得比你独自一人多得多的成就。随着资历渐长,这种思维方式与你融为一体,并体现在构建团队和持续提升效能中。
冒牌货综合症
请接受事实,你并非尽善尽美全知全能,积极寻找指导能够帮助克服冒牌货综合症
我们所有人都会在某项工作的某个时间点感觉到力不从心。这种对自己能力的担心被称为冒牌货综合症,这真实存在并且还挺常见。它的症状甚至会出现在那些被认为很成功的人身上。甚至别人视你为权威时你都可能会有此感受。不幸的是,你可能永远无法治愈这一病症,但幸运的是,它会督促你更加愿意接受新鲜事物。所以如果哪一天对自己产生了怀疑,不如利用这种心态。
指导
指导他人
通过及时指点为被指导者护航,避免他们的工作最终南辕北辙,并提升他们自主解决问题的能力
在职业生涯的不同阶段你会发现自己切换于指导者和被指导者的角色之间。指导他人并不需要多么正式的流程。你可以自己寻找机会对他人进行非正式的指导,或者角色对调亦然。你也可以在指导他人的过程中学习与人相处的技能。下面是关于指导的一些关键点。
指导他人并不是直接给出现成的解决方案,而是引导人们发掘问题的答案。因此需要允许被指导人在此过程中验证自己的想法。毕竟只有他们自己最能了解当前情况的风险和收益。不过作为指导者应该具备授予他人必须的工具和方法论来帮助他们找寻答案的能力。比如在技术问题面前,你可以提出建议和可以试验的方向,但是一定要让他们自己进行实际操作。认真听取他们的思路,提出新的问题,全心参与讨论。
如果有些人没能独立解决问题,那么你可以告诉他们你将如何解决问题,以及为什么选择这种解决方案。教授他们如何分析解决方案的结果或者调试问题。分享你诊断问题,尝试、实施和调试解决方案的思考过程。最重要的原则是与他人分享你解决问题的技巧,而不是分享问题的答案。
跨团队的指导
确保指导他人是资深工程师工作的一部分,能够保证当团队成员转岗、调离或者离职之后其所具备的关键专业知识仍然留存在组织之内
如果你对于指导他人的工作真的很有诚意,并且那也是你本职工作的一部分,那么你需要专门为此工作制定时间表。认真的对待指导工作可以让你在实践中游刃有余,并且能够真正的帮助到被指导者。有些公司甚至对于职级不同阶段的雇员制定指导/被指导的特定流程。
作为被指导者
指导人可以提供建议,但只有被指导者才是最终发挥主动性采纳建议并将其落实在工作中的人
如果你是一位期望在组织中不断成长的初级工程师,在这种情况下,我只有一个建议给你:找到能够帮助你踏寻成长路径的强大指导人。
在你的职业生涯中,你将会遇见各种各种的指导人,可能是组织内专门的培训师,或者团队内部的指导者,甚至是你敬仰的高人同事。他们会给你如何提升技能的建议,但只有你才是最终的行动人。当你在吸收这些建议时,要注意那些对于技术领域过于笼统的陈述。毕竟不同的情况需要应用不同的原则,对于一个项目适用的经验对于其他项目不一定有用。
高效的团队
建立信任
信任可以将团队团结在一个共同目标周围,但是官僚作风则会分裂团队
工程师们进行头脑风暴时秉持开放和无偏无倚的心态,能够为驱动创新的想法和不同的洞见铺平道路。这会打造一个高效产出的团队。而团队成员的有效协作只能根植于健康的沟通和成员关系之上。下面是一些关于如何构建、维护和参与一个高效团队的建议。
团队建设的关键是建立信任。打造高效团队需要团队成员之间抱有跨越组织架构的信任。为了审查项目的健康程度,不同成员可能有不同的方法,比如代码审查或者测试。但是如果缺少信任,这些方法都会变的可笑且官僚。比如说对于你信任的同事,在代码审查过程中你可能会倾向于少一些吹毛求疵。
理解业务模型
理解代码变更对于业务的影响
当你接到一堆需求时,应该去理解需求背后的原因。不要略过需求文档中关于目的和业务目标之类的章节。询问并理解业务模型及其与需求之间的关系。阅读已有代码或者找到组织内对应领域的专家,有助于厘清需求涉及的专业领域和项目架构。也可以查阅文档或者产品路线图以及系统流程的用例和数据流向。
“很多软件工程师喜欢解决有技术难度的问题。但是理解业务侧的事情然后提出更具性价比的解决方案也许会更有成就感。请明白一点,那就是你的用户/客户也是跟你一样的普通人,他们使用你的产品来完成自己的工作,日复一日年复一年。不要因为我们的工作让别人的生活变得更加困难。“[1]
提升影响力
对于业务的感知力和敏感度能够提升你在工作中的影响力
对于业务和产品的全方位了解能够给予团队和项目更积极的贡献。如果你能够理解营销部门或者销售部门是怎么思考的,你会更有能力作出正确的决策并且赢得更高的影响力。随着你对团队成功的影响越来越大,那你的工作满意度也会提升,薪资自然也会水涨船高。老板会认为你有能力在没有督促的环境中独立完成任务,做出适合团队、项目和业务的决策从而提高整体效率。
WLB(work/life balance)
一旦你掌握了技术能力、人际能力和领域知识,你作为一个软件工程师的技能将会使你陷入能者多劳的境地。不仅仅是你自己团队中的成员,整个组织中的人们都会来咨询你。除开你在工程上的投入,你还会成为协作过载的受害者。各种即时需求会像雪花一样飘来,蚕食你的时间,并且阻碍你做真正有兴趣的事情。
时间管理
为了深度工作优化你的时间表
在你的时间表上规划出整块时间专注于深度工作。我已经有好几年这么做了,并且我发现当撰写设计或策略文档,或者只是为了解决一个技术难题时,这样规划非常高效。深度工作是指没有分心、精神高度集中的工作,能够在很短的时间内创造大量价值。卡尔纽波特的专著深度工作对此有详细描述。
卡尔在讨论为什么长时间深度工作如此有益时,提到一个概念叫做注意力残留。每当你从一项工作切换到另外一项工作时,一部分注意力会残留在上一个任务的思考中。这种消耗会使得人们难以在真正重要的工作中保持必要的专注。
在深度工作中对单一任务保持专注,能够在有限时间内挤压出最多产量。没有使人分心的元素,没有微博、微信或者钉钉。当你面对一个大量消耗精力的任务时,深度工作会成为你的保留项目。我强烈建议尝试这种工作方式。
另外我还发现时常改变深度工作的场所有助于进入心无旁骛的状态。因为有时候我们会对特定的场所(书桌,房间或者办公地点)有所羁绊。为深度工作增加一些可变因素会让我们重新振奋起来。
避免分割工作时间
当一个小时的工作时间由于其他庶务干扰被切割成若干个几分钟的时间块,你会变得越来越沮丧。识别这些令你分心分的原因并解决它,否则会令你变得低效。
过量工作可不是好的职业道德
你永远不可能比世界上所有其他人都努力。 很多公司会把过量工作的那个员工作为标准,并且错误地将其等同于职业道德。但问题在于,成功的业务由很多因素组成,并不只是过量工作。
持续超越当前的标准是不现实的
我为曾经追求这一点而感到愧疚。如果你希望营造一个冷静的环境,避免疯狂内卷,那么你需要满足于足够。作为一个管理者,你的团队会认可你的标准,并以此作为追求。接受足够就可以设定一个良好的标准。
时也有崖。相比于为了工作腾挪出更多的时间,不如为了固定的时间删减不必要的任务。
大量的 络热门建议都是教你如何更好的安排工作。但真正的问题在于一开始就想要完成过多的工作。想一想,无情的删减不必要的工作和尝试管理有限的时间,哪个选项更加实际。
没有必要知道正在发生的事情的所有细枝末节。
我们很多人都害怕错失每一件新发生的事情。这也是为什么我们会像强迫症一样无时无刻不在关心着微博、朋友圈或者抖音。事实是,大部分信息都不重要。所以请尝试只看一些有价值的摘要总结,或者限制你查看这些信息的频率。
关于这一话题的更深度讨论可以参见贾森 佛雷德的这本著作工作,无需疯狂.
学着说不,主动将自己从过度劳累中拯救出来。学着何时停止,将休息时间也包含在时间计划表中。
无论什么等级的工程师,学习进行时间管理,维护工作生活平衡都是关键。经常性的超负荷工作会导致倦怠和压力,继而引发其他生理或心理的健康问题。在一天结束前解决一个问题总是很吸引人,但时间长了就变成习惯,难以改变了。
鼓励自己和团队的合理休息或休假
健康和家庭是至关重要的。如果你能意识到这一点,并且为整个团队树立榜样,能够提升整个团队的幸福感。反之,疲劳和倦怠会为团队引入病毒。你不知道什么时候会爆发,也不知道爆发时会产生什么样的危害。
随着对于问题理解程度的深入,及时更新预估工期
在工作中几乎总有会那么一个客户或者利益相关者,想要知道项目或者任务何时可以交付,以及需要多少投入。这一要求相当合理。有时他们想要匹配其他事项的时间点,或者你的项目规划需要其他的依赖条件。
软件工程的工期以难以准确预计而著名。仅在开发的特定阶段才能给出估计期限。随着时间的发展,预估时间应该随着我们对于团队成员解决问题的能力而逐渐清晰,因此应该经常更新。初始预估经常是最不可靠的,然而这又是随着时间推移逐渐精进的基础。最初的粗估通常都是非常保守的——由于产品需求、交互设计以及其他影响因素仍然不够清晰,所以在初次粗估时给出大量缓冲的保守预估反而对于整个项目的铺排是有益的。在实际工作中,我建议与PM协作对项目排期进行磨合,以便双方能够步调一致。
软件项目的工期预估最大的麻烦在于,人们把粗估时间画押盖章当作实际计划来安排,而不是视其为初版草稿。当整个团队以此为蓝本遵循严苛的时间节点,但将开发工期的时间调整视为工程方面的耽搁,这就成为了一个问题。另外一种情况是,当项目开发过程中一路绿灯,找出了更好的解决方案,这可能意味着由于对于需求更深入的理解,原本粗估的三个月工期变为两个月。
从开发者的角度出发,几乎总是期望让日程配合预估时间,而不是预估时间配合日程。在我们团队,当确实面对不可变更的时间期限时(比如发布会),即便预估排期超出了日程也没有关系——改变文案(比如改为:预览版)、发布框架(“即将发布”),或者一脚踢到以后也都是可以跟老板们探讨的选项。我当然明白这并不都是无关紧要的小事。所以当工期的确紧张,我们可以将工作拆分为必需项(must to have)、可选项(nice to have,可以将这些延迟到未来的冲刺再行发布),然后再评审实现这些必需项的工期能否满足日程节点的要求。
即便日程实在仍然太紧张,我们还有其他可选项,比如“我们是否可以增加人手?”以及“如果大幅缩减发布范围,交付内容是否仍然有吸引力?”
取消项目有时候是正确的选择
虽然我不喜欢这一做法,但取消一个项目有时候对于团队或者整个组织来说是最健康的决策。尤其是当产品在发布、获得掌声,却由于其人员方面的可持续性问题而导致产品最终淘汰之前。但尽量减少导致项目被取消的情况出现,我最近就撤销了一个运行多年的项目,这过程可不好受。
什么时候适合取消项目?早先,你决定在合适的时间投资一个适合的全新项目,彼时可能有很多优势,市场匹配度、组织认同、人员投入等,对于开展新项目都很合理。但一年之后,外界环境可能已经发生了变化——市场环境、管理者,以及对于项目的接受程度等。在一个项目生命周期的各个时间点,都应该检查当初的业务假设是否在此时此刻还仍然适用。
在这期间,如果你越能够保持假设正确的信心,你越可能成功发布项目并在后期持续获得支持。取消项目很难,其原因并不仅仅在于有血有肉的人们投入了精力,真切地期盼项目成功,还在于作为leader很难让投入的员工们从撤销的项目中退出,投入到其他已经成功发布的项目中,但往前看一步,让团队成员们退出到一个更加安全、可信和宽容的项目中又是如此重要。另一方面,要当心你的长期决策会如何影响用户们的信任。
关于技术债:利用五分钟做预防的价值大于耗费一个小时做修复
Titus Winters是这样定义技术债的:技术债是我们当前系统中的代码与我们期望中系统中的代码之间的差距。其中一些技术债的破坏力要远大于其他技术债。一些技术债是由于我们之前疏忽造成的,一些是事后发现的,还有一些是由于技术系统的迁移造成的。
我发现坚持优先解决技术债这件事挺难的,因为通过事前“偿还了足够多的债”而避免发生的BUG或者线上事故,你无法对其进行量化。所以有效且重要的手段是,通过在绩效评估中导向性的鼓励这种行为,以保持团队对于这一事务的兴趣。提前解决技术债虽然困难,但与之相比,用于解决债务累积所造成的线上故障的成本却更高。这个现象与污染问题类似,相比于在灾难发生之前的最后一刻想办法减轻污染,经年累月的预防显然成本要低很多。
那么在预防技术债累积方面你能做些什么呢?技术leader应该在冲刺中投入时间,在开发新功能之外,经常性的对技术债进行清理。其他相关者也应该认识到,推动短期开发进程最终可能会让问题随着开发不断积压。经理和总监之类的更高级别的管理者应该谨慎批准那些与已有项目有重叠的新项目,除非很明确的了解其中利弊得失(比如创建新功能比清理技术债更有价值)。在开发过程中监控整个项目的健康度是项目长远发展的重中之重。
无法做到生活工作之间的平衡最终会会导致职场倦怠
职场倦怠是指无法很好控制职场压力导致的一种身心俱疲的表现。我在疫情期间见到很多工程师们由于职场压力所导致的倦怠,但是这一情况在科技领域更加常见。所以最近我会在每次一对一谈话的场合询问“你是否感受到职场压力,我能为此做些什么吗?”
我经历过的职场倦怠大致表现为:发生的不突然但是最终走向冷漠。最初你会逐渐感受到精力不足,没有动力,最后在尽全力应对职场压力的过程中精疲力尽。你会一直追问自己有什么问题,但没有意识到身体正在错误地用更努力的加班来弥补缺失的能量。你会愈加强迫自己努力,直到最终发现没有什么精力可以用来努力了。
大约在五年前我经历过一次职场倦怠,幸运的是现在已经扭转过来了。是什么导致的?现在想起来,这就像是一场雪崩。有几年我都把工作放到第一位,一年比一年工作时间更长,从未对什么请求说“不“。在那几年中我没有正经休过什么假。那时候几乎每天平均睡眠时间是5个小时。当我晚上回到家里,因为精力不济,我在家也跟没在家一样。想要回到正常状态其实也简单,就是把上边说的这些事情反着做就行:正常休假,多睡觉,在工作时间中榨取更大的价值而不是延长工作时间,多放权,制定明确的“结束工作时间”。
而作为管理者,避免自己下属的职场倦怠,我认为很重要的一点是鼓励团队成员行使合法休假的权利,进行足够的休息,并且在发现有可能产生压力的时候时时常关心他们的状态。
在大型公司中执行效率会变得低下。下面是一些应对方法
我与很多工程师们的讨论最终结果会归结为这么一个问题——“为什么就做这么一件XXX在YYY公司这么难?”Alex Komoroske绝妙地将大型组织类比为粘粘的菌群。这是说,即便是执行一个简单的任务也会因为协调阻力而比预期时间长的多。组织具有复杂的系统、结构和动力机制,当在项目中需要协调的人数增加时,阻力就会增加。
这里有很多力量在起作用,包括低估他人任务的难度(例如,如果他们正在开发当前项目所需的依赖项)。 你无法忽视这些问题,因为它会使功能障碍蔓延。 克服这种阻力的一种方法是尽可能地解耦依赖,这样它们就可以落实为一个一个可以接受的时间节点,最终整体项目的复杂度会收敛于交付XXX的时间点。。
相对于从一开始就准备好解决交付XXX的所有问题,你可以通过解耦把完整的XXX这种登月计划分解为一项一项可以让你逐步接近最终目标的 X / X / X 类型的小计划。
关注问题还是关注项目
我们假设你的用户有一个未解决的需求(或者是问题)。作为一个工程师,介入一个项目时,你很自然地会想要了解当前项目是如何解决这个具体问题的。在一个大型组织中会有很多类似的项目,你会发现很多不同的工程师尝试独立解决问题。当然如果你只面对一个项目时,这种困惑可能并不明显。但可能你的用户会同时使用一堆类似功能的解决方案,他们会不会因为每一个项目解决问题的方式类似却不同而感到奇怪?此时你应该回过头去,尝试把一系列项目有机地整合起来,形成一个最能满足用户需求的端到端解决方案。即便这可能意味着你的团队需要在相关的多个项目之间进行深度协作,但当一天结束时,为用户提供了更好的解决方案总是更有价值的。
总结
以卓越为中心,与最优秀的人一起工作 – Brian Staufenbiel
与值得学习的人们建立友谊。对他们的指导、他们的成功、他们的失败保持开放的心态。永远不要害怕寻求帮助或者洞见,在很多情况下,成功只是一问之遥。
在任何舞台都请记住,掌握技术、业务领域知识以及组织内的人际关系都需要长期耕耘。一个组织不会期望从另一个那里聘请到的员工,即便是大师,在入职第一天就能够成就满满。如果你是一个优秀的工程师,你的贡献会让组织持续得到成长。作为回 ,你会收到更多的机会,使你获得新的技能并自我成长。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!