程序员技术晋升非正式攻略

一个成熟的中大型组织中,专业人员会有不同序列技术级别上升通道,比如腾讯及百度的T系列,阿里的P系列等。一些公开介绍的腾讯职级情况如下。

腾讯的职级系统有26个职业通道,如果你是一个一张白纸,没有任何职业能力的毕业生,可以从这个26个通道,比如行政、财务、设计、运维、开发、运营、产品…….的任何一个1-1级开始,修炼,打怪升级,直到千万年薪。如同一个完整的人生指引。横轴是26个职业通道,专业技能各不相同,纵轴是4个大层级。

通过职级的设定,大部分员工不需要更换工作,就可以在已有的岗位上通过自己的技术提升及项目贡献获得更高的级别,从而得到薪资的提高、专业能力的肯定及个人的专业声望。大公司的职级通常也得到业界大范围的认可,事实上也可以在多个公司之间平移。因此程序员可以在不改变工作岗位的前提下获得一个长期成长的通道。缺乏明确的成长通道也是大量小公司留不住人的一个困境,在小公司中,由于缺乏透明的、稳定的职级通道以及配套的薪酬体系,造成大量资深员工流失。

在公司有合适上升通道的情况下,工程师每年都有机会从当前职级晋升到更高的职级。在大部分公司里,对于高阶的晋升,会由公司相关权威专家组成的评审小组(通常是公司的技术委员会)来进行;低阶的晋升可以由员工的直接或者跨级上级决定。本文讨论场景主要是需要评审小组审批、候选人需要答辩的晋升,它要求候选人有更高的综合能力、专业影响力、展示能力及逻辑表达能力等。每年的年底也是大部分公司晋升评定的时间,因此本文谈谈对于晋升各种问题的看法。

本文主要是针对程序员的情况进行探讨,但所有技术工种如测试、运维以及其他专业工作岗位的人员如产品经理也大多同理。

Q: 晋升的申请材料怎么写?

当你思考晋升材料怎么写的时候,说明你已经获得了晋升的机会,这在很多公司里不是一个容易的机会。管理层通常只从符合条件的人员列表中挑选部分优秀的人员进行晋升提名,因此当上级跟你沟通这次机会的时候,说明你半只脚已经踏入了新的一个职级。

晋升无非是评估候选人的专业能力是否满足高一个等级的技术要求,候选人需要通过自己的参与项目的贡献,比如业务价值、技术成就、技术影响力等,来证明技术能力的提升达到更高级别的要求,项目贡献及技术提升两者缺一不可,因此晋升材料主要围绕这两个中心来展开。中级的晋升主要看岗位的成绩及贡献。高端的岗位可以归纳成公司级专家及行业专家。公司级专家指精通公司业务相关核心技术,在相关领域有较好积累,并且做出独到的贡献。行业专家则需要相关专业能力具有行业的领先能力,并且专业能力最好属于公司的核心技术。

Q: 每一级别的评估标准是什么?

在大部分公司一样中,每个技术等级会有相关的要求,比如技术能力、影响能力、协作能力等。在评审阶段,评委会根据要求进行候选人评估。在实践上,也有很多采用标杆人物对比的方法。评委集体选择几名处于相应级别最低能力、中等能力、和较高能力的在职员工,与申请人相对比,如果申请人处于这些标杆之中,正常应该处于中间能力人左右,则认为候选人符合条件,如果候选人处于最低能力以下,则认为候选人不符合申请相应的职级。

评估标准在人力资源领域比较知名的是Hay的评估方法,它对所有岗位的职级都适用,据说华为就是直接引入Hay的职级体系。
hay measurement

互联网公司的级别,最容易理解的程序员职级可以按下列方法来区分(如腾讯、新浪等公司):

Level 1: 能在他人指导下完成工作;(初级工程师)
Level 2: 能独立完成业务所需常见工作;(工程师)
Level 3: 能规划及完成业务所需常见项目,并能指导他人完成;(高级工程师/技术专家/架构师)
Level 4: 公司及行业专家;(首席架构师/科学家)

在操作层面上,每个级别会进一步继续细分几个子级别。当然这种划分方法只是从某一个维度去划分,实际要考虑的因素更多,大多也会落到Hay的体系上去。

不少公司并没有明文各个等级的详细要求,候选人在不能确定更高职级的明确要求的情况下,可以自己借鉴上面标杆对比的做法,检查自己与更高职级人员差别的方法来准备自己的晋升材料。

Q: 晋升有什么好处?

获得薪资及其他福利提升。越是正规的公司,薪酬范围跟职级是严格对应的,每个员工的薪酬会落到所在职级的薪酬范围内。尽管也有个别人员由于岗位的特殊性或稀缺性,出现薪酬与职级范围不匹配的情况。因此大部分人员,提升职级是获得薪酬提升最自然的方法。另外,大部分公司中,股票期权等福利需要员工满足一定职级的门槛才能获得,比如符合上述分类的Level 3的条件。

晋升在公司里面自然可以获得更好的专业能力的肯定及个人的专业声望;一些重要的项目,通常会由高级别的专业人员来带领及指导,高级别的人员通常可以获得更多历练的机会。

晋升还可以获得业界的声望及认可,大公司的职级通常也得到业界大范围的认可,在更换工作时候,至少可以在另外一家公司获得平级的职级。

Q: 技术晋升中技术能力与非技术业务能力的比重?

技术能力还是非技术的业务能力是评委以及管理层纠结的问题,有不少案例是候选人能非常好的完成岗位任务,工作积极主动,但是技术方面略逊一筹,而且进展较慢。通常管理层很希望这种人能得到晋升,毕竟这些人员是达成业务任务非常需要的人员。但从另外一个角度去看,技术晋升它不是项目贡献排行,原则上需要候选人在技术上有明显的提升,能够利用对技术更深理解去提升效率或进行技术创新,更好的解决未来面临的问题。而且放到业界,技术人员(非管理岗)也是按技术能力高低来决定薪资及等级的,所以评判是否有技术能力的提升是候选人能否得到晋级的一个刚性条件。

Q: 怎么看待业务能力与技术能力脱节的矛盾?

一些团队可能会存在脱离业务研究技术的人,对参与项目漠不关心。纯粹脱离公司环境的业务去研究技术在大部分组织里面是比较有争议的。在这些人员技术能力有明显提高的情况下,如果继续给这种人晋升会不会带来一些负面的问题,比如会诱导其他工程师脱离业务去研究技术。因此比较好的方法是评判候选人是否通过项目贡献体现了技术提升。这样脱离公司环境去打怪的人员自然就没有了生存土壤。另外,管理层从公平性的角度出发,可以设置晋升准入条件,比如绩效需要达到某个优秀分以上。

Q:直接上级是否可以决定下属是否晋升?

在大部分公司中,对于低阶职级的候选人,直接上级及跨级上级能发挥较大影响力,大多可以由直接或者跨级上级来决定。而越高阶的晋升,直接上级发挥的作用越小,通常由公司级别的专家小组来进行评审。因此高职级的同学在日常的工作中,需要更好的平衡上级的要求及合理的技术架构之间的关系,尽可能的多的具备独立思考的能力,更多的利用技术驱动项目带来贡献,并进一步体现自己的技术成绩。

Q: 评审时时候评委喜欢提的问题?

项目的难点,评委主要通过这些问题来判断候选人面对复杂问题的应对能力。由于是技术答辩,候选人应该尽量多的将问题放在重大技术问题的解决上。

项目的技术贡献,候选人通常会通过项目进度的方式描述如何参与项目,但评委比较关注候选人的技术输出以及技术含量。

项目中的个人贡献,原理同上,不少候选人参与过一些大的公司明星项目,因此对晋升答辩比较自信,但如果只是在大项目中做一些辅助执行类的工作,通常也不会得到较大的认可,反而会造成材料假大空的印象。

Q:怎样看待评委的刁难问题?

候选人用朴素的方法来介绍自己的项目,尽量客观的方法来描述自己的成绩。当被问及刁难及质疑性问题时候,尽量不要有防卫心态,不要将自己的项目中的不足设法合理化,心平气和的接受评委看到的不足。

Q: 评审时候选人容易忽略的问题

指导及影响他人的能力。在一个组织里面,独行侠未必能得到好评,帮助及带领周围技术人员一起成长会更容易得到认可及欢迎。
非岗位要求的贡献。能够按照岗位的要求完成工作只能满足合格的水平,主动思考及完成超出岗位要求的工作更容易得到高分。

Q: 我工作很努力,经常加班,是否必定会晋升?

没有直接关系。评审主要看技术能力提升、技术贡献及通过技术获得的成就。与是否努力是否加班没有必然关系。当然,工作努力的人员通常也通过更多时间投入在技术领域获得了比较好的成长,因此有更大的晋升可能。

Q: 我在我的team里面公认是技术能力最强的,甚至别的部门一些职级能力高的能力不如我,是否必定会得到晋升?

这种案例失败概率还是不低,关键点还是看候选人近期项目是否能充分体现出高级别所具备的能力,如果候选人近期做了很多零散工作,虽然具备很强的技术能力,也较难得到一个合格的分数。

Q: 我刚毕业,怎么才能获得快速的职级晋升?

刚毕业的同学还是更多的学好基础的知识,乐于学习,更多的参与实践,在工作中发挥更大的价值,不要刻意追求晋升与否。晋升更多的是一个能力到达的伴随物而不是追求的目标。如果你具备以上素质及习惯,即使在当前企业未得到认可,可以在一另外一个的环境得到实现,只是一个短暂的时间差问题。

Q:我公众场合的展示及表达能力不强怎么办?

大多评委也是技术背景出身,因此对展示表达能力并不是特别在意,反而过于华丽的展示材料会引起评委反感。但在另外一个方面,展示材料的层次关系、论证问题的因果关系的逻辑需要得到清晰的表达。评委不会特别介意候选人念稿,但是会介意材料结构及逻辑混乱。

Q: 应该以什么样的心态去看晋升?

晋升大多时候是个僧多粥少的游戏,而且评审的价值观也存在单一的可能,在有限的评审时间,考虑到准备的充分与否,候选人对于评审重点的理解等,未必每一个候选人都能得到合适的展示。评委也很难在短时间对候选人进行充分了解,因此评审通过与否未必能完全体现候选人的能力。

候选人最重要的是调整好自己心态,“不以物喜,不以己悲”,明白自己核心价值所关注的事情(参看拙作选择学习目标的方法与自然法则),将更多的精力投入到自己关注的事情上去,并产生相应的成果及影响,这个比一个晋升结果意义要大得多。晋升评审可以视为是一个职场阶梯游戏,不少得到晋升的人员后面无所成就的案例也是层出不穷。大部分情况下,晋升通过与否仅是薪资的一个损失,不会影响你的产出;不会影响你的生产率,不会影响你的成就。候选人需要清楚了解及坚持自己的目标,才能在个人能力,职业生涯、个人影响力方面取得更大的成就。

选择学习目标的方法与自然法则

不少工作多年的朋友都会有时间失控的焦虑,工作已经在设计好的轨道上运行,日常时间被例行的工作及各种琐事占据,大部分时间并不是由自己主动控制。每天还有不少突发的任务从邮件、电话、通讯软件等各种渠道涌入,挤掉了主动去做一些事情的时间。一些担任管理岗位的人员甚至每天大部分时间是由秘书安排。生活上重要的事项一再被拖延,许多时间一再决定下次有时间时候一定要做但是一直都没做。

另外一种情况,在时间可以主动把控的情况下,不少朋友也会碰到选择目标的问题,几个月前写的选择目标的困难与焦虑提到

工程师如果某段时间没有学习目标,就会有一种来自内心虚度年华焦虑。

文章也引起了一些同行的共鸣,不少朋友在后台留言询问解决的建议,而那篇文章的目的更多的是提出一些问题引发思考,而究竟怎么解决则需要每个人去自己寻找答案。并且当时也没有非常好的值得广泛借鉴的。

最近看了Hyrum W. Smith的10 Natural Laws of Successful Time and Life Management一书,1995年出版的,已经比较久远,刚出不久的中文版叫高效能人士的时间和个人管理法则,里面提到一些方法可以帮助我们更好的来控制时间及选择目标。

law1

书中提到的自然法则(natural laws)是类似“万有引力”这样的自然中的基本模型,不管我们同意与否,自然法则会独立于我们而存在。了解一些时间及目标管理的自然法则,可以帮助我们卓有成效的利用每一天时间。而我觉得最有参考意义的自然法则,就是确定“核心价值”这一点。

看到这一点时,每个人可以先问下自己核心价值是什么?关爱亲人及自身健康是大部分人核心价值的一部分,如果如此,那每天所做的最重要的事情是否包括这些?每个人还可以列出其他一些相对于自己生命中最重要的事情,如经济安全、事业有成、获得专业声誉及影响力等。判断一个目标是否属于核心价值则可以用自然法则去判断,比如用能不能失去做判断,或者假设生死关头最不能舍弃的元素来排序,排序最前面则是你关注的核心价值。

列出核心价值之后,你再可以去检查每天所做的事情是否属于核心价值,并根据核心价值的优先级程度对要做的事情进行排序,如果你的健康排在第一位,则每天你最重要的事情则是做一些让自己保持健康的投入,而不是把健康的问题拖延,让一些不重要的紧急任务占据你所有的时间优先级。每天起床后可以抽出15分钟时间去规划当天的时间计划,确保核心价值的事情得到了优先安排,如果一个人的核心价值是想取得事业上的成就,为了让事业有成,短期及长期要做什么?当天是否在主动促进?当检查完的核心价值,再回顾每天的日常轨道上那些事情,如果发现大部分时间是在做和核心价值无关的事情,那建议尽早去整理自己的优先级列表,让每天所做事情根据自己的核心价值的对应顺序进行优先级排序。

Smith提出激光思考的方法,如果在太阳底下我们使用一个放大镜,将阳光聚焦在一点就可以让树叶燃烧起来。激光思考也是类似的思路,让我们每天的时间聚焦在我们最应该关注的事情上面,并且持续投入,就会产生激光效应。有非常多的技巧及方法让一个人专注,当他意识到哪些事情值得投入的时候,方法通常不会成为问题。

google_calendar

上图是一个假设的一天时间计划,并按照优先级进行了排序。假定主人公的价值观排序是:1、家庭;2、健康;3、职业成就与专业声誉;4、学习与个人修养。通过Google Calendar,我们可以将日程设置颜色,上述的1、2设置成绿色,3设置成黄色,4设置成灰色。当然你也可以通过标注A/B/C/D这样来区分优先级。通过工具,我们可以方便的将时间投入在核心目标上。时间计划切忌排太满,需要留出一些空余时间应对突发事件。而Smith的工具则是纸面的表格,可能1995年电子日程工具还不太成熟。纸上的日程有个好处,做完后划掉后会产生巨大的满足感,大脑会分泌一种叫做内啡肽的化学物质,它会给你带来注射吗啡一样的快感。

最近网上一些讨论提到不少人群大量时间被通讯及社交软件占满的现象,一方面,移动网络拉近了人与人之间距离,可以随时随地保持连接。但在另外一方面,日常大量的时间也被微信聊天、朋友圈、微博等软件占据。一些人觉得罪魁祸首是这些软件,通过避免使用这些软件来把控时间,这诚然是一种方法。但问题如第二段所述,有一部分人每天即使能空出不少碎片时间,也存在不知道该投入在什么地方的问题。只有明确了自己每天更值得投入的目标,社交软件的问题自然可以很理智的去取舍。

每一天都应为自己的核心价值而行动。

Linux Load编程竞赛

Linux load average的意思就是说 目前有ready的进程 但是cpu都在满,然后这个数是一分钟的平均值。公式:loadvg = tasks running + tasks waiting (for cores) + tasks blocked. 让CPU满是最简单的方式

为了更好理解load average,Tim某天在群征集一段代码使load average最高。于是乎,群友纷纷出手。

Erlang版

[~]$ cat load10
#!/usr/bin/env escript
%% -- erlang --
%%! -smp enable -sname load10
main(_) ->
I = erlang:system_info(scheduler_id),
random(5).

random(I) when I > 10 ->
random(I+1);
random(I) ->
spawn(fun() -> random(I+1) end),
random(I+1).

此代码将Linux load跑到了10-20,取得了领先

Shell版

#!/bin/sh
for((i=0;i<10;i++));do
{
for((j=0;j<1000000000000;j++));do echo '1'>>1; done
}&
done

Ruby

ruby -e "require 'thread';t = Mutex.new;10.times {fork {10000000.times{t.synchronize {x=Time.now}}}}"

Java版

import java.io.*;

public class LoadTest {

  public static void main(String[] args) throws IOException, InterruptedException {
      int count = 1000;
      for (int i = 0; i < count; i++) {
          final Thread t = new Thread(new Runnable() {
              public void run() {
                  try {
                      while (true) {
                          RandomAccessFile file = new RandomAccessFile("/tmp/test.bin", "rw");
                          file.seek(1024 * 1024 * 500);
                          file.write(1);
                          file.close();
                      }
                  } catch (IOException e) {
                  }
              }
          });
          t.start();
      }
      Thread.currentThread().join();
  }
}

C语言版

void main () {
int i=0;
for (i = 0; i < 1000; i++) {
if (fork () > 0) {
continue;
}
while (1) ;
}
getchar();
}

此版本远远超过了上面的Erlang版本,将load拉到1000+

Java版本2

public class Test {

   public static void main(String[] args) {
       for (int i = 0; i < 1000; i++) {
           new Thread() {
               @Override
               public void run() {
                   while (true) ;
               }
           }.start();
       }
   }
}

此版本和上面C版本效果类似

部分讨论:

不对呀,这个方法以前不行
CentOS 6吧[惊讶]
CentOS 5
有几个版本有bug,cpu的hz拿的不对,load特别低,7就好了[坏笑]

Java版本3

写两类线程,一类进行lockObject wait, 一类进行lockObject notifyall。 cpu上下文切换消耗 竞争激烈。Load能很高。

public class LoadHighDemo {

   public static void main(String[] args) throws Exception {
       LoadHighDemo demo = new LoadHighDemo();
       demo.runTest();
   }

   private void runTest() throws Exception {
       Object[] locks = new Object[5000];
       for (int i = 0; i < 5000; i++) {
           locks[i] = new Object();
           new Thread(new WaitTask(locks[i])).start();
           new Thread(new NotifyTask(locks[i])).start();
       }
   }

   class WaitTask implements Runnable {

       private Object lockObject = null;

       public WaitTask(Object obj) {
           lockObject = obj;
       }

       public void run() {
           while (true) {
               try {
                   synchronized (lockObject) {
                       lockObject.wait(new java.util.Random().nextInt(10));
                   }
               } catch (Exception e) {;
               }
           }
       }
   }

   class NotifyTask implements Runnable {

       private Object lockObject = null;

       public NotifyTask(Object obj) {
           lockObject = obj;
       }

       public void run() {
           while (true) {
               synchronized (lockObject) {
                   lockObject.notifyAll();
               }
               try {
                   Thread.sleep(new java.util.Random().nextInt(5));
               } catch (InterruptedException e) {
               }
           }
       }
   }
}

上物理机把5000个线程改成更多,如50000也行。
直接while true改5000应该能更多……
我的应该能一直上涨, load 1000, 2000, 3000

可以试试parkNanos(1)

刚才卡了。。。
看来不能在本机上跑

Python版

把5分钟 load avg 稳定在1024了
在本群感到了一种情怀。。。

#!/usr/bin/env python
import os
import sys
import time

def load_add_1():
time.sleep(30)
fd=os.open("test.txt",os.O_CREAT|os.O_RDWR|os.O_SYNC, 0644)
for i in xrange(10000*100):
os.write(fd," "*100)
sys.exit(0)

for i in xrange(8192):
if os.fork() == 0:
load_add_1()

此版本将load跑到8192

C语言版本2

https://gist.github.com/hongqn/37cdfde04d0c5a03fede

#include <unistd.h>
#include <stdio.h>

#define LOAD 16384

int main() {
int i;
char s[256];

for (i=0; i<LOAD; i++) {
if (vfork()) {
return 0;
}
}
scanf("%s", s);
return 0;
}

macbook 上 virtualbox 里一个 2G mem 单 core cpu 的虚机就可以轻松达到16,000
这个的原理是通过 vfork 产生指定个数的 D 状态进程,从而提高 load

Vfork() differs from fork in that the child borrows the parent’s memory and thread of control until a call to execve(2) or an exit (either by a call to exit(2) or abnormally.) The parent process is suspended while the child is using its resources.
vfork 的子进程只要不 execve 或者退出,父进程就一直挂着(在D状态)。这里就是让最后一个子进程用 scanf 等输入

通过以上题目,你是看到了热闹,还是看到了门道?