【职场分享】程序员如何出活 / How to deliver fast as an IC

从entry level升到senior的路径通常很清晰,从技术上讲,就是能deliver能出活。从一个小ticket开始做,到独立完成一个feature相关的若干ticket,再到独立完成若干个feature的时候,基本就是senior的水平了。其他方面的衡量标准(主要是soft skills)以后单独聊。

上一篇提到,新人一开始工作的时候可以跟组里的大牛和老员工一起干,shadow他们,快速提高自己的技术能力。这样学习一段时间后,就可以逐步地跟同事pair/mob programming。有些组倾向pair,ticket两人一组完成。pairing的时候有不同的模式,比如一个人负责设计一个人负责打字,或者一个人写一个人看,或者两个人一起讨论之后一个人写,30分钟或者一个小时互换。有些组倾向mob programming,基本的模式是一个人负责打字,其他所有人讨论,然后互换。这些合作工作方式的好处是能够让新人很快地上手,观摩有经验的同事是如何工作思考的,也能够得到及时的反馈。弊端是有些人更喜欢自己一个人安静思考,集体的氛围会带来压力,新人有的时候写代码还不熟练,而老人思维活跃效率高手速太快,节奏不一样。如果组里有特别爱发言、爱打断别人、性格过于强势的同事,会极大地影响合作的效率和好感。

有一段时间我们组里新人很多,几乎所有的ticket都是pair,以便于老人带新人。一开始大家反响都还不错,过了几周,有些新人觉得老人干得多,导致自己缺乏ownership没有机会独立思考,有些老人觉得每天跟新人pair影响自己的工作效率。在开了RETRO反思会之后,大家决定还是一个ticket一个人own,如果有人觉得需要别人帮助或者have a second pair of eyes,可以在standup的时候提出来。我觉得这个模式很好,不强行pair,而是按需pair。我就经常在get stuck的时候跟组里的人pair,有时候甚至都不是pair,只是我把自己的问题解释给其他人听,然后自己就发现了问题出在哪儿,有一种小黄鸭调试法的感觉。

有些组的ticket是项目经理PM写的,有些组的ticket是IC自己按照PM的需求和planning的讨论写的。有些IC的工作是老板分配的,有些则是有一定的选择空间。比如,一个sprint可能有若干ticket:product feature implementation、tech debt、incident investigation、design doc等等,在大家讨论了priority之后,每个IC会own一个或者多个ticket。

怎么选择ticket和项目呢?还是那句老话,鸡蛋不能装在一个篮子里,diversification。

新人或者junior engineer一开始最好做scope明确且有大牛罩着的小活,比如大牛是一个项目的tech lead,design doc或者RFC之类的文档早就写完并且已经内部讨论结束了,所有的feature requirement已经写成TODO,只剩下干活implement了。这样的product feature implementation是低风险低收益的小活。所谓低风险,是因为design的时候已经讨论过risk和alternative,加上大牛牵头,项目的成功可能性极高。所谓低收益,是因为毕竟tech lead是别人,自己只是打小怪积累经验,没有太多的visibility。

低收益总好过没有收益。所谓的low hanging fruit可遇不可求。除非是去了start up,在大厂低风险高收益的坑基本早就被前人填了。而start up本身就是高风险的地方。世上没有免费的午餐。

product feature implementation的活做了一段时间之后,对code和组里的情况也更熟悉了,这个时候,可以分出20-50%的时间pick up一些tech debt的ticket。我不建议一上来就做tech debt,一方面是对tech stack还不够熟悉,二来是还没摸清组里和公司的politics。一个东西之所以成为tech debt,总是有很复杂的历史原因。要么是急着上线,以debt换速度,要么是debt无伤大雅,没必要,要么是涉及很多组的权力资源分配,要么是组里有其他更高优先级的活需要先做。总之,平衡tech debt和new feature是每个组都要面临的问题。等有了更多经验和知识,对系统有全面深入的了解,可以写一个doc,把现有的tech debt列出来,然后share给PM和老板,在RETRO的时候提出来。当然如果组里已经有这类doc,你可以先读一下,了解debt的现状。如果你认为需要priortize一些tech debt,PM和老板都觉得你说得对,就可以把tech debt的ticket提上日程。如果你的PM和老板因为各种原因不想搞tech debt,也不需要强求。毕竟tech debt不会自己消失,只会在backlog里越积越多,可以以后有时间的时候再revisit。如果sprint planning的时候已经有tech debt的ticket,说明这个tech debt已经被认为是重要的,这个时候就可以直接做了。

Tech debt的难度差别很大,难以预估时间,而且很多tech debt没有hard deadline。所以我不建议用100%的时间只做tech debt的ticket,可以一边做feature,一边搞tech debt。难度低的tech debt一般只涉及不到一个sprint的活,比如fix a flaky test、update API call、tech documentation,难度高的tech debt一般涉及时间更长,比如系统层面的optimization、migration、testing framework等。组里的日常工作,比如ways of working、remote work、oncall、onboarding也可以归于tech debt。

incident investigation一般和oncall挂钩,大多直接关联business impact,有很高的visiblity。一般新人刚加入是不在oncall上的,所以也没有incident investigation的机会和责任。在oncall的时候,一般需要预留出一半的工作时间应对incident,这个在sprint planning的时候可以体现为不要做那些时间紧迫的ticket,而是选择多选一些时间充裕的tech debt或者design doc:如果没有incident就可以多做点,有incident就可以做慢点。有些incident不是oncall alert,而是跟产品相关的反馈。比如一个广告商发现自己投放的广告CTR突然降低,或者广告投放不满足需求,会联系客服,客服会将这些问题反馈给相关产品组的PM,PM会让组里的IC去调查具体有什么问题。这个时候,最好有明确的incident management protocol。如果组里所有的IC都一拥而上去查看同一个问题,首先效率很低,会出现重复性工作,影响其他的日常工作,其次有些IC会觉得自己迫于压力不得不放下手头的工作,参加incident的调查。有些IC干得多有些干得少,credit分配不均,更有甚者,有的IC会抢credit,把大家合作的调查结果在老板面前说成是自己lead的。如果出现类似的情况,可以在RETRO的时候提出反馈,或者在跟老板1on1的时候提出自己的顾虑,同时提出解决方案,那就是明确责任人和ownership,比如让oncall IC作为直接调查人,其他IC可以不用参与调查,除非oncall IC觉得需要别人的帮助。

还有一类ticket就是design doc,一般是基于一个产品的OKR,需要IC这边写一个tech design doc,有些公司也叫RFC(request for comments)。RFC可以是针对一个OKR的High level system design,也可以针对一个具体feature的implementation design,当然也可以不是tech相关,而是涉及strategy和operation。总之就是一个类似于proposal的文档。大概的套路是,第一,提出痛点和问题,强调解决这个问题带来的impact,第二,提出解决方案,项目的scope,列出其他备选方案,第三,风险评估和规避方法。在细节方面,可以加上timeline、milestone,也可以加上具体的Implementation plan和各种diagram。

design doc一般会由有一定经验的IC牵头,有很大的主观倾向opinionated,也就是写的人要在多个可选方案中选出一个自己个人觉得最好的solution,然后跟大家讨论。我最开始写RFC的时候,觉得不能太opinionated,要客观,要考虑周全,各种pros and cons,各种alternative都详细讨论,然后跟大家一起讨论出一个解决方案。但我的mentor告诉我,RFC这么写虽然全面,但并不是最有效的。读者并没有写RFC的人想得那么多,很多时候我列出的pros and cons,反而会让读者对我的方案产生质疑。

而更有效的RFC写法,要先列出自己想要做的方案,要opinionated,在分析pros and cons的时候,可以有选择有倾向性。RFC的目的,并不是为了跟其他人讨论然后一起出一个方案,而是为了说服别人自己提出的方案是最佳的,因为XYZ这些原因。RFC的内容是要为了自己的目的服务的。举个例子,如果你的RFC是,把现有的系统migrate到另一个平台。我一开始的写法是:方案A,migrate,方案B,维持现状,然后“客观”地列出方案A和B的优劣,最后说,综合以上,我觉得需要migrate。经过我mentor的改动,内容不变,但是写法是,我认为需要migrate(一开始就提出论点 ),因为migrate的好处是123,不migrate的坏处是456,详见appendix。然后在appendix里写不migrate虽然有一些好处,但坏处明显。这样的写法,重在persuasion,而不是comparison,类似于GRE里的argument,得有自己的一个thesis和论点,counterargument是为了论点服务,而不是为了追求所谓的客观性。其实很多工作内容和方案都不是完全客观的,毕竟工作是人做的,而人都是主观的。

Design doc因为是项目立项阶段,所以风险一般更大,但作为项目owner,所带来的收益也更高。具有senior能力或者已经是senior的IC会更多地参与到这个阶段,甚至有50%的时间都在写/改/读/讨论RFC。

还有一类活是自己凭空想项目,大多是偏research、open-ended的项目,多是个人兴趣导向。不同公司的形式不同,有hackweek、side project、growth work等等。以我们组为例,每个IC可以有20%的时间做这类项目,也就是每周一天。有一些项目会有prototype,做demo,甚至会成为产品,大多数项目都是探索一段时间发现不能产品化,或者不能priorotize。有些growth work是读一本书、coursera的一门课或者book club。我之前的一个side project是写一个python library,我做出了alpha version还有很明确的feature list,但最后因为没时间做这个就闲置了。这一类项目重点在于growth和learning,而非出活。

最后说一下如果项目无法完成怎么办。这里说的无法完成是指因为主观或者客观因素导致没有交付最终产品。我参与或者牵头但最终无法完成的项目两只手都数不过来:项目A是我刚工作参与的一个项目,有好几个经验丰富的老人牵头,最后因为结果不好被砍;项目B每周都给PM和EM开会讨论,最后因为不是短期的high prioirty被搁置;项目C我读paper设计了一个很复杂的时间序列feature,提升了线下的模型预测准确度,但feature engineering的时间过长,无法满足线上预测的要求,终止;项目D断断续续做了大半年,涉及好几个组的人,各种开会讨论,code已经写完就差rollout,结果因为infra组的问题被迫终止;项目E是我的一个hackweek项目,做了一周发现数据量不够,作罢。

即使是所谓低风险的项目,也不代表一定能完成,因为很多因素是自己没法控制的。有些探索性质的项目,本来不是为了结果,而是为了学习。

没有完成的项目很难有实质的影响力impact,没有impact的工作虽然老板看在眼里,没有功劳也有苦劳,但是很多时候大多数公司的升职看的就是impact,看的就是功劳,而不是苦劳。审阅你升职资料的人,一般都是其他组的,他们跟你没有日常接触,也不知道你的项目为什么没有完成,他们只看你的工作有没有impact。这里面有work smart的成分,也有很大的运气成分,当然也少不了办公室政治。总之,项目能够完成比完美的半成品更重要,done is better than perfect。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.