• 作为有类似遭遇的应聘者,我是非常支持 Max Howell 的。

    为什么很多人理解不了 Max Howell 通不过白板编程面试

    这个事件在国内也引起了很大讨论,各大社区都有,以下主要总结 如何看待 Max Howell 被 Google 拒绝? 里的讨论,态度主要分为以下两派:

    1. 大多是惊讶或者调侃大牛居然连这个算法里的基础题也做不出来,有讨论具体算法细节的,也有发明段子讽刺连面试官给你放水都还帮不了你。
    2. 小部分人怀疑白板面试是否真的能很好的筛选人才,毕竟没有多少项目经验的做过算法功课的应届生也可以做到通过这种白板算法面试。

    很不幸的是,我并没有看到更多有分量的开源软件牛人(像 Max Howell 作出 Homebrew 这样巨作的,上了 Github 排行榜的)出来支持 Max Howell 的观点。这也说明了程序员的地位相对企业的地位而言是远不如的,更多聪明的人是选择了沉默,我也听说过为什么优秀开发者进入 Google 后就不参与开源了

    我想这个是有本质原因的,那就是开发复杂且优雅的软件系统 和 在脑子里背下各种计算机科学的算法 是矛盾的。这不是说复杂且优雅的软件系统不需要算法,而是算法已经被工程化地内含在项目里了,项目和代码都是真实世界里存活的东西,而纯粹算法代码只是存活于阉割版(用的字符最精简)证明理论里的,只是被人们用于口头交流功而抽象出的逻辑沟通系统,但却不是用于真实业务代码的理解和修改之用的。不得不承认的是,真正能做出复杂且优雅的软件系统的人比例很少,我指的是写出真正流行的框架和语言的那些人,没错,就是你平时用的那些,所以别太指望有很多人真的能理解 Max Howell 为什么就通不过白板编程面试呢。举个有意思的例子,你会发现有名的开源软件写的代码,和通常算法里写的代码完全是两种路子,虽然从狭义的算法原理上看干的是同一件事,但是前者是富有层次的工程结构,而后者则强调把全部细节都放在脑子里直观地去一次性理解,所以这也是很多初中级程序员啃不下开源代码的原因。

    在面试这种紧张 (其他的还有考试和演出等)情况下 ,其考察的是肌肉记忆能力,而不是分析和创造能力。即使在面试中能写出完全正确的算法逻辑代码,那么对该人的程序创作能力也是有损伤的,所以白板编程面试是考察候选人能力的下策。

    上策是考察过去项目经历,从而推断出其经验和学习能力;其次才是是通过一些实际或虚拟问题去考察。这两者都应该建立在双向沟通反馈上,才算的上是合格的面试。

    最后补充一条信息,一年多前我也发过 “ 面试时候如何用 Ruby 写一个最短二分查找代码 ” 文章来描述去某公司面试时的在算法流程上的失败。当时我是写 Ruby 的,面试官是写 Python 的。摘录文章最后一小段,“最后面试官总结我应用或 Rails 方面的经验比较多,但是算法不太行,他准备和 CEO 再讨论看看。于是我咨询他公司技术部有哪些算法工作,他提了一个数据排重,然后我说如果准确度不太要求的话,可以用 bloomfilter 进行过滤。但是他坚持这一轮面试结束了,于是只能出门和他道别了。” 有讽刺意味的是,在我加入新公司半年里就用 Python(进入公司当天我就现学 Python 干了一个统计的活了)实现了 百万题库排重算法(相同题目因为各种原因导致进入题库后有微小差异)的开源框架,源码地址在 https://github.com/mvj3/detdup ,演讲稿在 https://speakerdeck.com/mvj3/detdup 。多说几句,目前我的工作内容大部分都是如何在 Hadoop 上实现离线业务模型,并自己在写了一个不错的 DAG 任务管理框架,地址在 https://github.com/17zuoye/luiti 。对 Hadoop 的上手时间基本等同于熟悉一个 Python 类库的时间,再继续上手 Spark, Storm 也是不在话下,而这恰恰是有些看上去熟悉算法的人不容易做到的。

    关于 Invert Binary Tree 的技术讨论

    首先是 [Invert Binary Tree] 的递归版本,虽然我之前从来没有做过这个程序,不过在 LintCode 上读了需求后,用 Python 第一次写就通过了,http://www.lintcode.com/submission/630731/ ,但是脑子里还是慢慢反应一下,甚至还不太自信。

    其次是 [Invert Binary Tree] 的非递归版本,即是用栈实现的,我没想出来,主要想法是因为每个节点最多有两个子节点,是不是用数组来模拟索引啥的。因为不是实际想做的,所以和平时工作学习一样,直接搜索了,是用 Stack 实现,其逻辑大概稍微复杂了一点。总之,凭我的经验,是需要一些时间来突然顿悟这个算法是怎么回事的,但是我知道过段时间我肯定忘了,所以就不想了。

    最后是关于 Google 面试官考察的到底是不是 Invert Binary Tree,我看到 Max Howell 给某人的回复是 "min-max the tree, ascending to descending",地址在 https://twitter.com/mxcl/status/608891015945170944 。这样听上去好像是要做个上下翻转,而不是左右翻转,这可能是 Max Howell 没说清问题,也可能就是本身问题描述就不是一下子能说清的,那么请考虑在如何实现时就需要去理顺更多细节,可想而知会更容易出错了。

    傲娇的人只是对事情更认真而已

    有些人说 Max Howell 是大牛,被考察一个简单的 Invert Binary Tree 太不上档次了。

    对于这个问题,我首先强调的是,优秀是一种习惯,同样一个人的代码风格往往是一致的,更深一点理解,TA 解决问题的范式都已经形成了自己的一套经验体系。所以大牛去写一个算法,通常是工作中的,那么必然是考虑到各种和其他模块如何整合,API 是如何的形式,而自身的代码组织逻辑又是如何自恰。举个象棋或围棋的例子,虽然规则大家都懂(这个类比到算法的步骤),但是大师看布局的角度和一般人的是完全不同的(这个类比到有人觉得 Homebrew 没啥复杂技术,可是却不是一般人能做出来的),而且也不太好解释(要知道机器至今在围棋成绩上仍远远落后于人类水平)。所以突然把大牛放到一个陌生的工作模式里,即是换成教科书的算法步骤思维,并且是面试的场景,而且是短时间,做不出来是很正常很可以理解的事情。要知道真正一个算法整合到实际项目里是得花很长时间的,里面涉及到不断的反复构思和调整。

    有些人说 Max Howell 傲娇了,但他其实已经做了算法面试准备了(A good thing that came out of it is, I did prepare, and actually I found a bunch of common algorithm problems a lot of fun. Will continue. https://twitter.com/mxcl/status/608754975364276224 )。而且大家得注意一个事实,工作多年的人去复习算法和训练专门用于测试的思维方式是有时间成本的,相对来说应届生的时间成本就少多了,专门做算法的人在此不谈(TA 们的软件工程水平相比而言也是低一点的)。算法确实很有意思,这两年我也在提高,它仅仅是解决问题的关键之一,而且大部分场景下,刻意的教科书算法对于工程来说都不是关键的。

    说一下我个人对编码面试的观点,我热于在实际工作中接受任何相关项目的挑战,但是我不想做无用的压抑的耍猴游戏(可能也和我不喜欢玩电子游戏有关)。

    面试时气场不合是个关键问题

    很多时候人都是相当情绪驱动的,我人生经验里有一个让我震惊的观点是,有些我认为是应该非常理性的人居然也很坦率地承认自己对这个问题就是感性的。Max Howell 的气质是偏艺术家型的(这里有他在 Github 的演讲视频 https://www.youtube.com/results?search_query=homebrew+max+howell ),我猜测 Google 的那个面试官是偏死板的工程型的。所以如果和面试官气场不和,我理解是主要是 TA 感受不到你在 TA 未来的控制(中性词)范围内。

    我一直有个疑问,对于一些很有想法的人(理解 Max Howell 的个性看他个人主页的色彩设计就知道了 http://mxcl.github.io/ ),面试官在看到简历时,为何不直接拒绝呢。还有另一个可能性是,一个面试官去面试可能是别人要求去的。如果让对方来了,为何大家不和和气气好好沟通呢,面对一个可能是未来的同事,非得拿那些刁钻的题目来为难对方呢(举个人人努力一下都会做的算术题,比如 7*19 比 200*300 难多了,虽然同是两个数,而且前者数还小),工作应该是快乐和有激情的啊(有些人其实是在组织里很压抑的)。

    举一个我认为相当侮辱人的程序员段子,美女来面试,连不会写 HelloWorld 都能过(所谓程序员鼓励师),长相不好看的来面试,一定得拿红黑树来压制。虽然大家都当是个笑话,可是也折射出一些潜在的不良价值观。我理解 culture fit 是个一直都存在的常见问题,但是我还是觉得工作能力优先,这样才不会劣币驱良币。有一个调查是全球盲人比例约为千分之五,而城市道路上基本都人性化的加上了盲道,从道德上来说,应该谴责强势雇主在性格上歧视应聘者,另外我也相信大多数人还是知趣的吧 :)

    其他一些关于面试的问题

    我看到一篇看上去很好的文章 http://www.gayle.com/blog/2015/6/10/developer-interviews-are-broken-and-you-cant-fix-it ,主旨是讲面试流程无论如何改进,都是有缺陷的。我的想法是,这真的是典型的逻辑式废话,从各种利益权衡来证明现有的制度是合理的和没办法的,同时为了公平性而不能更改任何细节。

    我唯一的想法是,很直观的,一个大牛活生生的站在你的面前和你善意地沟通,同样希望得到一些相互的尊重,而面试官却非得照着一个脆弱的流程,去让自己和大牛都去适应这个规范(虽然实际工作时大家都是很灵活的),让旁观者也是干着急啊。

    有必要我可以逐条反驳文章里我认为不妥的意见。

    P.S. 我的知乎回答在这里 http://www.zhihu.com/question/31202353/answer/51304584

  • 前端架构分享 at 2015年05月29日

    :plus1:

  • #41 楼 @secondwtq 欢迎关注 http://human-lang.org ,在解决软件复杂度的同时,也符合人类思维的一般习惯。

    语法层面的构思在 https://github.com/human-lang/examples/blob/master/poignant.human 这里也有。

  • #2 楼 @huacnlee 赞。

    这点在不善言辞的工程师上更加明显,尤其是对方是有人事权的时候。

    像这种情况,别人通常会要求你看他优点,而 TA 指责你的时候,就只看你的缺点,说是违背了原则。工程师还是直来直去的,没有那么多心眼,反而是管理者会考察这个人受委屈时抗压好不好,或者受不受管制,唉。。。抗压能力好不好,还是真的看项目经验就好了,多大能力就担多大责任,有大型项目成功经验就足够了。

    #5 楼 @tini8 对,这个就是现实,一般而言,工程师最有谈判权的时候就是在刚进公司的时候,打工的角色就是这样的。

  • #17 楼 @still0007

    首先我想说的是我非常高兴地感受到了你的诚意和善意,对于你说的编码水平衡量标准我没有异议,我唯一介意的是,根据我的面试体验,和面试官的水平有很大关系,而且讨论有些较深问题的时候,照顾面试官(一般是未来的上司和同事)的情绪是一件很重要的事情(因为这个这个事情我真的挂了好多面试),对于能力好有想法的人只能拼人品和机缘了,对于能力差点(比如以前刚出道一两年的我)只能先委曲求全能通过就最好了。

    这个帖子,首先可以看出的事,我其实没有在应聘,我只是在发表企业这种做法在我的实际体验(在我看来这就是传统招聘的痛点)看来有点不舒服,因为我通过编码面试后,对方基本也不会就这个题目讲什么内容,说的全都是旁枝末节(比如方法名,或者一个不涉及性能问题的语言 API 等),真的是仁者见仁而已,太少去关注首先是能及时完成项目,其次是把项目做正确(设计和测试),再是整体软件设计能力,等等。

    是有点指名道姓,但其实我并没有针对 Oracle ,我只是在抱怨一个行业现状(被一部分企业采用的编码面试)而已。Oracle 是家国际公司,我觉得还是相对而言比在一个还在生存线上的创业公司的帖子下回复的好吧,即使这样,你说了你也会捍卫我说话的权利对吧。我的这个意见,就相当于有人抱怨国营单位的工作人员态度比较差一样,没有别的意思。

    最后,我真的真的建议,如果应聘者针对招聘需求去做简历和介绍,表示对对方公司职位和文化的兴趣,并自己的一些未来发展等,而雇主也应该对这认真评阅(现场我知道一般人都会答复,但是 email 就不是了),作出相对应的回复,这样会更佳人性一点,遗憾的是,有些公司的礼节做的太差了,好像应聘者是在求 TA 一样爱理不理。简单来说,对于群发的简历可以忽略不回,对于有诚意的应聘,只要职位匹配上的偏离不是太夸张,建议还是好好回复一个,哪怕一句话也好,虽然我知道这个已经是行业的潜规则了。我只是觉得我曾经受到了一些委屈,表达出来,看看有没有其他人有相似的经历并获得一些赞同。

    话说回来,即使我这样表达,你照样也收到了很多简历(好多回复对吧),所以假使我真的无理,那么其他应聘者不用在意我的话就好了,毕竟我说的只是一个流程问题而已。

    #18 楼 @lgn21st 首先非常感谢吕大哥去年邮件对我说的一些贴心的话,做人确实得磨练一些每个人都应该学会的技巧。你推荐的这期 Teahour Podcast 我听过(现在忘了内容了,有空我会再听一遍),我也经历过 Thoughtworks 公司的面试,简单来说,面试其实是个远比流程本身更复杂的事,任何一点因素都是可能导致双方最终没有对上的。我只想说一句,人活得稍微理想一点,是可以增强幸福感的 :)

  • #15 楼 @yanhao

    1. 对,这是相互选择的过程。但是听一听不同的声音总是好的。
    2. 那得看如何实现。我建议你对我的设计代码里涉及到的各种东西做一个深入考察并说出各种优劣后再说我熟不熟悉 Ruby 也不迟,或者你示范写一个更优雅的。
    3. 这个是平时的,如果每个人都是像为了应付高考一样去对待技术面试,那么中国的开源事业如何发展?
    4. 我上面说了,可以换用 其他对等的方式,比如平时写的作品。本来测试的目标主要就是为了考察水平,而不是主要为了考察诚意,对吧?!而且如果多花点时间写一个把对方招聘里的内在需求和自身技能清晰地匹配起来的简历,是否更有利于双方的选择呢?而不是几十行代码就看出一个人的水平。
    5. 对,但是得尊重少数人的选择,要知道开源作品主要还是少部分人做的。

    从上面反馈看来,"斯德哥尔摩综合症"患的比例还是有点严重的。好吧,以我个人经历来看,应聘者强势也没有好结果,但是我总是觉得缺了点什么。

    从之前的招聘贴 https://ruby-china.org/topics/24608 的回复来看,回复的人给出代码的,招聘方都给出了请发简历的邀请,我真的对"优雅"一词产生了怀疑。。。

    各种低级代码:

    1. OPEATOR.keys.include? -- 太明显的重复计算,明显是对对象内存占用没概念
    2. Fixnum.module_eval -- Monkey patch 。。。
    3. eval 还是少点用吧。。。
    4. 没有认识到 Ruby 里 Method 对象的威力
    5. 看上去都是没有写过中大型软件的,好像水平就停留在加个 lib 目录的阶段,也许可以尝试一下升级到 gem 的阶段。我知道我说的太严厉了。。。
  • #7 楼 @lolychee

    哈哈,我注册试用了一下 codewars ,真牛逼,这个提示做的。。。

    点击 Run tests

    Run options: --seed 1918
    
    # Running:
    
    .
    
    Finished in 0.002305s, 433.9223 runs/s, 4339.2231 assertions/s.
    
    1 runs, 10 assertions, 0 failures, 0 errors, 0 skips
    Test didn't pass: Unknown error
    Process took 135ms to complete
    

    点击 Submit

    static example calculations
     `block in 
    ': undefined local variable or method `five' for main:Object (NameError)
        from `block in describe'
        from  `measure'
        from  `describe'
        from  `describe'
        from  `
    '
    0 Passed
    0 Failed
    0 Errors
    Process took 66ms to complete
    
  • #7 楼 @lolychee 抱歉我没有理解你的意思,“21 Passed, 3 Failed, 0 Errors",我的代码里总共有 8 个测试,何来 21+3=24 个测试?

    #9 楼 @billy 非常感谢做了这么长的 Review。下面是一一回复:

    有问题部分:

    
1. method_missing 缺乏对应 respond_to? --- 这个确实是的,不过我之前做了 5 年多的 Ruby,还从来没有听过这个约定,搜索了一下,发现社区里确实有人提到,感谢提醒。说句题外话,我觉得这是 Ruby 语言本身的机制问题,没有提醒使用者去注意。 
2. method_missing 方法主体太长,无法单元测试。 --- 里面已经分步骤一二三了,方法长度不是为短而短,而是为了清晰的这个目标。我随便给你挑了一个代码 https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/cache.rb#L141 我建议你先挑一下我代码的优点,而不是缺点。面试的时候主要考虑优点,其次看缺点是不是在容忍度内,做人何尝不是这样呢:) 
3. send 调用私有方法有问题。 --- 有问题就不要说” 有问题 “,把错误栈或原因说出来,让对方马上明白,这个道理好像一般提问智慧里都有吧。 
4. 最大问题: assert_equal(7, one(plus(two(times(three))))) 这个是新增加的 API, 原需求不需要这个方法,你自己增加了,这个带来不必要的成本。
 --- 本身就是兼容的,而且是逻辑内含的,这不是画蛇添足。

    1. method_missing 里面条件不符直接报错不太合适,应该考虑往上甩的可能性,不然别人就没法用 method_missing 了。 --- 这个代码首先不是一个公共库,我能做成一个 module 再加点测试已经很是良心代码了。

    意见性部分:

    
1. method_missing 是很强烈的元编程方法,而且增加调试困难。不到走投无路最好不用。如果一定要元编程,我建议用 define_method 等比较温和的方法。
 --- 如果对方需求里要求支持 一万一个数字呢:)我这里本身用的就是 define_method ,如果你的能力再好点,应该可以明白我这是最佳的 cache 做法。

    1. 新增的几个 constant,除了 Numbers 和 OperationMap 我觉得有些意义外,其余都属多余。 --- 分步骤,数据流程清晰。 
3. method_missing 主体很长,里面的逻辑难懂。 --- 建议你说出难懂的原因来。 
4. 既然你注重扩展性,测试应该覆盖扩展的逻辑部分,而不仅是直接的需求。--- 请详细说出我扩展的逻辑的部分。这个代码主要目的就是为了需求里的几个数字和算数规则,没有太多复杂的东西。

    话糙理不糙,我喜欢你论证的条理性。现在我的代码在主要的 Ruby 版本上都通过了,见 https://travis-ci.org/mvj3/oracle_interview_calculation , - 1.8.7 - 1.9.3 - 2.0.0 - 2.1.0 - 2.2.0 ,我本地的 Ruby 是 1.9.3, 刚才我兼容了一下 1.8.7 和 2.2.0 ,详情见我的 commits为这个面试实在是没必要这么干的。

    #10 楼 @emanon 你说的比较诚恳。编码测试是可以用来过滤,但主要还是降低公司的成本,而不是应聘者的成本。如果这个员工真的重要,为什么不拿出点诚意来好好了解应聘者的 Github 开源项目呢?五分钟就大概能了解这个人水平了,其余都是细节。如果五分钟都拿不出来,我真的不能明白什么是求贤若渴。

    #11 楼 @kayakjiang 比起其他人的,你的代码应该是创业公司最推崇的(最好还是加点测试吧。。。),要速度快的话我也会这么干。可是这个面试题又没限制时间,做的简单了,对方还会以为你水平也就这样呢,这是个非常仁者见仁的问题。"一个优雅的解决方案"里的这个 “优雅” 还是很有主观性的 :)

  • 人和人本来就是有矛盾的,有些平时不会有问题,遇到问题时性格缺陷就会显示出来。

    一个人的技术和沟通能力都可以用某种方式试出来,但是不见得非得用一些激将法或故意制造场景来迷惑对方,否则还会落得个双方不愉快。

    咄咄逼人的面试官,如果在招聘后面也没有体现出对你的好意的话,建议还是远离吧。

  • #3 楼 @MrPasserby 好吧,我们价值观不一样。

    在我的价值观里,加班其实是工作效率低下,远远没有发挥一个 Ruby 工程师应该有的效率。我相信这个也是你用的包括 Rails 作者在内的众多开源软件作者的价值观。

  • #4 楼 @billy 我很尊重你的观点,你说的也没错,所以只是文化问题而已:)

    但是我觉得这个问题其实是应该我这样做的,在真实的复杂的项目里,和招聘里说的 “一个优雅的解决方案”,否则够 Ruby 吗?否则 Rails 如何诞生?

  • #1 楼 @MrPasserby 请看"我建议是可以让应聘者发一个 TA 得意的编码作品" 部分。

    另外,我想反对的只是 # 抵制浪费时间的编码面试 # 而已,没有反对其他。


    在微博 http://weibo.com/1798217197/CdR5YxdR8 上也有些讨论,里面我的观点摘录如下:

    主要是涉及到代做和抄袭的问题

    1. 这个应该是涉及到人品的问题,这个雇主应该有能力察觉,然后本身劳务合同里也是得规定是否属实的。
    2. 好的代码应该是有 commit history 的,所以这个如果让 TA 说下开发历程,没有一定能力是做不到的。
    3. 如果是团队里相关人作品,这个首先还是回到人品问题,再次是这个人能解释清楚,也说明其水平了。
    4. 是可以让 TA 提供多份作品,毕竟每个人都是有一些风格(编码和文档)的。
    5. 最后,比起 TA 平时的作品,这个编码测试是不是更容易找别人代做呢。
  • 随着对事物的理解和认识深入,更细化的分类不断产生。因为人们找到了更多的共性和特性。所谓“高内聚”说的就是这个意思。
    

    我更多理解为 不是找到了共性和特性,这好像是强调相似类或概念之间的继承和交集关系等,高内聚不是分类之下的最小单元,而是只是相对于要设计出的软件规模,选择把哪些个若干元素更适合放在一起,而不是和其他元素杂乱在一起,或者过度设计到很多类和模块里。

    归纳起来,简单的原则就是,“组合优于继承”,从这个原则去理解 高内聚 和 低耦合 会更有意义。面向对象的 高内聚 和 低耦合 应该被抛弃,它只适合于软件复杂度比较小能驾驭的框架,比如 Rails ,虽然这个 Rails 已经很满足一般小网站大部分需求了,但是后续的维护和壮大却不得不是个坑。

    我和 历史学家 Hayden White 说 “理解的源头就是分类” 理解不一样的是,我认为理解的源头或本质是上下文,它包含 分类,组合,联想,等等。

    在我现在要设计中的 Human 编程语言 https://github.com/human-lang/draft 里,我尝试想抛弃掉编程语言里 “类 (Class)” 和 类方法 等这些让人匪夷所思的概念。具体还在酝酿中。。。

  • 我的 2014 at 2015年01月05日

    楼主相当高产啊 👍 步入了成为大牛的第一步。共勉!

  • #6 楼 @zamia 还不错啊,玩各种新东西

  • 薪资比之前 8-15K 高了一点,顶全端! zamia 人很 nice!

  • #2 楼 @swordray 公司要求用 Python 做开发的。Flask 和 Rails 相比,虽然思维方式稍微有些差异,但代码量应该说差不多,所以多接触下其他语言框架对于写了四五年 Rails 的人来说不失为一种好处。

  • #118 楼 @diguage 在一家公司用 Python 做数据分析呢,微信联系吧~

  • 工作也旅行 - 工作机会 at 2014年01月26日

    一直对远程移动工作方式怀有憧憬和向往,无奈自己选择时还是更倾向于按部就班的工作方式,这样可以让自己在工作和思考之间保持节奏感,另外在办公场所很容易进入工作状态。

    期待楼主多分享,我对以后去国外旅行工作很有兴趣 👍

  • 关于算法, 我们该学什么? at 2014年01月13日

    #14 楼 @assassinpig 用算法解决问题有三个角度,1, CPU 组织, 2, IO 组织, 3, CPU 和 IO 互换。