大声点听不见

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

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

直到我来到了日本。

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

不单单是在日本的大城市,在欧洲的一些道路资源稀缺的大城市里,开车也是相当文明的。在米兰、苏黎世、伯尔尼的繁忙的闹市区,我过马路的时候车辆都会停下让我的。在英国、德国、法国和意大利,我在每一个国家都开过几千公里的自驾。遇到过堵车,遇到过修路。开过高速公路,开过小镇之间的郊区道路,也穿行于城市拥挤的街道。在这些国家开车的感觉和在西雅图开车的感觉很接近,很少按喇叭,很少有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。梁建章在他的书里说,中国人口资源丰富是好事,但也可能导致”资源的诅咒”。我觉得他说得是有点道理的。

Do You Have A Reservation?

2015年的最后一天,吃完午饭我去配眼镜。

在美国配眼镜和在国内很不一样。在美国配眼镜,比如近视眼的眼镜,是要有医生的处方(prescription)的。像我这种近视眼的人,要先去看眼科医生(OD,Doctor of Optometry)做eye exam,根据检查结果,眼科医生会开一张处方单,上面写了我这个人应该戴多少多少度数的眼镜。而且这个处方单还区分普通眼镜和隐形眼镜的,有些处方单上写清楚了是只能用于普通眼镜的。然后我拿着处方单去眼镜店,自己选好镜框,眼镜店按照医生的处方帮我把眼镜给做了。眼科医生的处方有效期只有一年。一年以后如果还要再配眼镜,就要重新做eye exam拿处方。

这个过程听上去相当的繁琐。不像国内,哪要什么处方啊。我自己在国内那么多年配眼镜,除了小学五年级的时候配第一幅眼镜的时候去的是大医院验光,当时还滴了一天眼药水扩散瞳孔,之后基本上就都是”电脑验光”这样子搞搞就好了。不过好在美国很多的眼镜店都是有”坐堂医生”的,至少我去过的几家都有。一个眼科医生就把自己的诊所开在这家眼镜店里,平时的业务主要就是帮来配眼镜的客人验光开处方。比如我去的那家眼镜店,那个眼科医生叫Dana Kindberg,她的小诊所也是五脏俱全:有个前台负责接待和billing(包括insurance),有两个助手帮着做一些常规的检查,再加上她自己。拿了处方以后出来到店堂里面就可以直接配眼镜,付好钱等一个小时就能拿到配好的新眼镜了。所以其实是挺方便快捷的。

不过因为是2015年的最后一天,眼镜店里人特别多。因为很多医疗保险每年都有一两百块的额度可以报销配眼镜的费用,不用白不用,配一副备用的眼镜放家里也是好的。所以每年最后一两天眼镜店都特别忙。我去的时候是下午两点,眼科医生的前台说他们只有四点二十分还有一个空,而且是另外一个人cancel了以后空出来的。于是我就约了四点二十分的eye exam,回去继续上了会儿班,然后去幼儿园接了郑轶嘉,等到了四点二十回到眼镜店,验光、配了眼镜。

很多像我这样在国内生活了几十年后才来美国的人一开始都不太喜欢、不太习惯美国这种到处要预约的做法。我自己原来也不是很喜欢,不是很习惯。车子servicing要预约(oil change可以直接去),看病要预约,拍B超拍X光片要预约(也不是绝对的,我的家庭医生的诊所自带X光,上次背伤了就是当场拍的片子),国家公园里的campground要预约,去San Juan岛的车渡要预约,去Apple Store修手机要预约,帮郑轶嘉理发也要预约。不预约直接walk in的话八成是理不到发的,倒不是因为理发店都坐满了,而是因为当天来上班的理发师一整天都已经排满了。去很多地方,前台见到我的第一句话往往都是”Do you have a reservation?”

习惯了这种到处都要make reservation的社会以后,觉得这种做法其实挺高效的。从客户的角度来说,容易安排自己的时间,不用担心白跑一趟,也不用操心估算要花多少时间排队。否则,排队的时间是一个未知数,未知数一多,时间就很难安排。排太紧了,万一一件事情上因为花了很多时间排队而delay了,余下的每一件事情就都要往后推,也许还会浪费别人的时间。在一个大量实行预约制度的社会里,每个人的时间都有比较好的可预见性(predictability)。

大量实行预约制度对商家也是有益处的,能帮助商家很有效的安排资源,减少浪费,不会出现很多技师、服务员、销售员无所事事坐在店堂里的情况。预约制度就像一只无形的手,既帮助客户避开高峰时间,也帮助商家对客流和需求进行”削峰填谷”。”削峰填谷”的好处是很显而易见的:国家通过分时电价将一部分用电需求引导到晚上非高峰时间;很多旅游区的配套资源在五一、国庆长假期间大大超载,但在平时大部分时间又大量过剩,因此有很多人提议减少长达一周的长假,增加3-day weekend之类的小长假,增加带薪休假,对游客量进行”削峰填谷”。

Better predictability,more efficient resource allocation,less waste,所以总的来说我还是比较赞成广泛的实行预约制度的。

为什么应该增加男性的带薪产假

因为增加男性的带薪产假,获益的将会是女性,而不是男性。因为增加男性的带薪产假,将会减少女性在职场上的劣势。

中国的很多公司都只给男性两周的带薪产假,但女员工可以有三个月产假,超过一定年龄满足晚婚晚育标准的可以拿到四个月带薪产假。美国的情况也一样。微软之前一直是男性四周、女性十二周。今年微软调整福利了,变成男性三个月,女性五个月。很多其他公司也类似,尽管产假长度各有不同,但总体上都是女性产假比男性产假多很多。再放眼世界上其他国家,情况也基本如此(参见:https://en.wikipedia.org/wiki/Parental_leave)。

如果一个社会普遍只给男性两周产假,但给女性三个月或四个月,那么生育后代对女性职业发展的影响会远远大于对男性的影响。

两周产假也就相当于一个普通的带薪休假,相当于去国外玩了两个礼拜,回来上班以后,一两天就能把过去两周里没有看的邮件给看完了,一两天时间里就能跟上工作节奏。休两周产假对工作的影响微乎其微。休三个月或四个月的产假就完全不一样了。离开工作三个月或四个月再回来,可能连自己生小孩前最后几周写的代码都已经看不懂了。这三四个月里面,可能发生了reorg,可能有新的项目已经开始了,可能换了老板了,可能原来的设计已经改掉了。每个人又都那么忙,谁有功夫跟你一点点都解释清楚啊。休完三四个月产假回来,状态其实很接近一个刚入职的新员工,至少还要再花几个礼拜才能完全进入工作状态。

很多公司都是每年做一次绩效考评的。如果这三四个月的产假发生在那一财年的上半年,那还好,回来以后catch up了以后还有半年才到考评的时间。这半年好好努力,这一年受的影响可能还不算太大。但如果不巧不巧,这三四个月的产假发生在年中或更晚,那休完产假回来上班时,已经离考评不剩多少时间了。这么一点点剩下的时间里也做不出什么能够大书特书的事情来。那么那一年的考评就算是打了水漂了,基本上就拿个平均分,升职什么的等下一年吧。很多情况下,浪费的可能不止一年。很多老板知道手下女员工怀孕了以后就不给她们分派很关键的岗位了,因为怕她们哪天突然就进产房了,工作交接都没做完。如果再加上怀孕期间身体状态不好,再加上花在产检上的时间,很多时候生一个小孩会耽搁掉两年。

大部分的人生小孩的时候是在二十多岁或三十岁出头一点,工作的时间少则三五年,多的也就是十年上下。工作到这个阶段,耽搁掉一年两年的话其实是一个非常巨大的损失。这个阶段的人基本上面临着职业发展上一个不大不小的坎:比如要升Senior或Staff了,或者要从IC升Lead了,或者是要从一线升二线了。如果到了那个时间点那个坎没过去,接下去可能就要再等好多年。比如,一个女员工,如果那时还没升成Senior或Staff,等生完小孩,能够花在工作上的时间肯定是多多少少要减少的,之后她们在和那些还没生小孩、比她们年轻三四岁的同事竞争的时候,就要吃很大的亏。

相比之下,同龄的男性就没有这么大的劣势。他们基本上不会浪费掉什么时间。男性不会有孕期不适,不需要产检,产假也只休两周,家里还有父母帮着做家务,还可以请月嫂或钟点工帮忙,基本上工作上一切可以照旧,该加班加班,该出差出差。这就是为什么在较低层级的职位上,女性和男性的比例还不算太不平衡,但在很多公司很多行业,到了中高级经理层往上,女性的比例就大大减少了。原因就是因为很多女性因为生小孩而掉队了。如果男性的产假和女性一样长,女性掉队的情况至少是能够大大缓解的。

男性产假只有两周还会对女性的职业发展产生另一个隐形的负面影响:男性如果只休两周产假,就不能深刻的切身体会到带小孩的辛苦。

两个礼拜时间一晃而过,很多情况下妻子也还没有去上班,加上可能还有上一辈的老人来帮忙。在这两个礼拜里,换尿布、拍嗝、热奶、白天抱着睡、晚上哄睡、给小孩洗澡等诸多caregiving的事情,很多情况下还是被妻子或者来帮忙的老人做掉了。很多爸爸休了两个礼拜产假以后,还是不怎么会换尿布、不知道怎么让孩子入睡。没有大量的亲身体验,就不懂得其中的艰辛。没有经历过抱着孩子午睡一睡睡上一个小时两个小时抱到整个肩膀和胳膊发酸发麻抬不起来,没有经历过每天半夜里要挣扎起来喂一次夜奶,这些爸爸们因此也就不能够发自内心的感激妻子的付出。他们的观念可能就一直停留在这样的无知和误解上:”抱着睡有什么难的,我还巴不得天天抱着我儿子/女儿呢“,“为什么要抱着睡呢,为什么不把他/她放到摇篮里去睡”,“为什么要喂夜奶呢,就是因为我们一直喂夜奶他/她晚上才会一直醒过来的呀”,等等。

消除这些无知和误解的最有效的方法就是让爸爸自己动手带孩子,而且带上一段时间。我自己当时休了一个月产假。那时候朱逢霖已经休完了四个月产假,回去上班了。我的那一个月里,白天就我一个人在家里带郑轶嘉,晚上也是我起来给喂夜奶。那一个月里,我充分的体会了朱逢霖在之前的四个月里有多么的不容易。我相信,如果当时微软已经有三个月产假给男性员工了,我会休满三个月,从而对带小孩的艰辛体会更深。

2015-12-21-Paternity-leave

那些在两个礼拜的产假里没有学会怎么给小孩换尿布的爸爸,可能之后就再也不会去学怎么换尿布了。之后的一两年或更多的时间里,换尿布可能就都是妈妈的工作了。而且,由于这些爸爸没有学会怎么换尿布,偶尔换一下也换的笨手笨脚的,很多妈妈就索性把这事儿全揽过来了:“算了算了,我来换吧,你去把衣服叠一叠吧”。类似的,很多其他caregiving的活也引起类似的原因就都落在了妈妈身上:“算了算了,我来哄他/她睡吧,你去忙吧”,“算了算了,我来喂他/她吃饭吧,你去把碗洗了吧”。这样,在一个男性产假只有两周,而女性产假有三到四个月的社会里,女性不单单因为休产假造成了那一年两年的职业发展停滞,还在今后的两三年里都比男性承担了更多的caregiving工作,进一步造成了女性在工作上的劣势。

也许有人会说,哪怕国家的法律政策给了男性和女性同样多的产假,比如都给三个月,很多男的未必会休啊。这是绝对是有可能的。我见过很多人,他们每年的带薪年假也都没有休完。但给了男性和女性同样多的产假以后,至少有那么一部分爸爸是会休的。今天,也许有一部分的丈夫会有这样的借口:“我是想多休一点产假在家里帮忙的呀,但国家规定只给我们两周产假呀”。到了那时候,至少这样的借口就没有了。哪怕一开始几年里只有10%或20%的男性休满了三个月的产假,那也能促进社会风气和观念的转变。在我所知道的公司里面,Facebook是做的最好的。Facebook无论男女,都有4个月的产假。而且,相当多的Facebook的男性员工都休完4个月的产假的。这让我相信,如果国家的法律规定,所有的企业和政府部门都必须为男女职工提供相同时间的带薪产假,很快就会有很多男性愿意休更多的产假的。

我认为,在中国制定这样的法律,不但是有益的,而且应该尽快的制定和生效。否则,全面放开二胎的效果会大大打折扣:原先只生一个,就会对女性的职业发展产生这么大的影响,那现在要是生两个了,那工作基本上就算是毁了。这样的结果就是,很多职业女性要么不愿意生第二个,要么生了第二个以后就索性不工作了。无论是那种结果,最后都会导致放开二胎所要达到的劳动人口增长的目标无法实现。

德胜门

高晓松说,他小时候能从德胜门看到香山,后来就只能从德胜门看到西直门,而现在,在德胜门都快要看不到德胜门了。蛮有意思的,典型的北京人的调侃。

德胜门,听着好亲切的,因为我也算是北漂过一年,那时就住德胜门。严格来说是德胜门外大街,简称”德外”。对应的另一侧就是德胜门内大街,简称“德内”。那时候有人问我住哪里,我回答说”德外”的时候都觉得自己特神气。我在北京工程院那一年里就一直住那儿,每天早上走十分钟路去积水潭站坐地铁,每天就都会路过德胜门。我特别喜欢从德胜门前路过的那感觉,所以后来回了上海,有时候上班会绕一点点路,从南丹路的家里去港汇上班,我会从徐家汇的天主教堂前面过。

每天上班的路上都能看到一个特漂亮的东西,无论是山水还是宏伟的古代建筑,以那样的方式开始自己的一天,是一种特美好的感觉。

2015-12-11-lake-sammamish

后来到了美国,先是在Sammanish湖边上住了一年。每天上班都会沿着Sammamish湖往北开十几分钟,然后才接上繁忙的highway。那段湖滨路特漂亮。这大概也是为什么那条路叫做East Lake Sammamish Parkway的原因。好像在美国,凡是叫Parkway的都是风景有点漂亮的路,开着车经过就是一种小小的享受。郑轶嘉生出来以后我们就搬到了现在的家。现在每天从郑轶嘉上幼儿园的路上有一段路正对着Mountain Rainier,那高高的雪山,有时候半遮半掩的在云里雾里,有时候山顶耸入云里像是戴了一顶帽子,有时候万里无云,山上的积雪就闪闪的泛着金色的晨光。每天经过的时候郑轶嘉都会大叫:”爸爸,look,Mountain Rainier!”

我觉得郑轶嘉长大以后一直会记得他小时候每天上学路上看到Mountain Rainier那个moment,就好像高晓松记忆中的从德胜门看到的香山。

郑轶嘉坐飞机

我是到念高中时才第一次坐飞机,从西安回上海。朱逢霖第一次坐飞机是23岁。郑轶嘉才四岁,已经坐了四十几次飞机了:

  • 2012:西雅图往返Honolulu;西雅图往返San Diego;西雅图往返Calgary;西雅图往返上海,经停首尔;西雅图往返洛杉矶。
  • 2013:西雅图往返Las Vegas;西雅图往返纽约;西雅图往返Fort Lauderdale,经停休斯顿;西雅图往返罗马,经停法兰克福。
  • 2014: 西雅图往返旧金山;西雅图往返Tahiti,经停洛杉矶;西雅图往返伦敦,西雅图往返上海,经停东京;上海往返珠海。
  • 2015: 西雅图往返法兰克福;西雅图往返旧金山;西雅图往返Maui;再加上这个月底就要飞的西雅图往返纽约。

我们带着郑轶嘉去了那么多地方,动机其实很纯粹:就是我和朱逢霖我们自己想到处玩。我们家里没有这个条件,不像其它人家那样可以把郑轶嘉留在家里一两个礼拜,让国内过来帮忙的老人在家里看着,或者索性放回国内去放几个月。我们无论去哪里都不得不把郑轶嘉带着,包括好几次陪我们去旧金山搞申根签证。我们没有觉得想要通过旅行让郑轶嘉增长见识,至少不是现在这个年纪。这个年纪的小孩还没什么长期的记忆,比如我自己就只记得五六岁以后的事情。我们发现郑轶嘉基本上两岁之前的事情完全是不记得的。他24个月大的时候跟我们去了意大利,吃了很多pizza和意大利面,在威尼斯的圣马可广场上被一群鸽子抢手里的面包。这些事情后来问他,他完全不记得了。

2015-12-03-Yijia-Take-Airplans-0

郑轶嘉大概是在两岁到三岁之间开始记得一些事的。去年他30个月大的时候跟着我们去了Tahiti,跟我们去浮潜的时候看到了stingray,似乎就记住了。上个月去毛伊岛的水族馆,他一看到stingray就指着叫出名字了。他将近三岁的时候跟我们去英国,在伦敦的白金汉宫门口看到卫兵换岗,看的特别兴奋,告诉我们说他很喜欢看”叔叔打鼓”。回来后有一次在家里,看到了我们带回来的一个卫兵样子的冰箱贴,他就指着那个冰箱贴对我们说,那是”叔叔打鼓”。我觉得可能从现在起,从四岁往后,他应该基本上就都能记得了,以后的旅行可能会有更多增长见识、锻炼能力的成份了。

话说第一次带郑轶嘉坐飞机是他四个月大的时候去夏威夷。那之前我和朱逢霖还是满紧张的,不知道这么小的小孩出门在外会遇到什么状况。不过那次坐飞机基本还算顺利,就是郑轶嘉晕机吐了。所以之后我们带他坐飞机都会在随身箱里放一套备用衣服。尤其是飞机下降的时候我们会特别警惕,发现郑轶嘉有神情不太对劲的时候,就赶紧把呕吐袋拿在手里准备好。不过好像随着年龄增长,最近他很少晕机了,也许是因为坐得多,习惯了。也许他当时呕吐也并不是因为晕机,也许是因为小孩小的时候胃的贲门没发育好,机舱里气压低,胃里面东西就容易跑出来。大概和婴儿吐奶是个差不多的原理,我是这么猜测的。郑轶嘉倒基本上从来没有因为气压调整而觉得耳朵不舒服。我觉得那主要是因为从小就坐飞机,一年做十几次,早就习惯了。

郑轶嘉第二次去夏威夷就是上个月的事情了,已经过了四岁生日了。这次去夏威夷带郑轶嘉坐飞机,我和朱逢霖基本上已经非常轻松了。Checkin和安检的时候他会一直帮我们拉着那只随身箱。郑轶嘉非常喜欢那只箱子。一个原因是那只箱子的轮子的质量很好,万向轮,而且滚起来特别平滑、顺畅。郑轶嘉年纪还小的时候就喜欢推着这只箱子在飞机场里走,他总说那是他的箱子。现在他四岁够高了,就学我们的样子拉着箱子走,一路引来不少侧目。

2015-12-03-Yijia-Take-Airplans-1

这次从夏威夷回来,郑轶嘉上了飞机一坐下来就自己把安全带扣好,然后就催着我和朱逢霖:”爸爸,你和妈妈也要把安全带扣好”。机长广播说飞机要开始滑行了,请大家收好小桌板。郑轶嘉就马上把iPad合上,还跟我们说,”妈妈,我等到飞机飞平了再看,OK?” 听得我和朱逢霖都笑死了。飞机飞了一会儿以后开始广播,说开始提供drink了。郑轶嘉那时候虽然带着耳机,但广播一说要开始提供drink了,他噌噌噌就把耳机拿下来,把iPad合上收好,把小桌板上面收拾干净,然后转过头跟我们说“I am ready for drink”, 又把我和朱逢霖笑死了。吃好snack,他又看了一会儿Peppa Pig,就说”妈妈,我困了”,就把耳机拿掉,往朱逢霖腿上一趴,片刻就睡着了,连着睡了两三个钟头,连机上的晚餐也没吃,直到要下飞机了才被我们拽起来。郑轶嘉睡了我们就可以做我们自己的事情了,除了要经常帮他拉一下毯子,免得冻着。郑轶嘉睡着的时候朱逢霖看了两部电影,岩石强森演的《San Andreas》和刘青云、黄晓明演的《暴疯雨》,而我继续看我的书,然后写会儿blog,再看一会儿书。

郑轶嘉能像今天这样,也是有一个过程的。他小的时候坐飞机我们也还是挺累的。那时候他还不大会自娱自乐,飞机上地方小,他喜欢玩的Magna-Tiles摊不开,朱逢霖和我就只能轮流一本一本的给他讲书。他小的时候坐飞机也是会哭闹的。不过好在美国这边的航班上的小小孩普遍比较多。经常机舱里此起彼伏的有小小孩在哭。这样我们家郑轶嘉哭的时候我们也就没有那么愧疚。其它乘客里面,很多人自己也曾经有过带小小孩坐飞机的经历,所以特别能理解。我从来没有遇到过有哪个乘客对周围小孩哭闹有抱怨的。总的来说,整个氛围很宽容。郑轶嘉比较小的时候我们会把他的car seat也带上飞机,装在他的座位上,让他坐car seat里面。这样就感觉有点像坐在车里,他在car seat里面睡的比较舒坦,不容易东倒西歪。不过后来他长大一点了,我们就不把car seat带上机了,否则太拥挤、活动不便。

说到郑轶嘉的座位,美国这边不太好的一点是无论小孩年龄多大,如果单独买票有个座位,就要买全价票。不过两岁以下的小孩可以on the lap,那样就不需要买票。这也是我们在郑轶嘉两岁前去了很多地方坐了很多飞机的原因之一,一旦过了两岁就只能乖乖的给郑轶嘉买全价票了。不过一个很贴心很方便的地方是,无论小孩年龄多大,只要小孩是乘客之一,托运小孩的婴儿车和car seat都不要钱。所以我们到任何地方都是自带car seat,从来没有在租车公司花钱租过car seat。

这几年这么多趟飞下来,我和朱逢霖对于挑选适合小朋友的航班也找到了一些规律。主要的选择条件就是时间,尽量把郑轶嘉afternoon nap安排在飞行途中,他睡着了我和朱逢霖就可以轻松一点,干点自己想干的事情。遇到需要转机的,比如我们从休斯顿转机去佛罗里达,我们有时候会选那种中间间隔两三个小时,而且在转机机场停留的时间是early afternoon的,这样让郑轶嘉坐在婴儿车里推着推着就睡着了。另外,如果时间选在飞机上会供应一顿午餐或晚餐的,也会比较好。小朋友在飞机上有东西吃,不容易闹。总的来说,就是根据小孩的生活作息习惯选航班时间,顺势而为会比较轻松。当然,这样选航班可能就选不到最便宜的航班,每次都会贵一点,有时候三个人加起来要贵好几百,但为了一个比较好的旅行质量和体验,那也还是值得的。

郑轶嘉坐的这四十几次飞机里面,有好多是长途trans-continental的。下次再专门写一篇关于带郑轶嘉坐长途飞机和调时差的。

双职工生活

郑轶嘉五个月大的时候就送去托儿所了。

我们也是不得已,没有其它的办法。我们两个把公司的产假都用足了,朱逢霖还额外请了一个月无薪的产假,这样才对付了一开始的五个月。因为种种原因,我和朱逢霖的父母都没法来美国帮忙带孩子。只有朱逢霖的妈妈来过,但朱逢霖出了月子她就回国去了。那之后的四个月就只有我们两个硬扛着。

等我们两个都回去上班了,就只能把郑轶嘉送day care了。不心疼是不可能的,才五个月大啊,都还没断奶。奶都是朱逢霖泵出来冻在冰箱里,每天早上拿几包出来带去day care,她们白天化冻了热一下给郑轶嘉喝。郑轶嘉在这家day care待了一个月,我们找到了一个姓杨的住家阿姨,就把郑轶嘉放家里了。

主要原因是郑轶嘉在那家day care睡的不好。那家day care的条件不能和Bright Horizons的比。Bright Horizons有专门的infant的一大间教室,到了nap的时候关上门,里面安安静静地。那家day care就开在一间普通民宅里,里面大大小小的小孩都有。郑轶嘉那时候每天还是要睡三觉的。一间房间里大一点的小孩在玩,另一间里郑轶嘉睡觉多少是受影响的。

我和朱逢霖都特别重视郑轶嘉的睡眠。我们相信,成年以后的很多睡眠问题的源头来自于婴儿阶段的神经系统的发育和睡眠习惯、睡眠能力的养成。我们也相信,好的睡眠质量能让小孩的更有专注力。相比之下,我们对他什么时候会爬、会坐、会走、会说话、会自己potty等等相对没有那么的在意。

2015-11-30-Yijia-Nap

杨阿姨在我们家做了一年,做到郑轶嘉一岁半的时候。这中间朱逢霖的妈妈来过一次,待了几个月。朱逢霖的妈妈和杨阿姨差不多是同时走的,那时候Bright Horizons也正好有空位了。杨阿姨和朱逢霖的妈妈刚刚走的时候,我们一下子好不习惯。有了对比才深深的觉得她们在的时候生活好轻松的。至少家务活都不用做了:不用烧饭,不用洗衣服叠衣服,不用地毯吸尘。每天到家都有热乎乎的现成饭吃,脏衣服总是会洗得干干净净叠得整整齐齐的回到衣柜里去,水池里的脏碗也好像会自动的就干干净净的回到碗柜里去。

从那时到现在,两年多了,我和朱逢霖就一直是双职工生活。郑轶嘉这个月四岁了。这两年多里,我们仅有的帮手就是请了个钟点工,一个月四百,每周来两次,每次一两个小时,主要就是干些低频的家务,比如擦地板、吸地毯、清洁浴室和厕所什么的。要说不羡慕国内的人那是不可能的,国内的钟点工的工钱相对于我们在国内的工资来说便宜太多了,我们可以请一个小时工每天来做家务,还能把饭烧了。朱逢霖认识的一个印度人就因为这个原因回印度去了:在印度他能请一堆佣人。

家务都自己做,做做也就习惯了。而且还相对有点好处。比如郑轶嘉在厨房吃早饭的时候我就在边上顺便把洗碗机给unload了。这样总比郑轶嘉在吃早饭我在边上看手机好。郑轶嘉也学会了喝完牛奶把杯子直接放到水池里面。洗衣服叠衣服也变成了一项亲子活动。郑轶嘉特别喜欢帮我们把衣服从washer搬到dryer里面,还喜欢把dryer的门关上然后按”开始”按钮。干好的衣服我们经常喊郑轶嘉一起来叠。一开始是让他负责分类:把爸爸、妈妈和嘉嘉的衣服分来,各自堆成一堆。后来他看着我们叠衣服的样子也学着叠,喜欢叠自己的袜子,还不让我们插手。如果这些家务都被钟点工或者过来帮忙带孩子的爷爷奶奶给做了,小孩倒也就没有这样参与的机会了。

2015-11-Yijia-Socks

其实在美国的中国人家庭,大部分的都有父母过来帮忙的。很多家里是爷爷奶奶半年,接着外公外婆半年,然后再爷爷奶奶半年,这样连续不断没有间隔的。还有些家虽然不是不间断的,至少也是每年有半年是有一方的父母过来帮忙的。说不羡慕那是不可能的。有爷爷奶奶或外公外婆在,很多时候可以轻松很多。我和朱逢霖经常会生出这样的感慨来:出去吃饭,有老人在的话可以帮忙看一下,我们自己可以吃顿安稳饭;晚上家里要是有个老人在,我们两个就可以出去,听个音乐会看个球赛什么的。虽然federal law和华盛顿州的法律都没有强制规定,但美国这边的惯例是不可以把12岁以下的小孩单独留在家里的。如果被发现被举报,最坏情况下,小孩是会被带走的。虽然说可以请babysitter,但一方面请一个晚上babysitter也要好几十块钱,另一方面babysitter毕竟不是亲人,小孩小的时候突然要跟一个陌生人待一个晚上,心理上还是满难的。包括那次去Las Vegas玩,晚上我们也只能留一个人在房间陪郑轶嘉,另一个人去看show。

所以没有父母在这边帮忙,夫妻两个会少了很多单独相处的时间,时间久了的确会有种感觉,就觉得自己整天不是忙工作就是围着孩子转。我和朱逢霖很早就预见到和意识到这个问题了,我们想了一些办法来弥补。比如说,我们约好每个月要找一个下午一起翘班出来,吃顿好吃的午饭,看场电影。郑轶嘉上的那家幼儿园,Bright Horizons,也有一个Parents Night Out的项目:每隔两三个月,这家幼儿园都会选一个周六,从下午四点到晚上十点,家长可以把小孩放在他们那里,他们提供小朋友晚饭,还配他们玩。因为是小朋友平时天天都去的幼儿园,老师也是平时的熟面孔,所以没有陌生感。我们觉得这个项目还挺好的。

双职工家庭没有老人帮忙,工作日的晚饭是个难题。我和朱逢霖后来摸索出来一套对我们家效果不错的做法。

首先,我们的电饭煲是可以定时的。早上出门前把米和水放好,定时定在17:30开始煮饭,这样到家就有新鲜出炉的热腾腾的米饭吃了。这样要好过早上时就把饭煮好,那样的话要保温保一天,到晚上吃的时候口感就不大好了。如果等到晚上到家再开始煮饭,那吃到饭就要很晚了。所以,能定时的电饭煲是双职工家必备的一个神器。另一个神器是慢炖锅。慢炖锅可以炖牛肉羊肉鸡肉什么的。一方面慢炖锅炖的比煎炒出来的要健康一些,吃着健康,油烟也少,另一方面慢炖锅能把肉炖酥了,否则如果要做个牛肉炖土豆,等到回到家再做,要么是煮不烂,要么就得等很久才能开饭。

除了使用可以定时的电饭煲和慢炖锅以外,为了能到家后尽快能吃上晚饭,我们家的菜谱也因此优化了,都是以容易准备容易烧的菜,但同时也兼顾了口味,使郑轶嘉有食欲,能多吃一些。我们做的比较多的是鱼。鱼容易做。我们一般早上出门前从冷冻室里拿一条鳊鱼或一袋带鱼出来,放在冰箱上层的冷藏室里化冻。这样做的好处是不用晚上到家再化冻,否则要么要花很多时间,要么就要用微波炉化冻。我们都觉得微波炉还是要尽量少用。鱼在冷藏室里化冻了以后,晚上我们一到家,第一件事情就是把鱼给蒸上,然后再搞蔬菜。蒸鱼不需要太多关注。煎炒的菜,时间长了会烧焦。蒸的时间稍微多了一点也问题不大,只要锅里水足够不蒸干掉,鱼是不会蒸焦掉的。

基本上我们现在每周五天工作日,一般在家里吃四天,到了星期五会在外面吃。我们基本不买外卖。我们是觉得外卖的东西不放心。倒也不是担心食品安全。美国的食品安全总体来说比国内的要好一点。但饭店里烧出来的菜,重油重盐的,不健康,能少吃点尽量少吃点。我和朱逢霖在这方面的观念是很相似的。我们也都很喜欢吃那些很好吃但不太健康的东西,比如烤羊肉串,小龙虾,水煮鱼,红烧肉,火锅,腌笃鲜,clam chowder,牛排。但每个人就只有这么一点点quota可以吃不健康的食物,超过quota就会三高就会影响健康。所以我们觉得把quota用在外卖的晚餐上是不太划算的。我们现在晚饭自己烧,牛肉都从Whole Foods买有机的(我们家基本不吃猪肉),鸡蛋无论是在Whole Foods、QFC还是Costco买都是买有机的,蔬菜也尽量是有机的,烧的时候少盐少油少高温。这两年我和朱逢霖体检的各项指标都正常,自己做饭做的比较健康是原因之一。

其实没有老人在这边帮忙,累是累了一点,不过也省掉了一些其它的烦恼。经常听身边的人说,也经常听朱逢霖说她在华人或mitbbs上看到,老人在这边帮忙带小孩,和孩子爸妈之间起了观念冲突。另外一些有老人帮忙带小孩的家庭里,老人太宠小孩了,小孩养成了一些不好的习惯,比如老人追着小孩喂饭之类的。这其实并不是在美国的中国人家庭独有的。在国内,和老人在同一个城市的,老人经常来帮忙的,也是类似问题的情况。我们家有点”因祸得福”的是,因为老人都来不了,也就不存在这些困扰了。

因为没有老人帮忙,郑轶嘉上托儿所也上得比较早,一岁半就上托儿所了。很多有老人帮忙的家庭,一般会等到两岁或三岁才送托儿所。我记得看到过一份研究报告,说小孩在一岁到两岁之间开始上幼儿园是最有利于小孩的社交能力和心智发育的。送托儿所送的晚的,可能就少了很多学习怎么和其他小朋友互动的机会。送幼儿园送的晚,一开始的几个礼拜适应起来也会更难一些。

双职工没老人帮忙,累是挺累的。不过在美国这边的中国人家庭,还有不少是只有一个人工作的。少一份收入,也挺累的。最幸福的当然是两份收入,还有老人过来帮忙。不过生活就像打牌,抓到手里的牌有好有坏,如果已经不能换牌了,那就用心把手里的牌打好。

After Automation Ate Testing

Huseyin Dursun, my previous manager, recently wrote a post “Automation eats everything …”, in which he pointed out that manual validation has been eliminated and technology companies are no longer hiring engineers exclusively for testing role. That’s exactly what happened last year in my group, Microsoft Azure. We eliminated test and redefined dev and now we only have software engineers, who write both product code and test code.

Now we have eliminated manual validation and all tests are automated. What’s next? My answer is: more automation. Here is a few areas that I see where we are/will be replacing other human work in the engineering activities with software programs.

1. Automation of writing test automation

Today, test automations are written by engineers. In the future, test automation will be written by software programs. In other words, engineers will write the code which writes test automation. One technique to consider is the model based testing. The idea of MBT has existed for nearly two decades and some companies (including teams in Microsoft, including my own teams) have tried and have got some successes. But by and large, it’s very under-used, mainly because other things aren’t there yet, like the scale, the demand, the maturity in other engineering activities[1], the people, etc..

Another direction that people have been pursuing for at least a decade is the traffic bifurcation. The idea is to run the test instance as a shadow copy of the production instance, duplicate the production traffic to the shadow copy and see if it handles it in the same way as the production copy does. The bifurcation could be real time, or more in a record-and-replay fashion. Twitter’s Diffy is the latest work that I have seen in this direction. I guess there is a long way to go, especially when the SUT is very much stateful and its state has strong dependencies with the states in other downstream systems.

2. Behavioral contract enforcement

Using contracts to define system boundary and doing implementation against contracts is now very common. However, our contracts are mostly about the data schema: the API signature, the structure of the JSON object in the input parameters and response bodies, the RESTful API URL, the WSDL for XML Web Services, file format, response codes and error codes, … These contracts don’t carry much information about the behaviors: how will the entity transit through its state machine, whether an operation is going to be idempotent, whether I must call connection.Open() before doing anything else with it, etc.. In particular, the behaviors related to time. For example, this asynchronous operation is supposed to complete within N minutes; the system will perform this recurring operation every X days; …

Today the behavioral contracts are mostly written (if ever written) in our natural languages in design specifications. The enforcement of such behavioral contracts are done in automated test cases. But there could be some fatal gaps in today’s way. Our natural language is ambiguous. Test cases may not cover 100% what’s written in and implied by the design specification. A more fundamental challenge is that the intention of the automated test cases may drift away as time goes by, meaning: our test automation code use to be able to catch a code bug, but after test code changes and refactoring, one day it will no longer be able to catch the same bug. I don’t think we have a good way to detect and prevent such drift.

I believe the direction is to write the behavioral contract with some formal language, such as the TLA+ specification language created by Leslie Lamport. In a presentation last year, he explained how TLA+ works and how it’s used in some real work. It seems pretty intriguing.

3. Automation of the analysis

In my previous team, as we made the automated tests faster, we found that now the long pole became the time human spent to make sense of the test result. So we developed some algorithms and tools to help us: 1) differentiate whether a failure is a new regression, or just a flaky test, 2) which failed tests are likely to share the same root cause. That was very helpful. In addition, we plan was to totally get rid of signoffs and let the software programs to make the call most of the time.

4. Automation of the workflow

Ideally once my code has left my desktop, the entire desktop-to-production journey should be led by software programs with no human participation (except for intervention/override). Today some companies are closer to that dream (e.g. Netflix’s Spinnaker) and some other companies are farther away. Some smaller/simpler products may have already achieved it, but it remains a challenging thing for complex products. Today CI/CD is a lot more common in the software industry than ten years ago. But in my eyes today’s CI/CD tools and practices more like the DHTML and AJAX things circa early 2000’s. The jQuery/Bootstrap equivalent in CI/CD has yet to come.


5. Integration test in production

Besides replacing more human work with software programs, there is one more thing that we can do better in the test engineering: eliminate the test environment per se and perform all integration tests in production[2]. Integration test is an inevitable[3] phase between passing unit tests and getting exposed to real customers in production. Traditionally in integration tests, the SUT and most of its dependencies runs in the lab that are physically separated from the production instances. There are several big pain points in that approach: a) fidelity[5], b) capacity, c) stability, d) support[6]. Doing integration tests in production will make all these problems disappear. Needless to say, there are some challenges in this, mainly regarding product architect, security and compliance, isolation and protection, differentiation and equality, monitoring and alerting, etc.. I guess next time I will write a post about “The Design Pattern of Integration Testing in Production“.


[1] For example, a team should invest in other more fundamental things like CI/CD before investing in building the model and doing MBT.
[2] “Testing in production” is a highly overloaded term. Someone uses it to refer to A/B testing. Sometime it means a late stage quality gate where the new version is rolled out to a small % of production and/or exposed to a small % of customers. “Integration test in production” is different on two things: i) it’s for low quality code that is still under development, ii) it doesn’t get exposed to customer.
[3] There are some strong opinions against integration tests. The lines like “integration test is a scam” help highlight some valid points. But practically we shouldn’t throw the baby out with the bath water. I am strong believer of “pushing to the left” (meaning: put more tests in unit test and find issues earlier) but I too believe integration test has its place in the outer loop[4]. Even though in the hindsight it might be very obvious that some bugs could have been caught by unit test, it would be a totally different thing when these bugs were unknown unknown.
[4] Outer Loop is defined as the stage between when an engineer has completed their check in and when it has rolled out to production. Depending on the product, this could mean App Store deployments (Mobile) or worldwide exposure (Services and modern Click to Run applications).
[5] Lab is different than production in many ways: configurations, security settings, networking, data pattern, etc. Those differences often hide bugs. Lab doesn’t have all the hardware SKUs that production has, which significantly limits how much we can do in the lab in hardware related testing (e.g. drivers, I/O performance, etc.).
[6] Let’s say the SUT depends on another service Foo. So traditionally in the integration test, we also have Foo instance(s) running in lab, too. When the lab instance(s) of Foo has any issue, the team of SUT will need the team of Foo to help check/fix. But that would be a lower priority for the team Foo, compared to the issues in the live site (production). Plus, the SLA (service level agreement) for lab instances is usually less than 24×7, but we want our integration tests to run all the time.