精子最近在 第一届烧火节 中体验了钻木取火,并制作了第一个 Vlog。

如何进行技术面试(面试官视角)

我参加过几十场技术面试,其中作为面试官的次数要远多于候选人。

说起来在我第一次做面试官之前,并没有人教过我应该怎么做,我则一直将面试视作通过一小时左右的沟通,对候选人形成一个整体的印象,最后给出一个主观的评价的过程。在这么多次的面试中,我也总结出了一些经验可以和大家分享。

验证简历真实性

首先花一些时间聊一聊简历上提到的项目,请对方进一步介绍这个项目的业务、自己在其中承担的职责和遇到的问题。然后针对其中自己了解的部分提几个问题,如「据我所知这类项目的难点是某某方面,请问你是否有遇到、是如何解决的」,确认对方的项目经验是否真实、是否比较深度地参与了项目。

围绕简历提问

尽量提问对方了解和擅长的话题,让对方有足够的表达机会,发挥出正常水平,考察候选人擅长的部分要比不擅长的部分更有价值。

开放性问题

避免问有标准答案的问题,而是可以问「遇到某种情况时可能是什么原因、你会怎么做」或「请解释一下某个事物是如何工作的」这样开放性的问题,给对方足够的发挥空间、主动提到一些自己的知识和经验。

也许有些候选人不喜欢这样的问题,认为缺少安全感、不知道该说什么,但我觉得开放性问题才有足够的区分度,才能在短时间内对候选人形成立体的印象。我们可以在候选人实在不知道从何说起时,对问题再做进一步的解释和提示。

围绕话题由浅入深

应该针对同一话题准备多个难度逐步增加的问题,让对方回答时思路能够相对流畅,更容易考察对方在这一话题上的深度;反过来应该避免大量零散、无联系、无难度区分的小问题。

没必要执着于答案

有时在反复提示下对方的答案仍差那么一点,在面试时间大多比较紧张的情况下,我们没必要花更多的时间去让对方答出答案。在候选人表示无法准确回答问题时,也可以引导他做出一些合理的猜测(这时的重点在于猜测是否合理而不是是否正确)。只要候选人在这一问题上说足够多的话,我们就可以考察到其水平了,不一定要等他说出最后的答案。

自己不懂也没关系

在一开始,我会担心问出的问题我自己也不了解,对方回答之后会把自己问倒或者无法考察对方水平。但后来发现完全没有必要,因为面试官没有义务即时地对候选人的回答做出评价(告诉对方对还是错),即使对于不了解的话题,自己也可以从对方的自信程度、逻辑层面,对回答有一个大体的判断的。

现场编码可以很简单

候选人在现场会非常紧张,面试时间也有限,在现场编码环节没必要出太难的题,重点在于考察候选人是否有最基本编程思维和编码能力。例如我觉得一些难度不高,但适合用递归解决的题目会比较合适,可以考虑在候选人编码的过程中一直保持沟通,注重过程而不是结果。

同时我反对为候选人在面试前或面试后布置编码的作业,这会让候选人付出不对等的时间去准备面试,也很容易从「考察候选人的能力」变成「考察候选人的诚意」。

重复使用一套题库没什么问题

可以自己建立自己的面试题库,在一次次面试中对其进行反复地打磨,让问题更准确、考察更全面。有些话题可能是永远都不过时的,例如对于后端工程师可能是并发模型及与之相关的线程、内存等话题。

给对方提问的机会

一般面试的最后一个步骤是让候选人提问,不要把这个过程敷衍掉,可以引导对方提问,告诉对方都可以问哪些问题。如可以补充一下没有提及的技术话题、可以问我司的技术架构或选型、可以问所面试的职位和如果入职之后所参与的项目、可以问日常工作环境和时间等。这样可以让对方有一个主动打开话题的机会,互相判断需求是否匹配,即使没有通过面试也让对方对公司有一个比较好的印象。

有任何顾虑都可以 pass 掉

我们前面做了这么多都是为了让候选人有更好的面试体验、发挥出自己最好的水平。这种情况下如果仍对候选人某一方面的表现有顾虑的话,应该果断地拒绝掉,招进来一个不合适的人损失远比错过一个合适的人大。

沟通是否顺畅很重要

沟通是后续开展一切工作的基础,如果觉得与候选人的沟通不顺畅,对方总是不能理解自己的意思,那么即使候选人的技术水平满足要求,也应该慎重考虑。

留下面试的记录

我每次面试结束后都会尽快开始写对候选人的评价,大多在一两百字,先列出面试聊到的内容、觉得好和不好的地方、了解到的对方的技术栈,然后总结一下对候选人技术水平和沟通情况的评价。这样可以帮助自己整理思路,在候选人比较多的时候也不会记混,最后给出通过与否的评价,同时还能给下一轮的面试官提供参考。

2021 年度小结

2021 年新冠疫情仍然没有结束,我们甚至已经习惯了它的存在。

和蛋黄在昆山住了三年之后,今年最大的变化是我们搬到了上海。相比于之前在北京的一年,因为收入更高了也有条件在上海租更好的房子,离公司和地铁站都非常近,面积也并 不比昆山的房子小太多

因为在走之前我有些舍不得我投入了这么多精力改造的家,直到搬走前三天我们才开始高强度地打包收拾。这次我们的物品达到了 惊人的 1000 千克、7.9 立方米,到了上海后又断断续续花了一个月收拾,买了沙发、桌子、电视、洗衣机、新的净水器,再次自己安装了窗帘杆,为了将洗碗机和洗衣机放到理想的位置做了不少改造,对于选择哪个房间做卧室(同时也决定了我们的桌子如何摆放)也纠结了很久。在又投入了这么多精力之后,我发现我也不会去想到昆山了,毕竟当下才是自己最理想的家。

2021/2021-shanghai-1.png

2021/2021-shanghai-2.png

上海的确有更多的地方可以逛、可以玩,但因为我周末总是下午才起床,所以我们不经常去比较远的地方。而是就像 2020 年一样,在夜里骑着电动车说走就走,走遍了家附近方圆七、八公里的区域。

2021/2021-shanghai-3.png

新的环境也确实对我的情绪有一些改善。想到和蛋黄刚在一起的时候就说「重要的是我们在一起并不需要做出什么改变就可以很开心,而不一定要按照社会的期待去改变自己」,我得承认在一些事情上我没有做到,有时候会因为觉得大家都可以这样做而去要求蛋黄。但她却一直是这样做的,会包容我所有和其他人不一样的地方,从未要求我改变什么。

在工作方面最大的变化则是 LeanCloud 被心动收购,团队整体加入了 TapTap,办公地点也搬到了上海。公司被收购是一种非常独特的体验,整个过程充满了不确定性,自己和同事们也都在考虑各自后续的变化 —— 其实说起来那两个月都没什么心思工作。最后尘埃落定,加入一个新的公司时,你既是老员工,也是新员工,也有了更多的时间去审视自己与公司的关系。

我一直对于大公司非常抵触,我也绝对不会加入像阿里巴巴、拼多多、华为这样的公司。当公司规模大到老板无法知道每一个人在做什么的时候,就会开始引入组织架构。这种变化一方面带来了效率的降低 —— 部门间的利益和公司的利益不一定是一致的,需要大量的管理来「对齐」;另一方面也带来了一种系统性的压迫 —— 公司与员工的力量是如此地悬殊,制定和执行规则的人也与员工离得更远,他们会充分利用合同和协议将风险全部转移到员工身上,在这里要感谢我之前的两家公司从未让我有过这样的感觉。

心动的 CEO 黄一孟 在社交媒体上很活跃,也曾分享过心动使用 Slack 和 Confluence 实现内部透明,TapTap 的「离职致意金」和无限假期等政策,尤其后两者以我的理解是在倒逼中层管理人员来提高管理水平,及时辞退不合适的员工。且不论结果如何,对于这种解决「大公司问题」的尝试我是认可的,也是心动不同于同等规模公司的地方。

今年下半年受邀参与了几个智能合约项目的代码审计,虽然实际完成的工作很少,但也算是补习了近几年智能合约和 DeFi 的发展。可以看到现在已经很少有人再去质疑 Bitcoin 或者 Ethereum 的意义了,而是将焦点放在了 DeFi 和 NFT 上,这说明了整个密码货币产业还在不断在向前发展,我几年前曾写过 一篇文章 说比特币是一场实验,那么我觉得在今天这个时间点可以说这场实验已经成功了。

2021/2021-cryptocurrency.png

图为我持有的所有密码货币在 2021 年的波动

继软路由和 NAS 之后,今年投入了一些时间搭建 基于 Home Assistant 的智能家居,花的精力不算太多,主要是将部分受支持的米家设备接入了操作体验更好的 HomeKit。

今年 和蛋黄一起玩了双人成行、底特律:成为人类 和 DYSMANTLE,不同于之前引导蛋黄玩游戏的尝试,这三部作品都是素质过硬且适合双人游玩的游戏,我们也都通关了这三部作品。

我们并不需要 Deno

Deno 一出生便带着光环 —— 它发布于 Node.js 创始人 Ryan Dahl 的演讲「Design Mistakes in Node幻灯片)」,当时有些人说 Node.js 要凉了,但我不这么认为。

原生 TypeScript

其实目前我们在引擎的「用户态」去使用 TypeScript 并没有引入任何问题,而且给用户带来了很大的灵活性。考虑到 TypeScript 不可能离开 JavaScript 的生态 —— 毕竟引擎总是要支持 JavaScript 的;再加上 TypeScript 有不同的版本、不同的编译开关,在用户态使用 TypeScript 可以说是最好的方案了。TypeScirpt 迟早会成为 Deno 的历史包袱。

从性能的角度,在 TypeScript 没出现之前,V8 已经在 JavaScript 上进行大量 魔法优化 了,可以说 JIT 出来的代码并不比其他静态类型的语言差太多,是没法简单地通过 TypeScript 来提升性能的。再加上前面说了引擎总还是要支持 JavaScript、TypeScript 的运行时语义依然是 JavaScript(TypeScript 并不能保证对象的实际类型在运行时不被修改),所以引擎也不可能从对 JavaScript 的魔法优化切换到基于 TypeScript 的类型来做优化。

包管理器

我一直认为 NPM 是最好用的包管理器之一,这包括将依赖保存在项目目录中 —— 在调整一个项目的依赖时不必担心对其他项目产生影响;每个包都可以指定自己的依赖版本,允许多版本并存 —— 在升级一个包的依赖时不会影响到其他包,每个包都可以使用新的版本或继续使用旧的版本;NPM 负责查找和安装包,而 Node.js 则用相对简单的协议去使用这些包,它们可以彼此独立地升级演进。

可以看到 NPM 最终极大地减轻了开发者的心智负担,只要你按照正确的方式去使用它,极少会遇到其他语言中有关依赖管理的问题。而 Deno 则反其道行之。虽然 Deno 也提供了一些相关的功能(deno cache),但你会发现 Deno 的本意仍然是不希望进行「依赖管理」。

在代码中包含 URL 是一个非常糟糕的做法(Golang 也是如此),Deno 称之为去中心化,但其实它只是重新将使用包的代码与包的来源耦合在了一起(现在 Deno 提供了一个 官方的代理,但这样和 NPM 的中心仓库又有什么区别呢)。缓存机制也带来了相当大的不确定性:package-lock.json 可以保证每次安装的依赖是完全一致的,而 Deno 的 lock.json 只能检查依赖是否有变化(如果有的话就拒绝运行)。这使得开发者很难控制依赖更新的时机,Deno 则建议将依赖缓存放入 Git

内建权限系统

一直以来通用编程语言都不曾在语言层面引入权限控制,但确实开源社区也曾报出过多次恶意代码的事件,但 Deno 的权限机制相当粗糙 —— 只能在进程级别进行权限控制,我可以大胆地预言,在几乎所有的场景里我们都需要 --allow-all,并不能对安全起到太多作用。

我们需要考虑 Deno 的用户到底是开发者还是使用者:对于 Deno 脚本的使用者来说关注的当然是进程级别的权限;而对于开发者我认为更关注的是第三方包的权限,权限系统应该以包为单位(然而 Deno 里并没有包的概念了),Node 里本来也有 vm 模块可以一定程度上实现沙盒(但确实非常难以控制)。

而且说起来我们现在已经有了 Docker(或者更广泛的容器的概念)这种彻底的隔离和权限控制机制,业界对编程语言引入一套权限控制已经没有太大的需求了。

孤立的生态

可以说 JavaScript 的生态来自于用户态类库的充分竞争,Deno 则在 Runtime API 之外提供了 Standard Library(类似 golang.org/x)、提供了全套的开发工具链(fmt、test、doc、lint、bundle),在试图提供开箱即用的使用体验的同时,也削弱了第三方生态。

在 Node.js 和 NPM 已然成为 JavaScript 事实标准的一部分的情况下,Deno 本来可以通过兼容 Node.js 或 NPM 有一个非常好的开场。但 Deno 却选择了和 Node.js 划清界限,而是兼容了一些浏览器环境的 API(如 prompt 或 onload)。

Deno 自己的说法是为了遵循已有的 Web 标准避免发明新东西,但实际上这些 Web 标准在设计时并未充分考虑浏览器之外的 Runtime,况且 Deno 其实也没能避免发明新东西(这些新东西被放在了 Deno 这个命名空间中)。

小结

Deno 就是这样一个有着非常鲜明个人偏好的 JavaScript Runtime,它试图去纠正 Node.js 的一些「设计失误」、希望给出一种「JavaScript 最佳实践」,希望提供高质量且开箱即用的标准库和工具链。这些偏好的选择总会有人喜欢或不喜欢,但除此之外 Deno 实在是缺少一个 killer feature(杀手级特性)让一个「理性」的 Node.js 开发者(如一个公司)切换到 Deno。

通过单一文件发行、进程级别的权限控制使 Deno 会更适合命令行工具的开发,但能否与已经广泛用于命令行工具的 Golang 竞争尚且存疑。

作为一个 Node.js 开发者,我并不觉得 Deno 可以在未来替代 Node 成为我的主力开发工具,Deno 更像是 Golang 的设计哲学对 JavaScript 的一次入侵。

12382

精子生于 1995 年,英文 ID jysperm.

订阅推送

通过邮件订阅精子的博客日志、产品和项目的最新动态,精子承诺每一封邮件都会认真撰写(历史邮件),有想和精子说的话也可以直接回复邮件。

该博客使用基于  Hexo  的  simpleblock  主题。博客内容使用  CC BY-NC-ND  授权发布。最后生成于 2022-05-14.