2012年6月16日星期六

HTTP 状态码详解

最近看《REST in Practice》,发现 HTTP 如此之多的状态码都有各自的含义,要准确使用并不难,但现实当中很少人能够做得到。大多数人熟悉的状态码就那几个,平时也不会去阅读 RFC 2616,结果反复使用的也就是那几个状态码。其实很多 REST 中可能遇到的情况,在 HTTP 状态码中都已经有考虑到,不需要自己去发明新的状态码,也不需要在 header 或者 body 自定义错误信息。

在说状态码之前,首先建议大家还是先阅读一下 RFC 2616 中的相关章节,看看已有的状态码描述都是什么。我相信有部分状态码是你看了描述也不知道用来干什么的,这时候就需要有更具体的例子来告诉你怎么用了。(我准备详细说的是那些比较少人知道但又实际上应该被更广泛使用的状态码。)

2xx

200 OK

所有人都知道 200 OK 是什么。这估计是最经常被滥用的状态码。很多人在应该使用其它 2xx 状态码时都选用了 200 OK 来表示。

201 Created

如果你在设计一个 REST API,或者一个 CRUD API,当你使用 POST(或者 PUT)成功创建一个新的资源后,服务器应该返回 201 Created 同时在 header 的 Location 字段给出刚刚创建好的这个资源的 URI。

例如说,如果你使用 POST 请求通过 \comments URI 创建了一个新的评论,那么服务器应该返回 201 Created,同时带上形如 Location: \comments\1234 的字段表明新创建的评论的 URI。

202 Accepted

如果服务器在接受请求后,需要进行一个异步处理才能有结果,并且觉得不需要让 TCP 连接保持到结果出来再返回,它可以返回 202 Accepted,意思是请求已接受,但没有立即可返回的结果。

204 No Content

在一个 REST API 或者 CRUD API 里面,当你使用 PUT 成功更新一个资源后,如果服务器完整接受了客户端的更新,没有拒绝也没有额外更新,那实际上是不需要返回任何东西的,因为现在客户端和服务器端已经拥有完全一致的状态。在这种情况下,服务器可以返回 204 No Content,同时 body 为空,客户端就知道它的状态已经跟服务器端同步了。

206 Partial Content

断点续传和多线程下载都是通过 206 Partial Content 实现的。

请求的 header 必须包含一个 Range 字段,表明自己请求第几个字节到第几个字节的内容。如果服务器支持的话,就返回 206 Partial Content,然后使用 header 的 Content-Range 指明范围,并在 body 内提供这个范围内的数据。

3xx

301 Moved Permanently

永久性重定向。目标由 header 的 Location 字段给出,同时 body 中也应该有指向目标的链接。新请求使用的方法应该和原请求的一致。如果用户使用 HEADGET 以外的方式发起原请求,客户端在遇到 301 Moved Permanently 后应当询问用户是否对新的 URI 发起新请求。

302 Found

临时性重定向。

这应该是浏览器实现最不符合标准的一个状态码了。理论上,除了临时性这一点,302 Found301 Moved Permanently 应该是完全一样的。然而实质上,很多浏览器在遇到 302 Found 后就会使用 GET 去请求新的 URI,而无论原请求使用的是何种方法。由于这种现象的普遍存在,使得这成为了一个与书面标准相违背的事实标准,新的客户端在实现时很难选择应该遵守哪一个标准,所以 RFC 2616 专门新增了 303 See Other307 Temporary Redirect 两个状态码来消除二义性。

303 See Other

临时性重定向,且总是使用 GET 请求新的 URI。

304 Not Modified

如果客户端发起了一个「条件 GET」,同时资源确实没被修改过,那么服务器端就应该返回 304 Not Modified,同时 body 不包含任何内容。

所谓的「条件 GET」,是指 GET 的 header 带上了 If-Modified-SinceIf-None-Match 字段。这两个 header 就是「条件」,如果条件符合了 GET 就应该正常执行,否则就应该返回 304 Not Modified,以便告诉客户端它想要请求的资源在上一次请求之后没有被更新过,客户端可以继续使用之前的版本。

307 Temporary Redirect

临时性重定向,且总是使用原请求的方法来进行新请求。

4xx

400 Bad Request

服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。

401 Unauthorized

请求未授权。如果请求 header 没有 Authorization 字段,服务器端应该在返回 401 Unauthorized 的同时在 header 中用 WWW-Authorization 字段指出授权方式,以便客户端带上登录信息重新发起请求。如果 Authorization 字段已经存在,则表明登录信息不正确。

402 Payment Required

需要支付。这是一个在任何浏览器中都没有被实现的状态码,仅预留将来使用。

百度曾经有一个部门印过一批背上写着 402 Payment Require 的衣服,并且开玩笑说这批衣服最适合在互联网企业员工讨薪时穿。

403 Forbidden

禁止访问。即使使用 Authorization 字段提供登录信息也会得到相同的结果。

如果客户端使用 HEAD 以外的方法请求,403 Forbidden 必须同时在 body 中返回禁止访问的原因。如果原因不能够公开,则应该使用 404 Not Found

404 Not Found

找不到如何与 URI 相匹配的资源。服务器无需指出资源是临时性不存在还是永久性不存在,但如果服务器端知道该资源已经被永久性删除则应该返回 410 Gone

404 Not Found 是服务器端在不愿意提供理由的情况下拒绝提供资源的最佳借口。

405 Method Not Allowed

请求的方法被拒绝。

如果你有一个 REST API 或 CRUD API 被设计为只读,那么在遇到 PUTPOST 或者 DELETE 方法时服务器端都应该返回 405 Method Not Allowed,同时在 header 的 Allow 字段说明允许的方法(如 GETHEAD)。

409 Conflict

冲突,且需要用户手工解决。

如果你使用 git(或者其他源代码管理软件),你已经知道「冲突」是什么了。409 Conflict 通常发生在 PUT 请求时,如果要更新的资源已经被其他人更新过了,你再更新就可能产生冲突。

410 Gone

如果服务器端将此资源标记为已被永久性删除,则应该使用 410 Gone 而非 404 Not Found,其用意在于告诉客户端资源是被有意删除的,而且删除是永久性的,客户端不应该再保留这个 URI 的链接。

举例来说,你有一个 REST API 或 CRUD API 用于向用户提供优惠信息。有一则优惠的 URI 是 /promotions/1234,但由于优惠活动已经结束了,所以这一则优惠信息不再有效且应当被永久性删除,那么这时候服务器端就应该让该 URI 永远返回 410 Gone 了。

412 Precondition Failed

条件判断失败,操作不会被执行。

在解释 304 Not Modified 时提到了「条件 GET」的概念,但「条件」本身也可以应用于非 GET 请求,这时候如果条件判断失败服务器端就应该返回 412 Precondition Failed,同时拒绝执行客户端请求的方法。

条件请求可以被看作是一种乐观锁。它不需要服务器端有任何逻辑判断操作是否存在冲突,服务器端只要记录资源的时间戳(或其它版本信息)即可。

5xx

500 Internal Server Error

最常见的服务器端错误。

503 Service Unavailable

服务器端暂时无法处理请求(可能是过载或维护)。

返回 503 Service Unavailable 的意思是当前的状况是临时性的,客户端可以稍后重试。服务器端可以在返回时通过 header 的 Retry-After 字段告诉客户端多久后可以重试。如果不提供这个字段的话,客户端应当把 503 Service Unavailable 等同于 500 Internal Server Error 处理。

总结

在看完这篇文章后,你有发现经常用错的状态码吗?如果有的话,将来在设计 REST API 或 CRUD API 时就应该改过来。由于状态码和 header 字段数目众多,所以我建议一般用户尽可能复用主流的 REST 框架或 CRUD 框架,而不要自己重新实现一遍。

如果你喜欢这篇文章,欢迎订阅或者捐赠。如果我有时间的话,我会再写写常见的 header 字段详解。

2012年6月9日星期六

向我的博客捐赠

阮一峰一年前说他的 AdSense 账号被封了,所以尝试接受捐赠,并且说一年后会公布收入详情的,不过至今仍未公布。考虑到现在支持小额支付的平台越来越多,所以我决定也试试接受捐赠,看看是否能带来收入。

看了几个不同的平台后,发现最简单易用的还是 Gumroad。有些专门针对内容收费的平台(如 ReadabilityFlattr),需要读者先去注册,然后在阅读过程中支付。考虑到我的读者里面没有多少比例可能注册过这些网站,这种平台首先被否决掉。至于专业做小额支付的平台,我觉得 Gumroad 是界面最好看流程最简单的了——你只要填个邮箱和卡号就可以支付了。当然,Gumroad 也有不如意的地方,那就是它不支持 PayPal 支付,估计是因为再加上 PayPal 手续费它就没有利润空间了吧,但这会使得不愿意提供信用卡信息给 Gumroad 的人拒绝支付。

如果你觉得我博客提供的信息对你来说有价值,你可以使用我的 Gumroad 链接进行捐赠。Gumroad 还有一个优势是可以设置价格为 n+,最终买家可以输入任何大于 n 的价格进行购买。我的捐赠链接设置为 $1+,大家觉得给多少合适就填多少。

2012年6月8日星期五

关于「如何追男生」的回答摘要

之前写了《关于「如何追女生」的回答摘要》,然后就有人问我有没有反过来的版本,所以我决定把 Why Men Love Bitches 的读书笔记整理出来写一篇文章。

先说说女人跟男人看待这个问题的本质区别。看 PUA 的资料,你会发现一切方法论皆以扑倒为终结点,随后的事情大家都觉得是不需要教的。但是给女人看的书就不一样,如果吸引男人的兴趣只是内容的一小半,另外一大半则是关于如何保持男人的兴趣。(我之所以感兴趣看 Why Men Love Bitches,也是因为好奇后面这一部分内容,因为 PUA 资料都不会覆盖到这些话题。)需要注意的是,这本书是假设女人采取 submissive 姿态的,所以如果你习惯了以很 dominant 的姿态来对待男人,这本书里面的部分观点对你来说并不适用。

自信

自信这一点是性别无关的,所以无论站在男人的观点来看还是站在女人的观点来看,自信都是放在第一位的。我觉得英文里面描述「自信」最好的一句短语是「comfortable in one’s own skin」,展开的解释比中文抽象的「自信」二字要具体多了:

表现出对自我清晰了解而带来的自信,没什么能让你感到不适。

自信跟盲目自大的区别就在于「对自我清晰了解」,因此要做到自信首先要增加对自我的了解——什么是我的强项,什么是我的弱项。对于强项,你应该尽可能多的发挥出来,尤其是在能够表现你特质时;对于弱项,你不应该表现出有任何的安全感缺失,就算别人指出了你也能坦然承认不会反应过度。

对于女人来说,缺乏安全感是很常见的,但为了表现出真实的自信,这又是一个很有必要解决的问题。通常的安全感缺失来源来自竞争对手(例如对方的前任),这时候如果你表现出受到威胁了,你的吸引力就会消失,同时你还帮助了你的竞争对手。

书中说,为什么大多数女人要到 30 岁后才能达到 sexual peak,那是因为到她们要到那个阶段才开始有足够的安全感,或者是意识到自己其实是不需要跟任何女人竞争,然后才能轻松地表达自己喜欢什么和不喜欢什么。但因为能做到这一点对男人来说是个 turn-on,所以显然你不会希望自己等到过了 30 岁然后克服安全感缺失。

满足男人成就感

这在书中也是一个很重要的话题,所以说这本书适合 submissive 的女人看,然后驱动男人在 dominant 的同时获得成就感。由于征服是人类本能,所以并不是说你应当可以刁难谁,而是你需要让他通过征服的过程获得满足感,因为这才符合人性。只要他觉得他对你来说还是 sexually desirable 的,同时他觉得自己还有机会,他就会继续接受新的挑战。

不要侵犯男人领地

男人的「自由」也就是他的「领地」。他想什么时间去哪里做什么,这是他的自由,你不应该八卦。一旦问了,就是侵犯对方领地了。就算你安全感缺失,有些事情你很想知道,你也应该控制住自己,因为在他爱你爱到一定程度之后他会很乐意主动告诉你这些事情。如果你想抛弃一个男人,你可以反过来使用这条规则。在他感觉到窒息的时候,他自然会远离你。

赞美而非唠叨

赞美是最好的调教方法,而唠叨则是毫无疑义的。不要说「你以前会送花给我的」,而应该在他送花之后说「这是我见过最美的」。如果男人请你吃饭,你要赞美食物或者餐馆。(如果真的不好吃,就别作任何评价。)无论如何都不要尝试通过唠叨来解决问题,因为一旦某一件事情你重复说三次,你就变成他母亲了,而他就会表现出反叛精神。

保持吸引力

PUA 的目标很单一,甚至可以说大多数男人的目标都很单一,那就是扑倒。所以作为女人总是会很在意如何保持吸引力。其中一个方法是,男人想要的东西不要一次性满足他,而必须一点一点提供给他。在这个过程中,你可以让他更好地了解你,慢慢地发现你的特质,他会发现你还有更多他想要的东西,然后他就会想要继续在你身边。

如果你发现他开始对你丧失兴趣了,那意味着你需要去寻找一件比他更能让你充满激情的事情。只要有一件事情对你来说显得比他还重要,他就会想要回到你身边。

总结

以上是我觉得 Why Men Love Bitches 里面比较有意思的论点。因为我是从看过那么多 PUA 资料的角度出发来看这本书的,我的目标主要是看女人观点和男人观点的异同,所以可能我看到的跟对你有帮助的不一定重合。我看过很多的 PUA 资料,但我看过写给女人看的这方面的书就几本,这本是我觉得写得最好的了,所以我会建议你去看原书。

此外,如果你觉得我写的文章对你有价值,欢迎订阅或者捐赠

2012年6月6日星期三

关于「如何追女生」的回答摘要

因为时不时就有人会问我「如何追女生」或者是「如何追某某特定女生」的问题,我又不像某些 dating coach 一样靠教这个赚钱,所以就决定把我知道的写下来。如果以后有谁还要问我相似的问题,可以先看这篇文章的内容再说。

尽管我几年前看过很多 PUA 相关的书籍和资料,但大多都不记得了,所以我不准备写很复杂的内容。由于原本我是想要基于 The Natural 的读书笔记写一篇书评的,所以这篇文章主要还是基于 The Natural 的读书笔记来写。

自信

无论你想要的是工作还是女人,第一条建议总是「自信」。(关于工作你可以参考另一篇文章,所以这里只说女人。)自信与否起到了关键作用,这可以从两个不同的角度来解释。

一方面,你可以认为自信会影响到你的发挥。如果你相信自己能拿 90 分的话考试成绩可以有 95 分,但如果你觉得自己拿不到 90 分的话考试成绩可能只有 85 分。这种现象也叫做 self-fulfilling prophecy

另一方面,自信也是一种说服力。The Natural 里面说到,当几个拿不准主意的人在尝试说服别人时,谁越坚信自己是正确的谁越能说服别人。这看起来很 tricky,但其实很合理——如果所有人都是理性的,并且所有人都如实表现自己拥有的信息的置信度,自然置信度最高的胜出。因此,跟其他人在一起时,包括跟女人在一起时,如果你确信你的经验能做出正确的判断(那家西餐厅很好吃所以我们去那里午餐),你就应当自信地宣布这个判断。

首领气质

在 PUA 的社区里,你会经常听到「alpha male」这个词,意思是动物群族中的雄性首领。PUA 还会强调要成为雄性首领,那是因为在很多哺乳类动物中,雄性首领拥有在群族中优先获得食物和配偶的权利。尽管人类社会已经进化到没有明确群族首领的阶段,但能够展示首领气质的男人还是在吸引女人方面有优势的。

在 The Natural 一书当中,作者认为以下 5 种特征属于首领气质:

  • 强烈的自我信念
  • 强壮的体格
  • 领导和抉择的能力和意愿
  • 在高压环境下保持泰然自若
  • 社交智商(与他人结识和沟通的能力)

至于如何培养这些气质,因为这是篇很概览性的文章,所以我不准备细说,想知道的人还是去看原书吧。

3 个阶段

The Natural 把追女分作 3 个阶段:

一开始你应该是 Mr. Sociable。你很善于交际,无论对方对什么感兴趣你都能说半天;就算对方不对任何事情感兴趣,你还是能分享很多有趣的事情。同时你还能传递正面能量,让人想要跟你聊天,跟你进行更多互动。

然后你变成 Mr. Comfort。能让人感觉到你像一位认识多年的老朋友,可以很放松地跟你聊任何事情,发生肢体接触也不会有任何不适。

最后你要成为 Mr. Seducer。逐步展现你的欲望,让对方感觉到你逐步被她吸引住了。

这 3 个阶段基本上跟 The Mystery Method 里面提到的模型是一致的,只是名字不一样:Attraction、Comfort、Seduction。

这 3 个阶段发生的顺序不对,或者漏了其中某一阶段,或者某一阶段做得不够好,都会导致结果不如人意。例如说「让我们继续做朋友吧」通常就是因为身陷第 2 阶段,不敢展现自己的欲望,结果也无法进入第 3 阶段。

训练勇气

要做对上面所说的,必然需要一些勇气。例如对于内向的人来说,如何慢慢地展现自己真实的欲望是很有挑战的事情,但如果你跨不过去你就永远停留在「让我们继续做朋友吧」这一阶段。The Natural 说了一件其它 PUA 材料没有提及的事情,那就是勇气是可以被训练出来的。

有些事情你因为感觉不舒服所以总是回避,但如果你能在确认安全的情况下多练习几次,你就会发现结果其实也不会有多糟糕,然后你不舒服的感觉就会开始消失。继续练习,你就习惯做这件事情了。这个道理很简单,但它能帮助你克服很多存在已久的毛病。

总结

上面是 The Natural 里面几个我觉得比较重要的点,如果大家觉得有价值的话,建议还是去读原书。对于入门的人来说,可能书中一些我认为很平常的点对你更有帮助。

P.S. 我知道肯定有人要问有没有「如何追男生」版本的了,所以我把 Why Men Love Bitches 的读书笔记整理成一篇《关于「如何追男生」的回答摘要》。

2012年6月4日星期一

三藩市湾区一周游

上个星期四一早从广州飞往三藩市,到这周三中午返回,大约一周时间,在三藩市湾区充满拜访了多位好友,也参观了几家互联网公司。还记得两年前去三藩市湾区,遇上暴风雨,不仅景色没看到,还让人担心自驾安全。这次旅行途中南湾阳光明媚,就算是三藩市也只是有雾而已,没有遇到下雨的情况,感觉好多了。

5/24

因为 Delta 取消了广州到东京的航线,所以尽管这次还是经东京转机,但飞的是 ANA 和 United。到达三藩市机场后,我做的第一件事情是把手机掏出来搜索机场免费 Wi-Fi。两年前的三藩市机场好像是没有免费 Wi-Fi 的,但我很确信现在是有的。找到 Wi-Fi 后先用 Foursquare check-in 一下,再打开 Twitter 回复了几条 tweet,然后才尝试连接手机漫游网络。很奇怪的是,我的联通 3G 卡开了漫游后到美国竟然连不上任何一个网络,AT&T 和 T-Mobile 都不行。无奈之下只好先打车去酒店。

头两天住的是 Sheraton Palo Alto,从机场打车过去要半个小时,花费 $100。酒店环境很不错,有泳池有喷泉,靠近 Caltrain 站同时 Stanford Shopping Center 也在步行范围内。住进酒店后,第一件事情当然是使用酒店 Wi-Fi 连接 MacBook Air,结果才发现连接 iPhone 时要再次收费。打电话给酒店的技术支持,对方说跟前台说一声就会撤销重复扣费,我想了想决定将来还是用有线再共享好了。

既然联通漫游失败,接下来肯定要买一张电话卡,否则离开 Wi-Fi 后连打电话联系朋友的能力也丧失了。根据几位之前来过美国出差的朋友推荐,购买 T-Mobile 每天 $3 的预付费卡是最合适的了,拥有无限量的电话、短信和流量,而且每天的前 200MB 流量还可以有 4G 网络的速度。幸好 University Avenue 上就有一家 T-Mobile Store,散步过去花 $30 买张卡够用一星期了,然后再散步回来顺便看看周围的环境。

晚上三藩市的朋友开车过来接我去晚餐,吃的是 San Mateo 的 Hokkaido Seafood Buffet北海道布斐)。在美国吃这类自助餐最好的地方在于分量充足的同时价格也不贵,$10 到 $20 能吃到的东西在中国至少要吃 ¥200 一位的自助餐才可能提供。

5/25

第二天去 Facebook,进门后见到室内的涂鸦就觉得很有创意。据说是请了知名涂鸦画家 David Choe 来画的,当然也有 Facebook 员工的作品。Facebook 现在用的园区以前是 Sun 的,Facebook 重新装修后只启用了其中的几栋楼,例如说工程师都在 Building 16,其余的楼房都还是空的。园区内只有一条主干道,因此不会迷路也不需要地图来导航。

Facebook 内部有趣的东西很多,例如 Building 16 里面的开放区域有几台街机,甚至还有一台带笔记本电脑支架的跑步机——你可以随时把电脑放上去接好线,然后就可以一边跑步一边工作。墙壁上的大屏幕是室内导航图,而且还带有会议室查询功能,点两下就能知道哪些会议室在用,或者你要进行会议的会议室在哪里。此外,为了降低 IT 服务成本,如果员工想要领取外设硬件,连 IT 也不需要去麻烦,在贩卖机上刷一下卡就能拿到。

Facebook 园区内最显眼的地标是 Hacker Square,据说在广场上写一个大大的「HACK」字,就是为了确保 Google Maps 的卫星图(或航拍图)能够拍到。每次 Hackathon 举行前人们都会聚集到这个广场上,然后 Zuck 以敲钟的形式宣布这场 Hackathon 的开始。

从 Facebook 回来后,我约了在 Stanford 读书的中学师弟出来吃饭,然后我先步行去 Stanford Shopping CenterApple Store 买 Gift Card。晚饭是在 The Counter 吃的,汉堡的牛肉和炸洋葱圈都很美味。晚饭后去了一趟师弟的宿舍,帮他解答作业上的一些 JavaScript 和 Rails 问题,结果一直折腾到凌晨两点才结束(他很悲剧地又要消耗 late day 了)。

5/26

离开 Sheraton Palo Alto 后,我搬到了三藩市朋友家住,在 Balboa Park 附近,搭乘 BART(地铁)和 MUNI(轻轨)都很方便。感谢当天 @liuxi 开车过来帮忙搬东西,在南湾这样乡下的地方没有车真的很不方便。那天还去了 Hong Kong Saigon Seafood Harbor Restaurant(西贡渔港)喝下午茶,见到了 @iveney。西贡渔港的出品很不错,据说中大有些同学很喜欢来这里吃,没时间在这里吃也打包带走。

喝完下午茶,去参观了一下 Google。在做 Android 的 Building 44 门外能看到一堆代表不同 Android 版本的大公仔,里面有大屏幕的 Android 设备(类似 Apple Store 的大 iPhone)可以用来试玩。我跟 @liuxi 想要试试如果对着展示设备的 Gmail 发邮件会怎么样,结果发现发不进去,而在展示设备上的 Gmail 中写邮件也发布出来。难道是机器没有联网?但网页和 YouTube 都能正常打开。估计早就有人想到我们会这样子搞,所以提前封锁了 Gmail 的访问,使得展示设备的 Gmail 处于离线状态。

Google 的访客中心还有一些有趣的展示品,例如一台由 8 块大屏幕组成的全景 Google Earth。由于 Google 的园区比较大,所以不像 Facebook 那样是封闭的,建筑物之间会有公路,跟其他公司的建筑物之间也没有围墙分隔。

5/27

住朋友家的第二天,跟着他们一家去了 South Sea Seafood Village(南海渔村)喝茶,虽然感觉没有西贡渔港那么正,不过至少做得还算正中。随后跟着他们去购物,买了几条廉价的 Levi’s(相对国内廉价),然后在 GameStop 买了 Forze 4,在 BestBuy 买了 Xbox 360 用的 Wireless Speed Wheel。虽说这样买比在 Amazon 贵大概 10% 到 20%,而且还要多交近 10% 的税,但既然出来购物了那就买吧。见识过这样的定价,才明白为什么实体连锁店都快要倒闭了。

下午去了 Half Moon Bay,可惜有阳光的时间比较短,大多数时候都是阴天。看了一下港口的渔船,据说 11 月份的时候蟹只卖 $2 一磅,好像很便宜的样子。往返的路上还路过了 Crystal Springs Reservoir。据说水库里的水部分来自 Yosemite(优山美地),现在专门提供给三藩市作自来水用。

晚饭是去 Mountain View 跟 Changhao 吃的,回三藩市时有了人生第一次搭 Caltrain(火车)和 BART 的经历。感觉 Caltrain 比 BART 要干净,而且因为搭乘时间比较长所以列车上还有洗手间(整列车只有一个)。BART 作为地铁,有闸机验票,而 Caltrain 则只有随机检票。一般情况下,Caltrain 只要在站台买票然后上车就是了,我搭的这一次 Caltrain 没遇上检票的。这一次从 Mountain View 搭 Caltrain 到 Millbrae 用了近一个小时,而 Millbrea 搭 BART 到 Balboa Park 又用了半个小时,加上等待和步行时间差不多两个小时。这再次说明了在南湾没有车是很不方便的。

5/28

Memorial Day 长假期的最后一天,经过 @diamondtin 的介绍,受 @lordhong 邀请去他们家作客。去之前的先去了一趟 Gilroy 的 Premium Outlets,逛了一圈最终只买了两条牛仔裤和两瓶鱼油。其实我还看中了 Sony 的 Blu-ray 3D Player,只是考虑到电压不兼容,还可能有分区锁,想想还是算了。打完折的价钱(好像是 $90)换算成人民币也很划算,在中国支持 3D 的蓝光播放器都不止这个价钱。

去到 @lordhong 家,第一次见到美国的 house 里面是什么样子的,有花园有车库的感觉还是很爽的。我们整个下午就在花园里晒太阳聊天,感觉美国人家的午后生活真的很写意啊。随后是海鲜大餐,感谢 @lordhong 夫妇提供的生蚝和螃蟹,这一餐吃得真爽了。这次的聚会还见到了 @delphij 夫妇、@jinghuaz 夫妇以及 @jasonlai,聊了各种有趣的事情。

吃完一餐,又要赶场下一餐。@essej 开车过来接我,去 Chef Yu(岳阳楼)吃饭,顺便见见在 Sunnyvale 忙于准备面试的另一位中学同学。(其实还有第三位中学同学,据说因为在女生当中太过 popular 而总是约不到,当天晚上他也没时间出来。)吃完饭后去 @essej 在 Palo Alto 的住处看了一下他租的 house 是怎样的。$1400 能够有独立的卧室和浴室洗手间,共享的客厅和厨房,我觉得不错啦。类似的空间在北京没有 ¥4000 你都不用想了,但你在北京的收入数字部分真的能做到 Palo Alto 的 3 倍吗?

5/29

在三藩市最后完整的一天,我选择了去参观 GREE,顺便体验三藩市室内公共交通。由于出门就有 MUNI 的 KT 线,所以上了 K 车后我也没怎么考虑 K 车和 KT 线到底是什么关系。话说 MUNI 的这些有轨电车很可爱,在路面上看就是有轨电车,但是进入隧道后感觉又好像地铁。中午跟 @jasonlai 到 Polo Grounds 吃汉堡(我又是冲着大块牛肉来的),下午到 GREE 看了一下,然后就准备搭 MUNI 往回走了。结果发现在我下车的站台上,反方向来的只有 T 车,那我到底要上不要上呢?一犹豫就错过了一辆车,接着下一辆车要 20 分钟后。好吧……无论下一辆是 K 车还是 T 车我都上,搭错了再说,反正我有 Google Maps,不信我找不到路回去。结果下一辆来的还是 T 车,走的路线则跟来时正好相反。(到现在我还没明白 KT 线和 K 车、T 车是什么关系。)

到倒数第二个站停车后,司机就不关门也不往前走了。看到前面轨道上停着一辆有轨电车,司机说估计 5 分钟内不可能解决问题,想要下车的人可以在这里下车。想想我只需要步行一个站,迅速选择下车往前走,发现前面堵了好几辆有轨电车,最后发现某个路口出事故了,警察在处理,两个方向的有轨电车都停下来等待。看来三藩市的公共交通系统还是挺脆弱的。

5/30

最后一天自己搭 BART 去机场,再经东京飞回广州,一路都很顺利。比较搞笑的是,到东京后被告知我们的飞机早到了,分配给我们的廊桥还被上一个航班占用着,机场正在跟他们沟通,希望他们能够准点离开。此外,在三藩市机场的时候我又忍不住花钱了,买了一本 PC Gamer 和一本叫做 The Zombie Survival Guide 的书。买前者是因为它的封面(有 Company of Heroes 2 的内容哦),买后者是为了在飞机上打发时间(结果在飞机上只看了一章,然后看了 3 部电影)。

总结一下,尽管这次湾区的路行安排有点匆忙,很多朋友也是临时约的,但抵达后能够见到那么多的朋友也实在是幸运。尽管没有车确实有点不方便,但朋友们提供了不少帮助,结果还是去了不少地方长了不少见识。这次唯一的小遗憾是没去看金门桥 75 周年庆典,不过根据去看了烟花的 @diamondtin 所说,看完烟花后人流散去公共交通资源实在稀缺,或许不去确实是正确的选择。

P.S. 在写这篇文章时,一开始地点我都是用 Google Maps 链接的,后来想想还是用 Foursquare 链接比较方便,因为地点我都 check-in 过,去 History 页把链接复制过来就可以了。此外,大家也可以通过 Foursquare 链接看到更多的照片,不仅仅是我发的,也有其他人发的。

2012年6月1日星期五

理想的技术面试过程

作为面试官

从在大学里面试社团大一新生,到加入百度后帮公司面试候选人,我觉得我对面试这件事一直不得要领。百度提供面试培训,也允许参考或使用题库,但我还是觉得不知道如何判断给不给一名候选人通过我这关。偶尔我会遇到非常优秀的实习生候选人,我能十分确定我要给他过,甚至想方设法确保他能来。其它时候,我觉得我的判断随机性太大,或许还不如一枚硬币做得好。

在百度做二面的时候,我往往会问一些组合问题,就是候选人需要有扎实的基础加上一定的解题能力才能做出来的。我假设一面的面试官已经问过基础问题,所以我不会再问基础问题。结果通常是,候选人的基础不够扎实,会作出一些错误的假设,甚至面对组合问题就无从下手,不知道如何分解为更小的问题然后再一步一步来解决。我不知道是否应该期望候选人全部答对,但答对小部分的状况让我无从判断。

为此我开始跟其它人讨论面试经验。Acumon 说应该针对候选人说他擅长的领域来提问,而且使用开放性问题以便了解候选人的思考方式,但我发现我遇见的大多数候选人都不清楚自己擅长什么,或者是他们自认为的强项无法达到我的预期。后来在上海跟 Winter 和 Hax 聊天时发现一个可怕的现实:大多数前来应聘的前端工程师都无法回答「position 属性取值都有哪些」以及「display 属性取值都有哪些」。随后我尝试在我的面试中先问这两个问题,发现确实有些人回答不出来取值,更多人则是无法准备描述常见取值的作用。(我甚至不把 inline-block 和 fixed 归类到常见取值里面。)遇到如此基础的问题都回答不出来的候选人,我通常会跟他告诉他正确答案,再问一些基础问题然后给他一些学习建议,最后很礼貌地送他走。

状况在我到达豌豆荚后有所改善。不是来应聘的人都非常优秀,而是我开始有感觉了。关键原因我觉得是我们不着急招人。现在我们还能应付手头上的工作,也没有快速扩张的需求,所以我们只有在遇到最合适的人选时才邀请他加入。我相信我前面的两位面试官做得足够好,然后我可以放胆地去考量「懂不懂」之外的其它方面。准确来说,这甚至不是一种考量,我只想知道我跟这个人一起工作是否会很愉快。我会以工作上遇到问题时同事跟同事间讨论的方式去跟他进行讨论,有可能是工作上实际遇到的问题,也有可能是刻意设计出来的有趣问题。(我觉得在一个充满活力的工作环境中,同事之间互相找些稀奇古怪的问题来讨论是很正常的,大家也会享受这类挑战。)如果我感觉跟他讨论问题是很愉快的过程,他能够提出有趣的想法,甚至能告诉我一些原本我不知道的事情,我肯定会给他很正面的面试评价。

作为面试者

换个角度来说,如果你作为面试者发现自己在面试的过程中能够进入这种状态,感觉如同跟同事讨论问题一样放松,那么你应该对面试结果充满信心。至少根据我个人的经验来说,感觉如同轻松愉快讨论的面试我都能得到面试官不错的评价。我明白要做到这一点很不容易,很多人在面试时都会很紧张,甚至会假设面试官一定会用各种难题来考自己,这种心态其实会把自己放在不利的位置上。我过去的经验是,我越不在乎的面试,往往我越能放松地跟面试官随便聊,结果反而越好。我很在乎的面试,反而有时候会高估面试官问题的难度,结果简单的问题没给出简单的答案,最后得到的评价反而不好。

在百度大厦的时候,我喜欢穿越二层平台,因为那里有很多小圆桌,也有很多人会选择在那里进行讨论或者面试。如果你对肢体语言有点最基础的了解,或者你就是在这方面有感觉,你会发现在那里很容易看得出哪些桌是同事间的讨论,哪些桌是在面试,以及谁是候选人。同事之间的讨论,往往大家都会很放松;面试的话,面试官也会很放松,但面试者通常处于比较紧张的状态,身体会略为前倾,就算不需要写字也会把手放在桌子上,用于支撑上半身的重量。对于有经验或者有感觉的面试官来说,这种肢体语言会传递一种不好的信号,那就是你太想要这份工作了,就算更深入的沟通后可能你会发现这份工作不适合你,但你还是会追求这个机会。

类似的场景也会出现在异性之间,下次去餐厅吃饭时你可以观察一下隔壁桌的异性交互。就算你完全不知道谈话内容,你也可以尝试从面部表情和肢体语言去判断谁在追谁。为什么有时候你追的人各种虐待你,还有充足的信心你不会放弃?因为他们看得出你把自己摆在什么位置上。在统计学的角度来说,我觉得女人在这方面比男人有优势,因为女人看的电视剧都不是白看的,她们在逛街吃饭时还无时无刻地在观察身边发生的各种剧情。就如同资深前端工程师可以只看 CSS 片段就猜出遇到了什么浏览器 bug 以及作者尝试如何解决一样,有经验的女人(又或者是面试官)要看明白你的立场太容易了。

因此,首先你要把面试看作一个平等的双向选择过程,不仅仅公司在选择你,你也在选择公司。如果面试官问的问题显得他很没有品味,或者是 HR 的某些安排让你觉得这家公司的文化很有问题,你随时可以提出说你没兴趣聊下去。这时候你反而可以比较好的发挥出来你真实的实力。对于你真的不知道的问题,你就直接说出哪部分你不知道或者不确定。同事间讨论也会遇到你不懂的问题,你平时是怎么处理的在面试时就怎么处理,面试官不会因为你直率地表达不懂某个点而鄙视你的,他应该帮你把这个点绕过去然后继续。

我觉得最好的面试建议就是 Changhao 跟我说的那句,「Be yourself」。(其实这也是很好的追女建议。)

改善面试流程

既然技术面试应该平等地讨论问题,通过感觉这个人是否能成为一名你喜欢的新同事来做出判断,那又应该如何衡量他的技术能力呢?这其实应该放在面试流程尽可能靠前的部分来做。很多外企的标准做法是,通过首轮(或前两轮)电话面试来判断一个人的技术,随后通过多轮的面对面讨论来判断这个人是否适合这家公司这个团队。我相信这套方法在美国执行起来没什么问题,因为空缺和候选人的数量差不多。

当然,上述流程来到中国后就必然会发生变化。中国有能力来做这份工作的人太多,同时还有更多的人想要来浑水摸鱼,这就导致了招聘成本大大提升。如果在中国还是用首轮电话面试来根据候选人的技术能力做一个初步的筛选,我想面试官就要疯掉了,所以大多数大公司都会在此之前加上一轮笔试。(对应届生可能是多轮笔试,否则面试官就阅卷都足以疯掉。)

有些公司会选择通过 ACM/ICPC 竞赛经历做出筛选,尽管无法保证获得最优结果,但至少能获得次优结果。招聘本来就是个搜索问题,一个在美国能有效求解的算法到中国来发现搜索空间大小增长了几个数量级,自然要想办法调整算法提高性能。这是非常理性的做法。当然它会带来一些外部性,例如说使得更多中国学生在可能不适合或不喜欢参加竞赛的前提下选择参加竞赛。

这些方法确实能把想要浑水摸鱼的人筛掉,不过能通过的人有时候还是太多了,所以接纳候选人过多的大公司往往会无端增加面试难度,问一些纯粹刁难人的题目。我觉得这没什么意思,也没在应届生面试以外的场合遇到过。既然应届生及格的太多,我觉得就直接随机抽签好了,这是最公平的做法。抽签可以通过公证过的算法来做,这比问一些候选人可能随机地知道或不知道的问题可靠多了。

最后说一下,为什么我觉得平等讨论的面试方式比问一堆问题要好。不同的面试方式,取决于你把候选人看做一个人力资源单位,还是一个有个性的人。如果你把候选人看做一个人力资源单位,他只要能完成你给出的任务就可以了,那确实是能力测试更重要。如果你把候选人看做一个有个性的人,你就需要知道他的个性能否很好地融入团队当中,这使得你在面试过程中必须把他当做一名未来的同事来看待。