Apptio是个好公司

Apptio最近上市了。

去年Apptio给过我一个offer。工资加奖金勉强赶上我当时的工资,然后就是一堆stock option。当时算下来觉得从财务角度[1]来说很不划算,所以没要那个offer。当时根据offer里给的stock option数量、strike price、以及total shares,算下来觉得Apptio上市以后的市值要达到$2.8 billion,这个offer从财务上来说才算是打平。但根据Apptio告诉我的annual run rate以及之前两年的增长率,再参考SaaS公司的一般multiple,我当时认为Apptio如果在1-2年里上市,能达到$2.8 billion market cap的可能性很低。

今天Apptio的市值大概是八百多million,股价二十几块。这样看来,当时的决定是对的[2]。我觉得我要感谢Apptio,当时我一问annual run rate和total shares,他们就告诉我了[3][4]

相比之下,我去年谈的另一家公司的做法就太不厚道了。那是一家国内的独角兽大厂,据说两年内要上市。他们的offer里给了我n股股票[5]。给我offer的HR跟我说,现在他们每股价格是x元,过两年上市以后价格会是y元。我就问这个x和y是怎么算出来的,那个HR不肯说。于是我就问total outstanding shares是多少,HR的回答是这个我们不能说。虽然纸面上 (y-x)*n 这个数字还蛮大的,但我最后还是没要那个offer。原因有好几个,其中之一是“Don’t work for someone who … won’t tell you what percent you own.[6][7]

相比之下,Apptio是个好公司。



[1] 这篇文章满有意思的: Big Company vs. Startup Work And Pay
[2] 也许APTI会像TWLO那样在上市以后的三个月里面涨三倍,不过那跟拿不拿Apptio的offer没有太直接的关系。
[3] 如果他们不告诉我,我也还是可以自己毛估估的。但以我的水平,毛估估的误差太大了。
[4] 看了一下Apptio的S-1 filing,里面的shares和revenue数字跟他们当时告诉我的基本一样。诚不我欺也。
[5] 一开始跟我说是期权,但后来各种细节问下来,怎么听怎么像是RSU,比如vest的时候就要交所得税。
[6] “Why are startup employers hesistant/unwilling to give information like % equity offered when making an offer?”
[7] “Should you join a startup if they refuse to disclose the percentage equity ownership you are getting as part of your offer?”

如何向国内的亲朋好友解释Preschool、Pre-K和K

中国有托儿所和幼儿园,幼儿园有小班中班大班。小学从一年级到五年级,原来的小学六年级很多年前变成了初中预备班。然后初中三年,初一初二初三。高中三年,高一高二高三。美国的中小学体制很不一样,很多身在美国的人都搞不清楚,包括我自己,一直到我们自己的孩子快到上学的年级了才慢慢弄明白。今天我想把它给写下来,这样以后这边的其他同学们要向国内的亲朋好友解释Preschool、Pre-K和K的时候就不用打很多字了,直接转发我的这篇就可以了。

总的来说,美国的中小学体制的一个特点是:。年级的划分不但每个州不一样,连在同一个county里,甚至是同一个school district里的公校之间都会很不一样。再加上私校,就更乱了。下面细细的来说,不想看的可以直接跳到最后的总结部分。

首先是托儿所和幼儿园。在美国,小学之前的一般都统称daycare。有些daycare接受最小只有六周大的infant。能接受3-6个月大的婴儿的daycare比比皆是。美国所有的daycare都是私营的,有些规模比较大,比如Bright Horizon是一家连锁daycare,还是一家上市公司。有些规模比较小,就开在民宅里,价格相对便宜,一般叫”family daycare”。Daycare一般按照年龄分级:

  • Infant: 一岁(12个月)以下
  • Toddler: 1-2岁(12-24个月)
  • Twos: 2-3岁
  • Preschool: 3岁
  • Pre-Kindergarten(简称Pre-K): 4岁

美国人(至少是西海岸的美国人)基本上没人管幼儿园叫nursery school。Nursery在美国人的语言里指的是苗圃,那种卖花花草草的店,尤其是那些开在suburban的。不信,你去Google Maps,找到西雅图,然后搜nursery。排名第一的是一家topsoil supplier(卖土的),排名第二的是Molbak,他们的店在Woodinville,离我家开车就几mile。我特别喜欢他们家,我觉得Molbak是nursey里的爱马仕。

另外一个很容易翻译错的词是kindergarten。美国人不管幼儿园叫kindergarten。美国人用kindergarten特指小学(elemetary school)一年级之前那一年(小学预备班?)。如果一定要翻译,那么kindergarten更接近国内所说的幼儿园大班的意思。

混乱的局面是从幼升小开始的。

美国的小学叫做elementary school。典型的美国小学有6个年级:Kindergarten(简称K), 然后是Grade 1到Grade 5,也就是一年级到五年级。如果你看到某个小学的简介上写着”Grades: K-5”,就是说这个小学的年级是从K一直到五年级。美国小学的一年级(Grade 1)倒是和国内一样的:一般是满六周岁可以上一年级,当然例外情况也并不罕见。但是,还有数量相当多的美国小学(包括公校和私校)不是K-5的。他们的年级范围五花八门:

问题就来了:Pre-K到底是在daycare(幼儿园)里上,还是去elementary school上。在daycare上Pre-K吧,怕小孩被放羊了。去小学上Pre-K吧,又怕小孩过早压力过大。不过大部分想推娃的都是会选择去小学上Pre-K的。

小学后面是中学。现在国内的中学慢慢跟美国的很像了:初中和高中是分开的,很多学校只搞初中,很多学校只搞高中。不像我念书的时候,那时候主流的中学的配置是初中+高中。美国的主流配置是:初中和高中是分开的。主流的public school里面,一所学校要么是初中(middle school),要么是高中(high school)。公校的初中和高中的年级划分还算比较整齐划一:middle school一般都是6-8,就是六年级到八年级,三年;high school一般都是9-12,就是九年级到十二年级,四年(对的,美国高中是四年!不是三年!)

个么问题又来了:既然初中都是6-8的,那么万一现在的小学是K-4的,那么Grade 5去哪里上呢?办法也不是没有,那就是:上私校($$$$)。私校的中学就五花八门了,什么样的年级配置都有,而且很多都是初中高中合起来的,初升高的时候少折腾一次还是很有吸引力的(但是,$$$$)。常见的有:

太变态了,有没有!比如,要上7-12这种中学,岂不是小学就必须要上K-6的?否则,如果上的是K-5的小学,岂不是还要另外找个地方把6年级给补上?还是说对于个别天资特别高的小孩,上完K-5就直接跳级进7-12了?不懂。我觉得大概过几年等郑轶嘉要上中学了我也许就能把中学的事情也彻底搞明白了。不过话说回来,我念书的时候还没有初中预备班这么回事儿,那时候的中学里面,7-12是标配啊。

以上这些还不算是最奇葩的。还有更奇葩的:

混在狮子座里的处女座表示:这简直让人不能忍啊!

当然,最让人省心的是家里附近有一所K-12的学校,十三年一贯制,一所学校里从K到Grade 12(相当于高三)都管了。这样的学校其实还蛮多的(但都是私校$$$$),比如我们家这边的The Bush School。对了,他们家的中文名字是“布什学校”么?

说了那么多,总结一下。一般来说,

  • 美国的高中是4年,从Grade 9到Grade 12。相当于国内的初三到高三。
  • 美国的初中是3年,从Grade 6到Grace 8。相当于国内的初中预备班到初二。
  • 美国的小学是6年,从K到Grade 5。相当于国内的“小学预备班”到小学五年级。
  • 美国的Pre-K就是K之前的一年。
  • 美国的Preschool就是Pre-K之前的一年。

我为什么不赞成压低级别(续)

在我看来,面试就是对一个人的能力值的观察,而定级就是对观察值取整。

为了简化讨论起见,假设每个人本身都有一个能力值,比如8.1。这个值随着人的成长会变高。这个值可以通过观察得到,但观察结果总会有偏差。由于观察者本身的差异,不同的观察者会得到不同的观察值。有经验的观察者和没有经验的观察者得到的结果也会不一样。一般来说,观察时间越长,观察结果更接近真实值的可能性越大。无论是面试后的定级,还是内部晋升,都是对观察值取整。例如,内部晋升的取整策略往往就是round down,向下取整:观察出来的能力值达到8.0或以上的可以升8级,观察值是7.9的就继续留在7级上。这种做法基本就是行业惯例,而且无可厚非,因为不管怎么做,线总是要画一条的,画在哪里都是画。内部晋升的时候,观察时间会很长,一般都起码有几个月时间,所以观察值比较接近真实值的可能性很大,一个真实能力8.1的人,观察结果可能就会在7.9到8.2这个区间里。所以在内部晋升的过程中,真实能力没有到8.0但是被升到8级的情况一般很少发生,真实能力已经有8.1或8.2了但没有升到8级的也很少发生[1]

面试也是一个观察过程。这个观察过程时间非常短,手段非常局限,观察者数量有限。所以面试的观察结果的误差范围会相对大很多。而且由于某些因素的影响,观察值偏低的可能性比更大一些。这些因素包括:被观察者会紧张、劳累;观察者在询问被观察者一些问题的时候可能用了一些被观察者不熟悉的术语,或者同样的术语在双方的理解中含义不同;观察者询问时在无意中可能包含了未说明的假设;等等。再加上各种各样的unconscious bias,综合起来的结果就是观察值偏低。比如一个真实能力为8.1的人,面试下来观察值可能会在7.6-8.0这个范围。如果在面试的时候采取和内部晋升同样的策略,即round down,那么这个被观察者有很大可能就被round down到7去了。但是,如果在取整时使用四舍五入(也许叫五舍六入或六舍七入会更准确一些),那么这个人会被四舍五入到8。因此在这类例子里,“四舍五入”能比向下取整得到更准确一些的结果。

“四舍五入”的策略的确会带来一些风险。比如,一个能力值是7.5的人面试下来的观察值有可能是7.7,结果“四舍五入”就把他/她定到8级去了。不过,我认为这个风险是比较低的,主要原因就是前面所说的,面试作为一个观察过程,观察结果往往是偏低的。换句话说,要真实值在7.8到7.9左右的才有比较大的机会被“四舍五入”的策略“错误的”定到8级。7.8或7.9的被定到8级,这样的误差是否可以接受,这取决于每个公司的具体情况,取决于供需关系。每隔几年都会出现少数特别火爆的公司,所有的人都以加入这样的公司为荣,在这样的公司就职的经历是会给简历大大加分的。对于这样的公司来说,供需关系是极其有利于公司方面的,这样的公司因而可以施行“宁可错杀一千,也不漏网一个”的标准。这样的公司即使在面试中使用round down策略,也不会有损于它们的招聘需求。但另一方面,绝大部分公司都无法真正做到”we only hire the best”,对它们来说,采用“四舍五入”的取整方法是一个比较好的折中:继续维持相对高水平的招聘标准,同时适当的降低招聘的难度。

在某些场合,面试得到的观察值并不会总体偏低,甚至有时候会总体偏高。在这些场合下,“四舍五入”的策略是不合适的。比如,当信息流动不畅,而candidate又顶着一块金字招牌的时候,很多观察者很容易受到金字招牌的影响而得到高估(甚至是大大高估)了的观察值。又比如,对较低层级的程序员的面试一般都比较标准化,主要就是编程题,考察的能力也主要就是算法和写代码能力。标准化考核的一个与生俱来的问题是可以事先准备,有题库,可以刷题,体现在结果上就是“高分低能”。编程题也不例外,有LeetCode等各种题库,还有人提供培训服务。我去年就在我的另一篇文章中指出,LeetCode之类的题库就像是体育比赛中的兴奋剂,它可以提高在面试时的表现,但效果并不能长久维持。很多能通过编程面试的人一旦进入真正的工作中,就会写出bug百出的代码。这些bug如果出现在面试中,他们是绝对没有机会通过面试的。所以,对于以编程题面试来说,不但不能用“四舍五入”,反而应该适当的把观察值调低一些[2]。相对来说,“四舍五入”更加适用于那些“非标准化”的考查类型,例如,对PM和manager的面试。

“四舍五入”的另一个作用是对那些undersale的被观察者的补偿。面试中,有些candidate比较能sale,说的难听点,比较能忽悠、能吹,能把自己做过三分的事情说成五分、七分。而另一些candidate比较不太能“吹”,容易undersale自己。大多数有经验的观察者对于前一类的candidate的甄别能力都比较强,但往往对后一类的判断力比较弱。这是有原因的:那些把三分说成五分、七分的人更有可能拿到超过他们自身能力的offer,因此更有可能take offer;而undersale自己的candidate更有可能拿到undervalue自己的offer,因此更有可能拒绝offer。我们作为观察者,提高自己观察能力、观察准确度的一个途径是考查过去的样本,把自己在面试时候的判断跟一起共事工作以后的判断做比较。由于overvalue的样本更多,久而久之我们鉴别这类人的能力就有更大的提高。另一方面,我们身边undersale的样本数量总体偏少,因此我们鉴别undersale的candidate的能力提升得就不太多。“四舍五入”能帮助观察者纠正对undersale的candidate的判断。

“四舍五入”作为一种对观察值进行修正的策略会不会导致over-correction呢?这个可能性不是没有。但对是否over-correction的判断本身也是一个观察过程,也会必定无法给出真实值,只能给出一个观察值。只要是观察值,就会存在error和bias。常常是当我们对over-correction担心的时候,其实correction得还不够。有很多传统智慧都是鼓励over-correction的。比如帆船界有一句俗语,“When in doubt, take a reef”。很多关于unconscious bias的实验数据都指出,哪怕我们有意识地对unconscious bias做出补偿,我们仍然可能补偿的还不够。


[1] 不考虑其他因素,比如名额限制、组织架构变动等。
[2] 这是非常不幸的。这让我想起了前几年美国大学对中国学生的GRE成绩会打折处理,原因就是中国学生普遍使用题库刷题来提高GRE成绩,而少数不刷题的中国学生也不得不开始刷题,这样年复一年,GRE考试作为一个对学生能力的观察过程,在运用在中国学生身上时,得到的结果越来越偏高,导致观察者不得不把观察值进行人为调低。

阿里月饼事件: My Concurring Opinion

最近我在看前美国首席大法官William Rehnquist写的《The Supreme Court》。书里多处提到在一些案子里,有一些大法官另外写了一份concurring opinion。

维基百科是这样解释concurring opinion的:“协同意见书(英语:Concurring opinion),法律术语,源自于英美习惯法,是一种由法院中的法官撰写的法律意见书。当法官同意主要意见书的决定,但是他同意的理由与其他法官不同时,法官可以独立撰写协同意见书,以陈述自己的意见”。

关于最近的阿里月饼事件,我是同意阿里开除那几个员工的决定的。不过我同意的理由和官方给出的理由略有不同。所以以下也算是我的“concurring opinion”。

我认为这几个人的错误是不遵守游戏规则

写脚本这个行为本身并没有错(假设阿里这次秒杀月饼活动并未事先规定不可以用任何automation,以及阿里公司IT章程没有类似“未经授权,禁止使用脚本访问任何内部IT系统”的条款)。但阿里这次的秒杀月饼活动事先已经说清楚了,每人限三盒(一个订单)。这几个被开除的员工,最少的一个用脚本下了三个订单,也就是九盒。

既然规则已经说清楚每人最多三盒,无论秒杀系统是否enforce这个规则,所有的参与者都有义务去遵守。遵守规则不需要理由。如果一扇门上写着“Authorized Personnel Only”,就算门没有锁,我们也不可以推门进去。如果路口竖着一个stop sign,就算没有摄像头、没有警察、没有车,也应该停下后再走。如果一块空地上插着一个“Private Property No Trespassing”的牌子,就算周围一个人都没有,我们也不可以进去。

知乎上最近有个问题很火:“中国现在到底有多落后?”。在我看来,中国至少在一件事情还很落后:遵守规则。而且还形成了恶性循环:因为大家都不遵守规则,所以每个人都只能不遵守规则。具体例子就不举了,信手拈来一大堆。对规则的漠视早已深深的渗透在了大多数人的价值观里,整个社会笑贫不笑娼,不择手段获取利益是被普遍默许甚至鼓励的。还有一些人,虽然不以获利为目的,但喜欢通过挑战规则、打擦边球来体现自己的水平,还有围观的人拍手叫好。

一个国家,如果国民们都不遵守规则,那国民凭什么要求他们的政府遵守规则呢?“法治的意思就是指政府在一切行动中都受到事前规定并宣布的规则的约束”[1]。如果政府不遵守规则,那就没有法治,最后吃亏的还是国民们自己 。


[1] 哈耶克,《通往奴役之路》,第六章

我为什么不赞成压低级别

前两天读到一篇博客,作者是码工界的名人。作者在文章中写道:“(某公司)在招我的时候,努力的压低工资和职称,比我之前的职称还低,跟我说什么‘小公司的职称不算数’。被我断然拒绝,然后不得不给我加了工资,改口说那职称是‘为了我好’”。这个作者的具体情况我不清楚。不过总的来说,招人时压低级别的做法在国内外各家大公司里都挺普遍的。

Recruiter和hiring manager的常见说法有这么几种:

  1. “我们这里发展空间很大的,你来了以后只要做出成绩来,很快就可以升的”
  2. “给你一个低的级别是为了保护你,因为这样别人对你的expectation会低一点”
  3. “我们很看好你的能力,但我们这里升8级一般都要做出东西来才可以升”

这种压低级别的做法背后的原因很多。有些公司有几年特别火,就算是压低级别大家也还是排着队要去,那不压白不压。有些是recruiter和hiring manager的贪小便宜的心理在作祟,就跟那些淘二手货的人类似,无论卖家开价开得多低,他们总是喜欢再砍掉点。有些recruiter觉得先扔个low ball然后再慢慢往上抬会比较容易谈成。遇到这些公司和hiring manager,不去也罢,没必要糟净自己。

还有一种比较常见的情况是面试面下来hiring manager觉得这个candidate处于7级和8级之间,为了保险起见,就先给一个7级的offer吧。他们大概是担心万一给了8级招进来,结果工作一段时间以后实际表现出来的能力还不完全满足8级的要求。他们担心这样子会影响团队其他成员的士气,不但团队里其他7级的人可能就会觉得不高兴,也许其他8级的人也会觉得不高兴:“我的8级含金量十足,而他的8级水分好多”。很多hiring manager在可上可下的时候喜欢给一个低一点的级别,但在工资和sign-on bonus上多给一点,因为他们觉得级别是公开的,谁都看得见,但package是不公开的,给多一点也不会影响其他人的士气。

我自己作为hiring manager也遇到过好几次这种情况:一个candidate面试下来觉得可上可下,给8级还是7级都说得过去。我遇到这样的candidate,大部分时候都是给8级的。我觉得我应该给他们the benefit of doubt,应该给予他们信任,相信他们很快就能做成配得上8级的成绩来。我会对他们说:一部分interviewer觉得可以给你7级,另一些觉得可以给你8级,我决定给你8级,因为我相信你。

这种信任will go a long way。

举个我亲身经历的例子。那是四年多前,我手下来了个新员工。他一来就休了一个月的产假。他入职那天来了一天,然后就消失了一个月(微软当时男员工的产假是一个月)。换做很多其他manager,可能都不会同意的,他们可能都会要求这个新员工延迟一个月再来入职。但我同意了。我跟他说你去休产假吧,专心休,休好了回来再专心工作。后来他在我手下干了三年,去年我离开那个组以后他也离开了微软。这三年里他的工作非常出色,做的东西让我很满意、很放心,他自己也连续升级。我觉得我和他之间的相互信任很大一部分来自于我当初同意他刚入职就休产假,这让他相信我的确是have his best interest in mind的。

中国人有句老话叫做“士为知己者死”,说的就是这种信任。当然,在公司里做事情,不至于到了要出生入死的地步。但做事情本身弹性很大,尤其是在码工界,不管在哪个级别,想要cut几个corner不被人发现是很容易的事情。而且就算被发现了,只要念几声类似“Perfect is the enemy of good”、“minimum viable product”或者“Premature optimization is the root of all evil”这样的咒语就可以了,不但可以轻松过关,还能占领道德的高地。要让员工自觉自愿的go extra mile,不能靠物质奖励,更不能靠非物质奖励,还是要靠信任,让员工感到“老板是挺我的”,从而想要努力工作来回报这种信任。

我发现,对于那些可以给7级也可以给8级的candidate,如果老板用8级把他们招进来并告诉他们“虽然我们内部有争议,但我是相信你有8级的能力的”,大部分情况下这些candidate很快都能在实际工作中做出和8级相称的成绩。这也就是所谓的“皮格马利翁效应”。相反,同样的candidate,如果拿了7级进来,就算老板嘴上说的是“我相信你很快就可以升的”,但偏低的定级本身就透着一种不信任感的味道,让人心里嘀咕“老板好像不是很看好我”。这种微妙的情绪会产生深远的影响,就好像如果恋爱中的一方时不时会觉得对方并不是真的喜欢自己,那这段关系一般都不会走的太远。

Rest Area

我很喜欢这边高速公路上的rest area。

2016-09-11-blog-rest-area_2

跑在高速上,每次看到rest area那蓝色的指示牌,不管需不需要休息都很想进去停一下。每个rest area都像是一个小公园:有参天的大树,有绿油油的草坪,有picnic table。安安静静地,只听得到小鸟的叫声,风吹动树叶的声音,还有远处的高速上的川流不息。没有人声鼎沸,没有hustle and bustle。

Rest area翻译成中文就是休息区。不过美国的rest area和国内的休息区在功能设置上是完全不同的。Rest area的基本设施就只有厕所,只有个别的rest area在白天会有free coffee,其实就是附近过来的几个大叔大妈,在小亭子里摆上一些cookie和保温瓶装的咖啡。他们的咖啡的味道实在不怎么样,但cookie还算说得过去,郑轶嘉很喜欢,每次出远门路上都念念不忘要去rest area吃cookie。他们的咖啡和cookie虽然说是free,但桌上还是有个放donation的玻璃罐子,每次我们总会放一两块钱进去的。

2016-09-11-blog-rest-area_1

国内的休息区有加油站,有小卖部,能吃到焖肉面和盖浇饭,还能买到文虎酱鸭什么的带在路上解馋。在美国跑高速,如果要加油或者吃饭,是要下高速的,不过通常也不需要走很远,大部分时候下了高速的第一个路口就是加油站和连锁餐厅,所以也并不是很麻烦。我觉得美国的这种设置的经济效应可能会更好一些,能把高速上的客流引导到local economy里去,对增加本地就业机会更有帮助。另外,把加油、餐饮等配套设施和高速公路系统分开,能促进在这些配套设施上的竞争,进而提高服务品质,也能减少rent seeking和corruption的可能。

多年以前当我刚注意到rest area和休息区之间的这种差别的时候,曾经以为这种差别来自于国内交通系统的国营性质。直到后来我去欧洲自驾了几次,发现英国、法国、意大利等国家高速公路上的休息区都和国内的休息区很像。后来我想明白了:欧洲这几个国家的高速公路和国内的类似,都是有收费站的。而美国的高速没有收费站,上下高速都很方便,所以就不需要在休息区里提供餐饮和加油了[1]


[1] 我看到很多rest area已经提供EV充电了。

大声点听不见

我第一次来美国大概是十年前。

和很多第一次来美国的人一样,我当时也对这里马路上的秩序感到非常震撼:车是会让人的。无论是在西雅图市区还是华盛顿湖东边的郊区,行人过马路的时候右转车辆都是会停下来让行人的。另外,车与车之间也很和谐,很少有人加塞、强行并线。两条道并一条道的地方总是井然有序:左边的道进一辆,然后右边的道进一辆,然后再左边的道进一辆,大家都像是有一种默契似的。有时候路上堵车了,只见到长长的一条车龙安安静静的慢慢的往前挪,没有人忽左忽右的变道,一股心平气和的氛围。和很多人一样,我也问了这么一个问题:为什么?为什么这里和国内有这么显著的差别。和很多人一样,我给我自己找到的答案是:美国地广人稀。这个答案很合理:在国内,在上海、北京,行人那么多,车那么多,道路那么拥挤,如果也像在西雅图这边这样彬彬有礼的开车,肯定会寸步难行的。和很多人一样,我也给用纽约曼哈顿的为例来证明道路资源的稀缺度决定了开车的文明程度。

直到我来到了日本。

那次是在大阪,在心斋桥附近的一条繁忙的小马路上。往来的车辆络绎不绝,有送货的小卡车,也有出租车和私家车。路的两边不断的有要过马路的行人。路的中间画着斑马线,仅此而已,没有红绿灯,没有信号灯,没有挥着小旗子的交通协管员。往来的车辆时不时的会在斑马线前面停下,让一大批的行人穿过马路去。停在后面的车并不会拼命按喇叭,催促行人或者前面的车辆。行人也好像很有默契的样子,一批行人过完马路以后,后面再来的三三两两的就会停在人行道上等着,让车子可以过一批。等待中的行人都很从容的等着,因为他们知道,他们并不会需要等太久,很快就会有一辆车在斑马线前面停下,让这些已经聚集了一定数量的行人穿过马路去。那天我就在那些行人里。相比起刚刚到美国的时候感到的震撼,我当时对眼前大阪街头的这一幕感觉到的震撼更加强烈,它直接推翻了我之前很多年的观点。我在大阪、东京等日本大城市所看到的证明,在道路资源的稀缺的地方,马路上也仍然是可以秩序井然地,开车也可以是很文明的。

不单单是在日本的大城市,在欧洲的一些道路资源稀缺的大城市里,开车也是相当文明的。在米兰、苏黎世、伯尔尼的繁忙的闹市区,我过马路的时候车辆都会停下让我的。在英国、德国、法国和意大利,我在每一个国家都开过几千公里的自驾。遇到过堵车,遇到过修路。开过高速公路,开过小镇之间的郊区道路,也穿行于城市拥挤的街道。在这些国家开车的感觉和在西雅图开车的感觉很接近,很少按喇叭,很少有road rage,很少有想要对前面或后面或边上那辆车竖中指的想法。

2016-06-20-blog-loudroom

不争不抢就寸步难行,当每个人都有这样的预期时,这便成为整个社会的困境。

这就好像同样是满满一屋子的人,有的屋子里大家都很小声的说话,因为大家都很小声,所以每个人都只需要很小声就能让对面的人听到了。在大家都很小声的屋子里,每个人都很小声,因为大家都不想破坏这么好的氛围。如果偶尔有人大声说话,边上的人都会对着他看,把食指竖在嘴上让他小声,于是这个大声说话的人自然就感到了羞愧,记住了要把声音压低。而另一件屋子里,大家都在大声说话。因为大家都在大声说话,每个人都不得不提高了嗓门说话。有人想要喝止大家,让大家一起小声说话,但就算他大吼大叫还吹口哨,仍然没有人停下来听他说,因为所有人都在大声说话,没有人能听得见他的呼喊。这间屋子里有些人想要“从我做起”变得文明一些,于是他们开始降低嗓门说话。但他们的伙伴马上就朝着他们大喊,“大声点听不见!”

如果你问我,为什么第二间屋子里大家都很大声,我只能说不知道。但我知道肯定不是因为屋子里人多。因为同样是满满一屋子人,第一间屋子里的人说话都很小声。

抬头看到猎户座

我又回上海了。各位亲朋好友见谅,这次不一一拜访了,这次专门就是回来陪家里人。

记得去年回上海的那几天,正是背痛痛得厉害的时候。痛得最厉害的那两周,晚上睡觉都没法翻身,一换姿势就巨痛无比。以前经常听到美国人说lower back pain怎么怎么,以前都没当回事儿,心里想:不就是背痛么。那时候还以为lower back pain大概就跟晚上睡觉没睡好,早上起来落枕了一样。等到自己痛了才知道有多厉害。早上起个床要起一个钟头,都没法站着穿裤子。弯下身子穿个袜子都疼得哇哇叫。

偏偏那时候还要回一次上海。在飞机场安检,要脱鞋子。我只能让在边上,慢慢的慢慢的蹲下去,边上还要找个东西靠着,才能慢慢的慢慢的解开鞋带,再慢慢的慢慢的坐到椅子上,慢慢的慢慢的拽着裤管把脚提起来,慢慢的慢慢的把鞋子脱下来。然后再重复一遍另一只脚。过了安检,还要重复一遍同样的过程,把鞋穿上。

原本还以为因为背痛会连黄石的roadtrip都去不了了。后来从上海回来以后,看了正确的医生,吃了几个礼拜消炎药,背痛就好了。原来病因就是lower back那几节脊椎周围的筋膜发炎。拍了X光,确认椎间盘(美国人叫disc)没有问题,骨头也没问题,脊椎也没有错位。吃了消炎药(anti inflammation),过了几周就好了,黄石也去了,每天帐篷里钻进钻出。

背痛好了以后第一次坐飞机是感恩节去夏威夷。那天在飞机场安检,我一边脱鞋一边跟朱逢霖感慨,能自己脱鞋就是幸福啊。重要的事情要再说一遍:能自己脱鞋就是幸福啊。

经过了这次背痛,我算是深深的明白了这个道理:无病无灾,就算是很幸福了。很多人到病入膏肓的时候才想明白这个道理。那次背痛之后,我每天都觉得可以回到家里跟家人一起吃晚饭,吃完晚饭还能跟郑轶嘉一起玩一会儿,就算是很幸福了。

班还是要加,活还是要干,工资还是要涨,级别还是要升,新东西还是要学,钱还是要赚,有点子还是要去试,事业还是要有追求的。但就算维持现状,也该知足。我常常跟周围的人说,我们都要知足,我们中的很多人都已经属于美国甚至是华盛顿州收入最高的1%家庭了。占领华尔街运动针对的人里面,我们也是一分子。

干我们这行的,不用忍受风吹雨打、日晒雨淋,不用每天早出晚归,不用打卡,想什么时候去公司就什么时候去公司,想什么时候下班就什么时候下班,想翘一天班去滑雪就翘一天班去滑雪,有些人公司里休假还没限制,每年可以休四五个礼拜的假到处玩。我们这一行,除了有时候要on-call几天,除了常年看着电脑屏幕费眼睛,其他真的没啥可挑剔的。

平时朋友之间聊天,有时有人提到他有个大学同学去纳斯达克敲钟了,或者有人提到他的一个前同事现在在的某某某startup上市了,大发了一笔。说着说着会流露出觉得自己混得很so so的意思来。我说,我这两年想明白一件事儿:if we want to feel bad about ourselves, there are a lot of ways to be successful at that.

想要自己feel bad还不容易么,事业有成的可以羡慕别人事业更有成,嫁了个好老公的可以羡慕别人家小孩有出息,事业家庭都顺利的可以羡慕别人保养得好、身材不走样、皮肤不松弛。就是做到了微软的VP,照样可以feel bad:可以觉得自己的影响力还不够大。或者,自己原来手下一个老印,短短几年变成了自己的老板,而且还是CEO。遇到这种情况,完全有理由可以觉得自己很失败。

但我们这些人得要这么想:的确,山外有山,高人背后还有高人,但我们现在的生活,已经是大多数人想得到却一辈子都得不到的。所以要知足,要感恩。能和家人在一起,无病无灾,能自己系鞋带,就应该每天都感到满满的幸福。要记住那天晚上出去散步,抬头看到猎户座的那个moment。

2016-04-30-orion

What Digital Camera and Public Cloud Have in Common

This is a picture featured in the March 2016 issue of the Outdoor Photographer magazine:

2016-04-07-panorama

To take such a high resolution panorama picture, traditionally it needs a high-end large format or at least medium format camera. But this one was taken by using a handheld Canon EOS 1Ds Mark III with a Canon EF 24-105mm ƒ/4L IS USM lens at 50mm, which is, in layman’s terms, a mass market digital camera (although 1Ds Mark III is at the expensive end of that range). The composited panorama consists of five vertical images captured at ƒ/13 and ISO 400. We are seeing more such things in the digital photography world. Another example is the High Resolution mode of the Olympus OM-D E-M5 II camera. E-M5 II is a commodity camera: the sensor is smaller (Micro 4/3) and has only 16 megapixels. But it can shoot a 40 megapixel picture by shifting the sensor in half-pixel steps and capturing eight images over a period of one second. The moral here is, with the help of software, commodity digital cameras can achieve what could only be achieved by high-end cameras.

Replace “digital cameras” with “computer hardware” and that will be the spirit of the cloud computing. Cloud platforms, especially the public clouds like AWS and Azure, use commodity hardware to achieve what could only be achieved by high-end super computers and expensive networking devices. In this analogy, IBM’s mainframes and EMC’s storage systems are the large format and medium format cameras. Cloud platforms stitch together a bunch of commodity computers with the help of software, just like how George Lepp stitched together the pictures shot by a household DSLR, with the help of software, to produce a high resolution panorama pictures.

Having said that, in the digital photography world, there are still situations where we have to use high-end cameras. Take the panorama picture of the balloons as an example. If the balloons were some other fast moving objects, such as birds and buffalos, George Lepp’s technique wouldn’t work. He would have had to use a large or medium format camera to freeze all the motions in one single shot. We have seen similar situations in cloud platforms. There are still some situations where the computing has to be done in a single high-end computer. That’s why even in AWS and Azure, there are very high-end configurations of machines: Azure G-Series VMs come with up to 32 vCPUs, 448 GB of memory and 6.59 TB of local SSD space. The largest AWS EC2 instances are in the same neighborhood. However, local network speed is getting faster and faster: the best Azure VM type now supports 20 Gigabit network and AWS EC2 supports up to 10 Gigabit. The technology of 40 Gb and 100 Gb is already ready and 400 Gb is on the horizon. With faster Ethernet speed, more workloads can be scaled out, which wasn’t possible in the past due to the limitation of network speed.

When Code Review Becomes Annoying

Overall speaking, code review is useful.

From time to time, my reviewers did catch some bugs that I overlooked, or point out options that fell into my blind spot. Sometimes I learn new things in code reviews. For example, last year a reviewer suggested me use ThreadLocal<T>, which indeed would simplify my code a lot. Some code reviews aren’t the code review per se, when it’s more about a FYI: “Hi, I have written this code and I like you to be aware of and get familiar with it.” That happens when you are the only person in the team truly understand that piece of legacy code. Although such FYI type of code review isn’t that much helpful to the author, it’s still good to the team.

But sometimes code review can become annoying, especially when people spend time on things that (in my opinion) don’t really matter. For examples:

I understand there are differences, often very subtle or trivial though, between string vs. String, readonly static vs. const, etc.. But those differences don’t do any real harm. Explicit declaration, such as Stopwatch stopwatch = Stopwatch.StartNew(), doesn’t make the code harder to read[1] than var stopwatch = Stopwatch.StartNew(). String.Join doesn’t make the code slower than using string.Join. Putting using outside of the namespace block doesn’t make the code harder to work on. In addition, by default all versions of Visual Studio put using outside of namespace in the code it generates.

I really don’t like to spend time on those things in code reviews. I don’t think they matter to product quality and engineers’ productivity. There are so much more things that we wish we had more time to spend on to improve quality and productivity. Debating on those things are like debating whether to put one space after a period or two.

What people should do is to make sure that their team has collectively decided on what StyleCop[2] rules to turn on in their code base and get included in the build. Once that’s decided and has taken effect, there will be no debate any more: if the rules are violated, it will be a build error and we don’t submit code review until it at least passes build. Simple and clear.


[1] Readability is both objective and subjective. There is no doubt about that a line longer than 120 or 150 characters is hard to read and single letter variable names are hard to read. But whether Stopwatch stopwatch = Stopwatch.StartNew() is harder to read than var stopwatch = Stopwatch.StartNew(), that’s really personal.
[2] Or the equivalent of StyleCop in other languages.

Too Many Retries Erode the Quality

In one of the teams that I have worked in, our code was full of retries. To name a few:

  • When the code was looking for a storage account, it would retry up to 30 times when the storage account didn’t exist. The whole retries took 13 minutes.
  • When the code was looking for a setting value which didn’t exist, it would also retry 30 times which took 13 minutes;
  • When the code was trying to read an XML file from a file share, it would retry up to 30 times for 13 minutes when the XML file didn’t exist.

That was too much. When a system has too many retries for too many times all over the place, the worst consequence isn’t that it wastes time. The worst consequence is that it erodes the quality of the system in an irreversible way. I have seen some groups where people were used to simply adding more retries and retry for more times when they run into intermittent issues. Lots of genuine code bugs are intermittent in its nature. Adding retries will cover these bugs up. But over the time, as the code gets reused, as the system scales, the only way to maintain the same level of availability is to add more and more retries. It’s like only reinforcing the siding of the house when its frame is being eaten by termites. Adding retry is simpler and less costly than getting to the bottom of intermittent issues. It takes some courageousness to not go down the easier (but irreversible and poisonous) path.

My rule of thumbs for retry is that we should not retry, or only retry for very few times, in the following situations:

  1. AuthN/AuthZ failure
  2. HTTP 404 or similar error code indicating resource not found
  3. HTTP 400 or similar error code indicating bad input
  4. Timeout

In most of the time, if a resource is not found, it’s not found. Retry won’t help. The resource is not going to show up all of a sudden several minutes later[1]. In general I also avoid retry on timeout error. Timeout indicates something has become very slow. Maybe the database is too busy. Maybe the frontend is under high load. Retry on timeout will likely make things worse.

The situations where I think it’s necessary and useful to do some retries are:

  1. Network glitches, such as “System.ServiceModel.CommunicationException: The socket connection was aborted
  2. HTTP 500 or similar error code that indicates a server side error
  3. HTTP 503 or similar error code that certain systems use in throttling. Sometime the response will include some guidance for the client: whether the client may retry, how much time should the client backoff for, …

It worth pointing out that retry should be mainly used to smooth out glitches[2], rather than for handling outage. If a service/resource has problems for more than a few seconds, it’s an outage. When there is an outage, the caller should treat it like an outage: mark the operation as failure, write necessary logs, tell its caller that things have failed. Usually I frown when I see a code spend more than a few seconds to retry.

Another often debated topic about retry is where shall we put the retry. My take is: either as close as possible to where the failure happens, or as close as possible to the originator of the bigger operation. The benefit of putting retries close to where the failure happens is that you won’t have to worry about idempotency and side-effect too much when your code retry. But you have to be very careful with the footprint of the retry. Excessive retries in the lower level code can be amplified when it’s placed in the whole system.

Last but not least: do not have a default retry count and interval in your code base. In the examples provided above, they all retried 30 times for 13 minutes. That’s because they all use the internal Retry lib with default values for retry count (which was 30) and interval length. To make it worse, it spreads when people copy and paste code (they do!). Not having a default retry count and interval length will enforce the developers to make conscious choice every time about how many times they want the code to retry.


[1] Retry is different than polling. We use polling when we expect to see changes. It’s OK to spend several minutes or even longer to wait for things to happen.
[2] People also use other terms like “hiccups”, “blips”, “transient error”.

成功是失败之母

去年圣诞节我在纽约玩的时候很惊喜的发现那里的出租车都支持Apple Pay了。每辆yellow cab的前座背后都安了一个Apple Pay的”读卡器”,到了目的地以后,坐在后座的我只需要把iPhone靠上去,大拇指放在Home键上把指纹识别出来,支付就完成了。不需要把手机解锁,不需要打开任何app,也不需要扫码什么的,很方便。

不过美国的移动支付总的来说还是比国内发展的慢很多的。正如前阵子朋友圈里有人在说的,现在在上海出门基本上都能用手机支付搞定了,可以不用带信用卡了。美国的手机支付发展的落后的主要原因之一是信用卡太发达了。而且这两年有了Square以后,连卖几块钱一份冰沙的小摊都可以刷信用卡了。信用卡那么方便,自然就没有动力、没有需求去拼命搞拼命推手机支付了。

所以从某种意义上来说,成功是失败之母。一个社会、一个国家、一个市场,某个阶段发展得太好太成功,会增加它向下一个阶段发展的阻力。也许再过十年二十年,等到那时候回头看今天,或许我们也会看到在互联网和高科技的一些其他方面,中国今天获得的成功变成了今后十年二十年发展的阻力。

美国由于地广人稀,人力成本很高,所以最近几年非常积极的在往robotic和无人化上面靠:已经在很多超市普及的self checkout;Amazon的无人机送货;Boston Dynamics的机器狗;很多人家里的iRobot扫地机器人。在今年的国情咨文里,总统还宣布要支持和加快self-driving cars的开发和应用。Newark机场航站楼里的餐厅基本都没有服务员了,每张桌上都有一个tablet,吃饭的人坐下后在tablet上点单,吃完以后直接在tablet上刷卡买单。整个用餐过程中需要服务员的地方仅仅是把菜从厨房端出来。

中国的人力成本相对低很多: 钟点工小时工又多又便宜,骑着电瓶车的快递员满大街的跑,超市雇几个收银员也不算难事,连马路边上只有两个坑位的公共厕所亭都有个人专门负责收钱。罗振宇说,中国的电商比美国发达太多,是因为中国人多、人便宜。这话没错。但这可能也会导致中国的公司和用户缺乏动力和旺盛的需求去搞扫地机器人、无人机送货、self checkout、serverless restaurant和driverless car。梁建章在他的书里说,中国人口资源丰富是好事,但也可能导致”资源的诅咒”。我觉得他说得是有点道理的。