如果建筑工人像程序员写软件那样盖房子, 那第一只飞来的啄木鸟就能毁掉人类文明。
--Gerald Weinberg (软件工程大牛)

我的墨尔本求职之旅 – 第一个进行到最后一轮的面试

上一篇文章我的墨尔本求职之旅 - 准备篇介绍了求职准备工作,这篇文章打算详细聊聊第一个进行到最后一轮的面试的公司。这家公司是一家上市公司,主要为中小型企业提供财务会计软件服务。他们会时不时举办一些 hackathon,在澳洲和新西兰应该是一家知名度比较高的企业。在了解这家公司背景时发现其在成都还有过分公司和在中国开展过业务,可惜在08年金融危机后退出了中国和亚太市场。

招聘信息是从公园遇到的父母处得知,其中一个小朋友的爸爸在这家公司工作。被告知可以先去公司官网看看,如果有合适的职位,他可以推荐。打开了公司招聘网站后,我开始了这家公司的面试之旅,整个过程有三个部分:1. 解开招聘信息彩蛋;2. 完成 code exercise;3. On site face to face 面试。对具体细节不感兴趣的同学,可以直接翻到最后看总结。

1. 发现彩蛋,解开Puzzle

在浏览招聘信息时发现其中一个职位最后有这么一行字:

P.S. Can you solve this? aHR0cDovLzEzLjU1LjIzNC4xNTQ6ODA4MC9pbG92ZWRldi9NYXNzaXZlbHlfU2xlZXB5UGFuZGFz

有兴趣的同学可以先不看下文的剧透,根据上面的信息尝试下是否能解开这个彩蛋。这个 puzzle 虽然不是特别困难,但是还是有点挑战的。

P.S.下面这一行字符串看上去像 base64 编码,很明显是一个隐藏的彩蛋。果然,base64 decode 后它就是一个 URL。打开后看到一个共有五关的 puzzle,顿时来了劲,因为我向来喜欢挑战有难度的东西,而且这对我来说是一个不可多得的机会。简单记录下闯关过程:

0x00: 整个页面充满了各种看上去很神秘高大上的干扰,其实对闯关无用处。我一开始试图把背景图的符号按照 ASCII 翻译出来后得出一串发现不了什么意义的数字。由于一开始没有摸清套路,这里耽搁了些时间。

第一关

0x01: 打开网页开发工具(Chrome DevTools)后 ,console 中输出了一小段乱码 srehaeh kcehc,尝试反转过来是 check headers,于是去检查 HTTP Header 中的信息,在 Header 中发现了第二个 URL。至于如何发现 srehaeh kcehc 其实是反序的呢?首先,这很明显是一段包含了有用信息的乱码,很明显它也不是 base64 编码;其次,它不太可能是一个有着很复杂规律的加密结果,因为如果它是常规的按照某种字母偏移规律的加密算法,由于样本太小,解密会非常困难。所以很自然想到把它简单的反转过来试试。

第一关线索

0x02: 打开这个 HTTP Header 中发现的 URL 便进入第二关。这一关很简单,里面有个 URL 网址图片,似乎是被截断了,用 css 把他显示出来后发现了第三关的 URL。

第二关

0x03: 进入第三关后,有一大片的乱码,一看就知道又是 base64 编码(看来出题人很喜欢 base64 编码),解开后是一个用 Node.js 写的函数截图,这个函数的意思是,要求你猜一个数字,以16进制形式放在 URL 上提供一个他要求的参数和数值。该函数只接受 HTTP PATCH 的方式发送,他会返回你猜大了还是猜小了。于是用 postman,根据函数要求发送 HTTP 请求,猜了几次猜中数字后顺利获取第四个 URL。

第三关

 

第三关函数decode后内容

0x04: 第四关有个提示SQL inj…很自然想到用 SQL Injection 做点啥。

第四关

根据 URL 参数和页面上线索,首先尝试伪造一些 URL 参数,把 URL中的
?name=singlequote换成 ?name=' or''‘后有段出错信息,从出错信息中获取表名和字段名。

SQLite execution completed:executed: 
SELECT question from PUZZLE where name = '' or'' '' , result: {"errno":1,"code":"SQLITE_ERROR"}`

这一关花我2个多个小时时间,因为我刚开始一味的尝试往表里面 insert 数据都以失败告终。后来转变了思路,尝试把表里面的数据 query 出来试试,继续构造合适的 sql injection,终于在表中查出了最后一关 URL。
?name=' UNION SELECT answer FROM PUZZLE --

第四关解答

0x05: 这一关已经没什么挑战内容了,HTML 代码里面有个邮箱,告诉你如何发邮件过去。于是按照描述发了封邮件过去。

最后一关

2. Code excise

第二天该公司一名职位是 Digital Talent Advisor 的人和我电话联系,大概了聊了下如何闯关解开puzzle,简单问了下我的工作经验和背景,他花了较长时间介绍他们公司情况。并且问了我对工资和 title上有啥期待。吸取之前的教训,我说没有期待,只要不低于平均工资即可,最后他说会发一个code exercise,做好了发给他。

在电话沟通以后很快收到了他的邮件,职位介绍是写着是2+年以上的开发职位。这才明白他为什么会问我对 title 有什么要求了。邮件里有个 code exercise,不限定时间,不限定语言。刚开始觉得这是个非常人性化的条件,后来才发现其实有点坑,下文详叙。

题目并不难,任何一个合格的开发应该都可以轻松应对。就是给定一个 csv 文件里面包含员工的年薪,根据澳洲政府的税率(大概有5-6个档)输出一个计算结果,结果要求计算月工资单,包含税前收入,税后输入,交税额之类的。该题要注意使用查表的方法来确定工资税率档位,如果写很多 if 来判断,代码就非常难看了。这个题目的基本要求是:

  1. 列出你解决这个问题的所有前提假设条件;
  2. 描述如何运行代码;
  3. 考察的重点是good design 和good test。

决定用什么技术和语言呢?我的决策过程如下:
招聘要求上有后端语言经验 preferred Node.js,并且招聘彩蛋 puzzle 也是 Node.js 写的(HTTP 头里面有 powered by express),电话里沟通的 Digital Talent Advisor 也说他们目前使用的是 .NET, Node.js 和一点 Ruby。但是招聘要求里面有提到 .NET,我研究了下他们公司技术栈应该以 .NET 为主。而我手里只有一个Mac Book,有现成的 Node.js 环境,加上题目上写着不限定语言,所以我有点偷懒的选择了Node.js,后来证明偷懒的选择就是不好。

题目提交到 Github 后,HR 说会转去 review,一周左右会告诉我结果。一周到了我没有收到反馈,加上期间有其他公司也在面试流程中,我就写了封邮件问了情况。当天没有回复,第二天给我打电话反馈:我的代码很明显满足一个开发者的基本要求,单元测试用例也很全,但是 design 不是很好,比如没有显示的建立一些 model 去处理数据。

我在了解这家公司的过程中,发现这家公司的企业文化和我蛮契合,于是想争取更多的机会,于是又花了2天时间写了份 .NET 版本发过去(.NET Core and Visual Studio For Mac)为此我特意在 Mac 上安装了Visual Studio for Mac 和.NET Core SDK。
过了两天,说约到周五下午最后一轮面试,一共三个小时,整个过程如下文所述。

3. Face to face interview

在面试之前,这位 Digital Talent Advisor 和我详细说介绍了三小时的面试过程的具体内容,包括可能要问到的问题都一一提醒。他和我介绍的面试具体内容大概有半页A4纸,简单概括如下:

  1. Show around 办公室的环境;
  2. 开发 Leader 聊一些常规问题,考察候选人是否能契合团队和公司文化;
  3. 两个高级开发,了解我技术深度;
  4. 两个高级开发跟我过下我做的 code exercise,看看如何改进。

具体体验是这样的:
第一个小时:面试我的是开发 Leader 是一位印度裔,和我之前 team 同事名字一样,另外一位是金发美女,该金发美女也才来公司2-3个月。整个沟通过程气氛融洽,有说有笑,虽然那位印度老大的语速很快,但全程只有一两处要求他重复说一遍。这时候发现我英文其实已经够用了。该阶段唯一回答不好的问题是,他说我们招的 Develper 职位,和我简历上的最近的职位有差距,你介意吗?我的回答是:我并不介意从最底层的开发做起,虽然我确实不是非常开心的接受这个 lower level 一点的职位,但是我既然来了,我完全可以接受这个职位,而且我相信我肯定会很快晋升的。印度开发老大立马接过话:我们这里没有 low 或者不 low 的职位,只是不同工作内容而已。我才意识到给出了一个非常糟糕的答案。因为英文不是母语的原因,我用了一个 “low” 这样非常不恰当的词汇。我没有试图解释,因为这确实是我最真实的想法。

第二个小时:接下来是两个高级开发面试我,他们年纪不大,应该工作5年左右。聊起来感觉不是很舒服。主要问了我熟悉的开发过程是什么,介绍下我之前做的项目的系统设计和开发过程。他们关注的是 devops 实践,我并没有太多 devops 实施经验。所以我回答并没有达到他们的预期。最后让我给自己的 C# 水平评分,他们分别说自己是8分和9分。我说我 rate 8分吧,我有2年没有碰 .NET 了。最后自己评8分的那个面试官出了一些 .NET 题目,我也顺利答出,证明了我的 rate 应该没问题。

第三个小时:最后一部分是 review 我做的 code exercise。一个妹子和一个有点冷漠的帅哥。那个妹子一进门就问,你就是写了 JavaScript 代码的那个吗?我说是,但是我说我也写了个 .NET 的。她说她没有人告诉她(从这里可以看出,那个 Digital Talent Advisor 并没有 FW 我后来写的代码去 review,可能是他不想太麻烦他们的开发团队,也或许他觉得这样可以更公平去批判其他人)。她说没关系,你既然有 .NET 我们就 Review .NET 的吧。整个沟通过程和气氛感觉不是很自然,对面的开发比较冷漠,精神不是很好的样子。整个过程主要是围绕 TDD,她提一个要求,我改下代码,跑 test,改 test...

虽然每个阶段我都有一两个问题回答的不是很好,但我觉得自己的表现不算差。第二天那位 Digital Talent Advisor 给我打电话反馈说,开发说我们不熟悉 SOLID 之类的基础知识(面试过程中被问到一个关于 OO 设计原则的问题。我说这些我都很熟悉是基础知识,但是我想不起来了,好像是 open closed 之类,于是没有详细说下去了,其实我对这个题目有本能的反感,所以自动的说了些敷衍的话敷衍过去了),说他们很抱歉无法和我一起工作,并且祝我找工作顺利之类。我和他寒暄了几句结束了这家的面试。其实 OO 的这些原则已经融入平时工作的潜意识了,反而忘记怎么去表达了,这确实是我准备的不充分。我没有好好回答这个问题的另一个原因是因为他们刚问了我一个我毕业第一份工作被问过的问题:authentication 和 authrization 有啥区别。我虽然回答了,但是可能表现的有点不耐烦,于是再被问到 SOLID 的时候我更加本能的不耐烦了。

总结

没有给 offer 可能的原因

  1. 根据 Grassdoor 准备的问题都没有被问到,而基础的 OO Design pattern 如 SOLID 回答不好,给面试我的开发团队留下了不好的预设印象,即使其他题目答的再好,可能也会被忽略掉。
  2. 可能开发老大觉得该岗位和我并不是很匹配,因为我其间直接说了自己的真实想法。
  3. 竞争对手可能确实比我优秀,只要竞争对手有2-5本地经验,人聪明,我就没有什么优势了。

面试流程评价

总体来说,这句公司的面试体验非常棒,流程清晰,每一步都让你知道他们的要求和下一步的计划。特别是那位 Digital Talent Advisor 表现的非常专业,给人感觉很好。那个印度的开发老大沟通起来给人感觉也很专业,人也很随和。

他们的办公室环境是我见过最好的,和 Google 有的一拼,健身房,厨房各种生活设置一应俱全。会议室装修的和咖啡厅一样,办公室无固定座位,办公桌子可以随意移动,可坐可站,标配2台显示器。某个角落还有Xbox 和 Play Station。

我觉得该公司可以做的更好的地方是:对候选人的评估缺乏统一标准,导致可能对候选人在一两个问题上的失误会被放大。就拿他们的 code exercise 来说:在不限定语言的条件下,review的人很难做到在一个起跑线上衡量一个面试者水平。他们的初衷是可能是好的,想要试图展现他们自由的工作空间和和工程师文化。但是导致的结果是,你很难拿 JavaScript 代码和 .NET 比。而 review 你代码的人也不一定能体现某些代码的某些好坏,加上写代码的手艺人,倾向于觉得别人代码写的烂,所以更需要一些标准的东西的存在。当然也有可能他们是想通过这个 code exercise 来考察候选人是否具有 Do right thing 的能力,如果是这样的话,我最终 fail 掉也属正常了。

给自己和其他面试者的建议

  1. 如果你非常喜欢一家公司,多和这家公司保持沟通,面试过程要积极主动争取一切表现机会;
  2. 如果想提高拿到一家公司 offer 的概率,你可以选择不要总是坦诚的透漏自己的一切想法和底线,除非是你非常在意的问题;
  3. Do the right thing,选择更重要,选择怎么做和做什么,比傻乎乎的把一件傻乎乎的事情做好更重要;
  4. 你无法预知面试官的习惯和爱好,所以要尽可能多的准备一些常见问题,包括你觉得很弱智的问题都要认真准备,毕竟,最终目标是过了面试这一关。如果被问到弱智问题你却答不好,只能证明自己更弱智,无他。
  5. 公司没有给你 offer,仅代表他们的面试流程判断你不适合这个职位而已。至于你能否胜任该职位,你自己真实能力究竟如何,关系不是特别大。没有 offer 后要迅速调整心态,总结经验,继续前进。
  6. 不能盲目自信,不能因为觉得某个面试很有把握后而放弃其他机会,在没有拿到offer之前,一定要继续保持简历投递的节奏,增加输入。

下一篇打算写写另一家令我印象深刻的公司 Aconex,这家公司是我自己在 LinkedIn 上投递的公司。Aconex 后会写一篇关于如何设计技术面试的文章,算是总结下自己这些年面试别人和被别人面试的经验,作为此系列的终结。