程序员如何准备技术面试

程序员如何准备技术面试

本文章由 ResumeJob 撰写,ResumeJob 能帮助你审视简历,模拟面试,重新规划你的职业生涯。我们团队在国内外公司面试过数百名的工程师,浏览过千份简历,志在帮助程序员找到合适自己的工作,如果你想知道简历哪里出现问题或者想在面试前进行模拟面试的话,欢迎联系我们,了解更多细节欢迎浏览 resumejob.net/

求职系列文章:

概述

刚开始参加工作的时候,我对面试总是很恐惧,既担心简历无法通过初筛,也担心即使简历通过筛选,因为面试经验不多以及基础知识不扎实而导致发挥不好。有一次,我拿着普通的简历(专业不是计算机,作品也没多少)也得到了一线大厂的面试机会,但是因为根本没有准备,也不知道怎么准备。自然地,那次面试我表现得不好,也没有得到 Offer。

恐惧也使我不想浪费时间去面试不同类型的公司。我当初并不知道对比其他求职者,自己的优势和劣势在哪里,也不知道如何去准备面试,面试官看重的是哪些方面,更不知道自己到底值多少钱。现在回过头看,我觉得当初只是在欺骗自己,我真正担心的是即使自己认真准备简历和面试也对结果毫无影响,更不敢去想如果放弃某个 Offer,找不到其他工作怎么办。

工作了几年,当我有了越来越多的面试官的经验之后,我越来越发现认真准备简历和面试是非常重要的,因为毫无准备就来面试的求职者真的太多了。而且互联网公司招聘到合适的工程师实在非常难,有计算机基础知识,有项目经验,愿意学习而且愿意来这家公司,实在不好找。所以只要求职者能证明自己有一定的计算机水平并且愿意努力,市场上还是有非常多机会的。

这篇文章我把这几年作为面试者和面试官身份的的经验給大家,希望大家可以从中学到一些面试的技巧,找到心仪的工作。大家也可以使用 ResumeJob 进行简历 Review 和模拟面试,这样既能节省请假面试的时间,也能根据我们的反馈改善自己面试的表现。在真实面试的时候就会更有把握。

分析阶段

  1. 公司需要怎样的员工

我很喜欢 Google 前 CEO 施密特分享的一个故事,他刚到 Google 的时候,Google 还只是个小的创业公司。他一开始以为 Google 和其他公司没什么两样,直到有一个周五,拉里佩奇在用谷歌搜索一些关键字的时候,他发现出现了一些不相干的广告推荐(这个情况我们现在在国内最大的搜索引擎也经常看到)。施密特以为接下来就是开几个会议,然后分到具体的工程师手上解决。但是拉里佩奇没有这么做,他用纸条写下 "These Ads Suck!",附上相关的截图贴在布告栏上就回家了。接下来的 72 小时彻底改变了施密特的认知。在周一凌晨 5点,有几位并不是负责广告业务的工程师发来一份邮件,从头到尾阐述了这个问题产生的原因,他们的解决方案,以及这个计划对公司有什么影响。他们自愿自发地用周末的时间去解决并不属于自己范畴的问题,因为他们相信其他同事不会因为他们抢了工作而怀恨在心。

这样的员工我想就是每个公司都需要的:

  • 不错的技术能力,工作认真负责,可以及时解决问题,能给公司带来实际效益
  • 出色的团队合作精神,能与团队一起成长
  • 愿意自我学习,投资自己

所以求职者的简历与面试中必须能体现出这几点品质,并且与其他求职者区分开来。举个例子,在简历我常常看到这样的描述:

热爱计算机,喜欢学习计算机系统的知识。

如果你你也这样写,那么完全体现不出自己的优点,可以根据实际情况改为:

喜欢阅读计算机系统的书籍,完成《深入理解计算机系统》80% 以上的习题。并在博客(链接)分享学到的知识。

这样不留痕迹地引导 HR 打开博客,进一步地了解求职者已经击败了其他 80% 的求职者了。另外,一些软技能,例如团队合作能力也是面试官非常注重的一点,面试过程中如果被问到有没有带领团队的经验,即使没有也不要简单地回答没有,可以这样回答:

“我在以往的项目中与团队成员都能融洽相处,并且每个月都会做定期的技术分享互相学习,虽然没有带团队的机会,但是相信自己能够做到。”

当然这些回答不可能一下子能想到,面试方面的技巧必须多练。如何写简历可以参考我们这篇文章:程序员如何写一份更好的简历。未雨绸缪对于一位工程师尤为重要,等到离职再找工作就比较晚了。在职期间定期找几家公司面试练练手,一方面能知道市场的行情,找到其他更好工作机会,另一方面本身自己就有工作,等于手拿一个 Offer,面试的时候就能比较放松。

2. 员工需要怎样的公司

找新工作之前,你需要先认真思考下几个问题,一份工作中最看重的是哪些方面?

  • 薪酬
  • 公司名气与规模
  • 公司福利/工作环境 / 地点 / 工作时长
  • 工作方向(这个岗位可以让你从技术转向管理吗?)
  • 工程师文化
  • 个人成长

有时候薪酬远不及公司名气与规模 / 工程师文化重要,有的公司能聚集一批优秀的工程师,那么只要认真待一两年,进步速度远比其他地方快,以后跳槽也会更加容易。有的厂则能提供大量隐性的福利(国内可以参考腾讯)。求职者需要真正地去思考自己想要去怎么样的公司,工作和找男女朋友一样,找你喜欢的,而不是找你能找到的。

了解自己的想法之后,求职者可以根据自己的着重点,筛选公司,修改简历,复习常见面试题以及准备向面试官提问的问题。 最后这部分的提问非常重要,我常常期待求职者在面试结束后能问一些问题,但是很多求职者却没有,一方面怕面试官会觉得自己有很多要求,留下的印象不好,另一方面根本没有想好要问什么。这点我觉得非常不明智,公司和员工就是互相选择的,一定要多提问题,了解公司的文化以及岗位的职责。才不至于刚入职就因为不适应而要离开。这点我们在面试阶段会介绍。

3. 了解自己的优势

根据自己的目标岗位强调自己的优势。例如,如果求职者要面试的是开发工程师,就应该突出项目经验以及对框架的熟悉程度,如果面试的是研究岗位,那么论文与文章的数量就比较重要。然后在简历以及面试过程中突出,优势可以从这几点入手,后面是面试官的理解:

  • 大厂或者大型项目的经验 (能解决项目普遍出现的问题,技术水平靠谱)
  • 作为主要参与者得过比赛名次(聪明,勇于尝试)
  • 毕业于不错的学校(学习努力,认真)
  • 维护优秀的开源项目 (懂得团队协作,喜欢学习,愿意了解项目原理)
  • 发表过论文或者优秀的博客文章(研究能力强,分析能力强)
  • 数据结构和算法基础好,Leetcode 做了不少题(基础不错,培养起来也简单)

准备阶段

  1. 随时都在准备

随时准备并不是鼓励频繁地跳槽,而是要有随时有跳出舒服圈的准备,也许求职者已经很满意现在的工作,薪酬,觉得习惯而且安逸。不过如果公司突然倒闭,或者部门被裁减,还能找到这样或者更好的工作吗?我建议各位,每两三个月可以去面试一两家公司,因为你已经有不错的工作了,所以可以带着轻松的心态去面试,同时也可以增加面试的经验。

2. 技术基础

  • 基础知识

基础知识主要包括:编程语言基础,算法基础,计算机网络,操作系统,数据库。面试之前的复习阶段非常重要,通常大家会通过阅读各类的书籍来补充自己的基础知识。但是计算机方面的书大多是大部头而且艰深,一时间也看不完。所以我在程序员面试推荐书籍这篇文章中列出了面试常见的问题以及对应的解答书籍供大家参考,希望大家带着问题去看书,也可以从某些章节看起,这样会更加有目标与效率。

1. 编程语言基础

  • 数据结构的实现细节以及比较:数组,链表,哈希表是如何实现的,底层内存分配是怎样的?插入与查找的时间复杂度是多少,分别有什么优缺点。
  • 编程语言特性: Java 的字符串池是怎么实现的,垃圾回收的流程以及原理。
  • 关键字特性:包括 Java 中的 static,final,Python 中的 __init__ 关键字的含义以及使用场景。面向对象的细节:类的封装,函数与变量继承,抽象类和接口有什么区别等。
  • 多线程与多进程:线程如何同步,进程如何同步,wait() 函数使用场景以及常用的并发编程模式。

2. 算法基础

  • 算法题:链表操作,二分查找,动态规划,DFS,BFS 等(可以使用 Leetcode 来进行学习)。
  • 算法复杂度的分析:时间复杂度,空间复杂度,平均时间复杂度。
  • 数据结构的实现:实现二叉查找树,Trie 树。

基础的算法题,大厂都会考。刷算法题的时候,要把每道题都当成面试题一样按步骤完成,完成一题之后总结经验。这样遇到变形题也迎刃而解。这里我推荐 Leetcode 以及 Hackerrank。这里说一点题外话,可能有的同学有疑问,觉得这些平常工作都用不到,为什么还要花那么多时间在上面。其实不是的,第一,平常工作都能用到,无论从二分查找到复杂一点的前缀树。开发的过程中如果你知道这些算法/数据结构,就能根据自己的业务来选择最适合的算法/数据结构,减少整个项目的复杂度。 第二,数据结构和算法锻炼的是思维,刷算法题的时候,慢慢会学习到一些有趣的,巧妙的方法。它们能扩展你的编程时思考的范围。同时也要求你考虑到各种不同的边界情况。即使你不准备换工作,我也建议每天都刷一道算法题,日积月累,一年下来你的算法基础一定能比同龄人高出不少。而且当你真正理解算法题的知识之后,写程序 debug 和花在 Stackoverflow 的时间就会大大减少,往往知道哪里可能有问题并且能大幅地增加工作效率。

3. 计算机网络

  • 协议的基础组成与用途:HTTP 协议中不同头部,方法,状态码的含义。
  • 协议的使用场景:DNS 协议,ARP 协议,SSH 命令的使用场景以及原理。
  • 不同协议的区别:TCP 与 UDP 的区别,HTTP 与 HTTPS 的区别。
  • 协议具体功能实现:TCP 三次握手原理,TCP 慢启动以及滑动窗口的原理与实现方式。

4. 操作系统

  • 操作系统基础概念:进程,线程,虚拟内存,文件权限,信号量等概念考察。
  • Shell 的基础使用:ls, find, top, ps 等命令的应用与原理。
  • 常见功能的实现:进程调度,用户态与内核态的切换,各类系统调用的实现方式,epoll 的实现。
  • 常用函数的实现:memcpy,strcpy,strstr 等常用库函数的实现方式与优化。

5. 数据库

  • 基本概念:事务,存储引擎,隔离级别,索引等概念考察。
  • 数据库基准测试与性能分析:基准测试的策略,性能剖析工具的使用和分析。
  • 数据库设计与优化:范式和反范式,索引的类型,如何选择合适的索引,如何使用硬件优化。
  • 数据库原理及高级特性:数据库分区分表,存储过程的使用,全文索引,主从热备等常用策略的使用与原理。

3. 积累项目经验

  • 公司的过往项目
    国内的技术公司,相对重视项目经验,所以在面试前,曾经参与过的项目需要认真回顾一遍,从技术选型,架构设计(即使是中途加入项目也应该对此有所了解),维护或者实现的功能细节,过程中遇到的技术难点,学到了什么知识,都可能被问到,常见的问题是有:这个项目遇到了什么技术难点,你是如何解决的?这个项目你学习到了哪些技术知识点?
  • 开源项目
    开源项目可以让你和世界上顶级的工程师一起工作,学习软件设计以及语言的高级使用方法。同时能让你理解软件是如何运行 / 设计的。
  • 参与较底层/偏向算法或研究的项目
    如果求职者未来想从开发转向研究的岗位,那么就可以阅读一些相关学术论文,写相关的文章分析与工具。
  • 造轮子,实用工具
    从学习的角度来说,造轮子可以说是最好的方法,不过要给自己一个期限,不能无止境地把时间花费在程序的细节与优化中。知道原理,能够实现就足够了。尝试实现平时常用的 Web 服务器,Web 框架开始,有时间的话可以延展到操作系统或者编程语言(我遇到过这样的求职者)。自己写完再看看别人是如何实现的,学习他的优点。其实到最后,你会发现计算机是越学越容易的,如果你不了解同步异步,往往是因为你不知道 Web 服务器是如何实现,不知道系统调用是如何实现的。当你能自己去实现的时候,很多以前的问题也就迎刃而解了。
  • 写论文,分享文章
    如何宣传你的开源项目或者业余项目?写一篇优秀的文章介绍它。同理,要证明你有喜欢计算机,有研究的能力,最好的方法也是写一些优秀的文章以及论文。

4. 模拟面试

如果你准备去面试一家非常喜欢的公司,那么面试之前,你应该先进行模拟面试,模拟面试的意思是让另外一名工程师充当面试官,按照该公司的题库以及流程对你进行面试,然后再把面试过程中的优点和缺点反馈给你。模拟面试既可以让你的朋友当面试官来面试你,也可以去找几家有类似岗位的公司。因为当你本来就没有一定要进该公司的想法,那么心态自然就能放轻松,带着轻松的心态去面试的话更能发挥好,给自己信心,同时也可以问问面试官自己哪里不足,可以加强的。经过总结后,锻炼自己面试的技巧,包括技术的基础,以及如何问问题。当你面试得多了,会发现问题其实都差不多,下次遇到也知道怎么回答了。你可以选择 Resumejob 或者以英文为沟通语言的 Pramp 来训练。

5. 选择公司

前几家公司的选择对你的职业规划会有很大的影响,大公司还是小公司,和你个人的性格或者职业规划有直接的关系:

大公司

优势

  • 入职薪酬较高,每年固定调薪,员工福利例如下午茶,文娱活动,年假都有保证。
  • 通常都有大牛,而且工程师比较多,总能遇到一些志同道合的朋友。
  • 跳槽到小公司比较容易,岗位也能得到提升。

劣势

  • 刚进去的时候接手的可能都是比较枯燥的小项目。
  • 可能需要维护几年前的没有文档没有测试的项目。(其实也能学习到很多)
  • 比较容易安逸,缺乏学习的动力。

小公司

优势

  • 相对来说,条条框框没那么多,偶尔迟到请假没什么关系。
  • 什么都能学到,从开发到运维到测试。
  • 项目可以加上自己的建议和想法,比较有成就感。
  • 能直接向老板汇报,升职速度比较快。
  • 万一上市了呢?(中国每天有一万家公司注册,上市的嘛...)

劣势

  • 入职薪酬比较低,员工福利嘛,不能保证。
  • 有大牛的可能比较少,除非你事先知道(所以面试问问题非常重要)。
  • 加班压力通常比较大,而且公司不一定会根据你的加班时间就涨薪。
  • 跳槽到大公司比较难,除非你有非常好的简历与能力。

在国内来说,除了一些很 geek 的小公司,一般的小公司并没有那么自由,加班也可能很多。所有我觉得一开始选择大公司往往是不错的选择,之后跳槽的选择范围也更多。

面试阶段

  • HR 电话确认
  • 电话面试
  • 家庭作业
  • 现场面试
  • 非技术问题
  • 求职者提问

当你得到了面试的机会,开始进入重头戏了,无论你的履历如何出众,都不能对面试掉以轻心。我遇过不少简历不错但是面试一塌糊涂的求职者,结果当然没有录用他们。起码翻转二叉树要会写吧 :D,面试一般会有几轮:

1. HR 电话确认

HR 会和你聊下天,确保你了解这个岗位的基本信息。问几个关于你简历的问题,这轮只是考核下你的基础信息是否正确,谈吐是否正常,对自己简历是否了解(相信我,很多求职者如果不看自己的简历,连自我介绍都做不到)这轮放轻松,按照简历实话实话就好。通过之后 HR 会和你约定技术面试的时间,方式,使用的工具等内容,

2. 远程面试

这是技术面试的第一轮,谷歌会使用 hangouts 或者 bluejeans 进行视频面试,微软会使用 iTeams 进行电话面试,也会使用不同的在线写代码的平台。确保自己在面试前知道怎么用这些工具并测试网络的稳定是重要的一步。面试官通过电话或者视频问一些技术问题,也可能是通过把算法题目发在在线文档,然后让你去解决。一般都是算法,数据结构的基础问题。如果遇到难的也不需要担心,提供解题的思路,即使最后不能 bug free,起码也能向面试官证明你的实力。

3. 家庭作业

这轮并不常见,有的公司会让你实现一个小模块或者小工具。主要考核你实际情况下的开发能力。这点就要靠平时积累了,如何设计 API,使用什么设计模式,都有讲究。维护好的 commit messages 以及文档都很重要。平时多看看开源项目源码就好。Python 的话我推荐看 Requests 源码,常用而且简单易懂。

4. 现场面试

面试官会根据简历问一些项目上的问题,例如这个项目为什么要这么设计,开发过程中遇到最大的困难是什么。大厂的话,算法题是跑不掉的,面试官会出几道算法题写在白纸或者白板上。我明白很多求职者不喜欢白板面试,也觉得白板面试没什么意义。不过在我面试的求职者中,白板面试能力强的在实际工作中表现得也比较优异。白板面试确实难,不但对于你,对于其他求职者也是。要是你能做到,别人做不到,你就能在众多求职者中突围而出。 简述一下解算法题的几个步骤:

出个经典题目 Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice.
给出一个整数数组和一个目标数,返回两个索引值,它们对应的数组元素的和等于目标数,只有一个答案。

例子:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

4.1 提问

这阶段的提问非常重要,因为你要 100% 地了解题目,才能解决题目。不要觉得提问得多显得愚蠢,提问得多代表你在思考,没有问题我反而会担心求职者是不是之前做过这题,或者根本没有思路。

  1. 这是一个有序数组吗? 不是(注意这里有个小陷阱,虽然在 Example 中给出的是一个有序数组,但是实际题目并没说这是一个有序数组,所以要考虑无序以及为空等边界条件)
  2. 数组可以包含负数吗? 不可以
  3. 如果数组为空或者只包含一个数字,是没有答案吗?对的
  4. 时间复杂度和空间复杂度有限制吗?没有

题目就转变成

一个只包含正整数的无序数组,要求返回两个不同的数组索引值,它们对应的数组元素的和正好等于目标数,如果数组为空或者只包含一个数字的话没有答案,其他情况有且只有一个答案。

这样就能排除一些边界情况了。然后写测试用例

4.2 测试用例

target = 9
# 测试用例
[], 返回 []
[1], 返回 []
[2, 7], 返回 [0,1]
[2, 5, 7], 返回 [0, 2]
[5, 4, 2],返回 [0, 1]

空的,只有一个元素,正序,逆序,正常情况都写下来,面试官会对你考虑到那么多情况而加分。

4.3 思考

先想想会用什么数据结构,链表,哈希表,堆,栈,二叉树,哪个结构能解决这个问题?如果真的没有思路的话,思考了之后,可以请面试官给点提示,这个其实也是团队合作的一种表现,请求提示不一定面试官就觉得你能力不行。

4.4 阐述

边思考边向面试官说出你的思路,虽然一开始你的思路可能比较乱。但是没关系。要大声肯定地说出自己的想法,同时可以向面试官提问,这样比看着题目 10分钟 不知所措要好得多。我面试过几位求职者,虽然他们没有顺利地完成算法题,但是能一直说出自己的思路,给我留下不错的印象。就像我之前说的,有些难题,面试官并不是期望你都能答对,只不过想知道你遇到难题是如何思考的,所以阐述自己的想法是非常重要的。

4.5 伪代码

如果数组长度小于2,返回False
建立一个哈希表
遍历数组每一个元素:
    如果目标值减去元素值在哈希表中
        返回该索引与当前索引
    否则把当前索引与值添加到哈希表中

分析解法的时间复杂度与空间复杂度,在这个题目中时间复杂度与空间复杂度都为O(n),其中 n 为数组的长度。

4.6 代码

这题算简单:

class Solution(object):
    def twoSum(self, nums, target):
        # 如果数组长度少于2的话,无解
        if len(nums) <= 1:
            return False
        tem_dict = {}
        for i in range(len(nums)):
            # 检测这个元素是否曾经出现过
            if nums[i] in tem_dict:
                return [tem_dict[nums[i]], i]
            else:
                tem_dict[target - nums[i]] = i

4.7 检查

把测试用例带进去代码中检查,然后看看哪里可能会有问题,做出修改。

4.8 非技术问题

接下来面试官可能会问一些非技术的问题:

  • Q: 为什么选择这家公司?
  • A: 面试之前对起码要浏览过公司的网站,了解公司有什么产品,这样既可以防止遇到皮包公司,或者小作坊欠薪拖薪。
  • Q: 你曾经面临最大的专业挑战是什么?你是怎么战胜它的?
  • A: 这个一定要准备好,不能说没什么挑战,没什么挑战代表你没有认真去思考,对你在简历中的每一个项目,你都应该能说出里面最大的挑战,最有趣的部分是什么,这样面试官才能真正理解你在项目中做了什么,学习到什么。就算是最简单的增删改查或者前端的动效,背后的原理,网络协议的原理,你都应该去了解。
  • Q: 是什么为什么你选择离开你现任公司?你从你上一家公司学到最重要的是什么?
  • A: 大多数求职者不喜欢这个问题,也不知道怎么回答。这个问题你能回答好的话就能拉出距离了。我觉得答案其实很简单,你们公司的项目有更好的发展前景/我想挑战自己在这一方面的能力等等。至于说旧公司薪酬太低,工时太长,没前途这些就免了。
  • Q: 你的长期工作目标是什么?
  • A: 这个看个人,但是必须要有未来三年自己的定位,我遇过很多求职者没有长远规划以及目标,代表他们并没有认真思考自己的未来,这往往不是一位优秀的工程师的兆头。

4.9 求职者提问

这点非常重要,要预防你到了新公司之后,发现公司文化不适合你,再马上找新工作的话就不好了。

  • Q: 这个职位空缺的原因?
  • A: 就像公司会问你离职的原因一样,了解到上一位离职的原因能帮助你更了解这个岗位的职责以及需求。
  • Q: 公司如何保证人才不流失?你们新老员工的比例是多少?
  • A: 这个问题其实揭示了公司的文化,如果新员工非常多,公司也不算新的话,那么代表流动率很高,公司文化可能不是很好。第二个问题其实就是问公司是否重视人才,通过什么方式对人才进行嘉奖。一个公司如果有比较多优秀的工程师的话,代表是不错的公司。
  • Q: 如果我入职的话,会有入职培训吗?会被分到哪个项目组,项目组的成员构成是怎样?
  • A: 这个可以了解公司的架构是不是清晰,个人职责划分是否明确。如果面试官回答不了这个问题,或者支支吾吾的话。即使你进去的话可能要兼顾几个项目,维护老项目。这些都要问清楚,你才知道自己大概的工作量有多少。维护旧项目虽然头疼,但是上线压力不大。如果新旧一起来,就要考虑自己是否适合这样的工作强度。
  • Q: 我入职的前三个月,要完成什么工作来证明我的能力呢,试用期的时间和通过标准?
  • A: 了解清楚如何通过试用期以及标准非常重要。
  • Q: 我今天面试的表现怎样,如果通过之后我还会经过多少轮,怎样的面试流程?
  • A: 首先可以了解自己的不足,积累经验。也可以开始为下一轮复试做准备

总结阶段

一次面试过来,可能筋疲力尽了。回想下自己哪里可以做得更好,简历哪里可以修改的。统计学告诉我们不要选择第一家面试的公司,多面试几家。不要欺骗自己,认真去思考每家的优点和缺点,和你的好朋友聊聊,寻求他们的建议。如果没有拿到 Offer 也没关系,重复上面的步骤,继续努力。两年前我连想都不敢想到美国的大公司工作,而现在的我就在为 Google 的面试做准备,就算我现在进不了 Google 又有什么关系呢?我还是在准备过程中学到很多知识。我很享受这段时间。相信自己,努力和汗水总会能得到回报的。

如果你觉得这篇文章帮助到你,希望我们继续分享求职经验的话,请帮我们点赞吧。👍

编辑于 2020-03-14

文章被以下专栏收录

    本专栏专注于介绍计算机的基础知识,学习完这一部分的课程并不能使你成为一位程序员,但是你不需要成为一名程序员,你可以是会编程的老师,会编程的 HR,这点可以使你在行业中更具有竞争力。而且世界上很多问题都没被解决。当你学会编程,用编程的眼光再去看自己平常的工作,或者就能找到一些属于你们行业的独特的问题,去解决它们。