聊聊面试和程序员找工作这件事

最近把工作换了,工作内容也从原来的单纯得后端开发转到了云,基本上换了个方向。由于公司的距离我比较在意,最低要求是最远不要超过北五环或者公司就在望京,再加上对公司规模和工作内容的要求,能选择的公司基本不多。

先说说今年的市场行情。都说今年行情不好,整体找工作的经历来看,确实各家都比较谨慎,通过类似拉勾网这种渠道投简历大多数没有任何回应,所以如果有认识的人,优先考虑内推。

再说说程序员找工作必须经历的笔试面试。

IT 这个行业比其他行业特殊点的是,面试一般有笔试,而且会在白板上手写代码,甚至有的公司会出智力题,巨头们如微软、Google 等的面试是出了名的难。虽然工作了这么多年,面过很多人,也被不少人面过,基本还没遇到过出智力题的情况,大家都是按照传统套路出牌,不偏不倚。很多公司面试最少有四面,三面技术面,一面 hr 面,有的公司会多点,有五轮技术面,一轮 hr 面,但套路都大同小异,总结下对程序员考察点基本划分为:

  • 计算机基础科学知识
  • 项目经验和工程能力
  • 常用开源软件的理解、使用和应用
  • 语言细节
  • 思维能力和学习能力
  • 其他如领导力、团队合作、职业规划等软实力

接下来我会把每个考察点一一展开来谈谈我的经历和看法,只针对具有普遍意义的程序员面试。

计算机基础科学知识

科班出身的程序员在基础计算机科学知识上是占优势的,即使很长时间没有碰这些理论性知识,花点时间重新复习一下也不会是什么大问题。基本的基础知识包括:

  • 算法
  • 数据库理论
  • 操作系统和计算机体系结构
  • 计算机网络和协议
  • 分布式基础理论
  • 计算机语言以及编译原理

算法

算法是一个老生常谈的话题,作为程序员不可能绕得开,正面面对是唯一的办法,如果仅仅是抱着攻破各大公司面试题的这种想法去学算法,心会很累,而且会失去对算法的兴趣。相反如果留点心,根本不难发现现代各大开源软件到处都是经典算法的影子,MySQL 索引中的 B+ 算法,Redis 中集合中的 skiplist、hash 等数据结构,Java HashMap 中红黑树等等、字符串搜索提示的 Tire 树、大数据过滤的布隆算法等等不一而足,也就是说学习算法最好的途径是从解决实际生产问题入手逐个击破掌握

由于所有的算法都是建立在特定的数据结构之上的,而这些数据结构又是各种经典数据结构的组合和创新,比如红黑树是为了解决二叉查找树插入、删除不高效而演变出的结构,B+ 树又是多叉树的经典应用场景,skiplist 是链表和二分查找的经典组合,所以想要掌握算法又必须要能做到把所有常用的数据结构烂熟于心,对他们的优缺点有着原理性的理解,能够熟练写出最基本的表达和实现,这些基本结构包括:

  • 数组
  • 队列
  • 链表
  • hashmap

有了结构,就能按图索骥,不断把触角延伸,一步步探索这些结构的演变;有了问题,就有了场景,就能把算法应用起来,做到理论联系实际,而最后需要注意就是分类、归纳、对比,总结和不断地练习

算法分类,按功能划分有:排序、查找、压缩、过滤等等,按结构划分有:数组、链表、队列、栈、树、图、位图、hashmap 等等,按照思想划分有:暴力、分治、回溯、递归、贪心、动态规划等等,按照领域解决问题场景划分有:存储算法、分布式算法、调度算法、机器学习算法、限流算法、字符串匹配算法等等。

有了上面这些方法论和学习地图,配合 LeetCode 的习题不断练习,算法终能掌握,不过可以预见的是,这个过程对于我们大部分并非天赋异禀,没有得到如来神掌真传的程序员来说是都是一场漫长而艰辛的寂寞之旅。

数据库理论

不管什么时候数据都是 IT 行业赖以存在的基石,因而存储不管在什么时候都应该在程序员应该掌握的领域知识中排第一位,按照目前后端开发经常遇到的存储类型可以简单划分为:

  • 传统关系型数据库
  • NoSQL 数据库
  • 内存数据库
  • 图数据库
  • 大规模分布式存储系统

互联网企业中,传统关系数据库基本都是 MySQL 或者 PostgreSQL 为代表的,其他收费的数据库一般来说基本可以不用考虑,因而一般来说只要掌握了 MySQL 或者 PostgreSQL 就能胜任绝大部分和存储相关的开发工作。

关系数据库本身有一套非常复杂的理论,比如事务、外键、数据库范式等等,但是由于真实生产环境的复杂性,很多数据库理论都不会严格被实现,因而学习数据库知识最好以大规模使用的开源软件为准即可。

MySQL

MySQL 是关系数据库的最强代表,没有之一,因而掌握了 MySQL 基本可以通吃,可以从以下几方面入手:

  • MySQL 数据库基本安装和使用以及组件结构
  • MySQL 支持的数据类型以及各自使用场景优缺点
  • MySQL 各种存储引擎以及适用场景
  • MySQL 实现的基本原理 (推荐 《MySQL 技术内幕 —InnoDB 存储引擎》)
  • MySQL 索引实现以及优化 (推荐 MySQL 官方文档索引相关章节)
  • MySQL 优化 (推荐 《高性能 MySQL》)

MySQL 涉及到的知识点非常庞大,没有哪本书会把 MySQL 的方方面面都涉及到,如果你确实比较懒,买点付费课程也是一种学习途径。

MongoDB、HBase、Elasticsearch、Cassandra、各种 KV 数据库

NoSQL 数据库是个很大的概念,基本上把 MongoDB、HBase、Redis 等等都包括了,拿 MongoDB来说, 本身是个文档数据库,支持以类似 JSON 的格式存储,支持大规模的读写,自带分布式部署和 shard,虽然 MongoDB 的争议不少,但是不可否认 MongoDB 的使用还算比较广泛。

其实这些数据库产品不论哪种,如果平时工作中有应用,就多花点时间研究一下,能做到深入了解最好,这对面试都是加分项,至少能够说明个人的技术视野比较开阔,不局限,如果没有时间深入了解,最起码能做到,知道其应用场景以及局限,能够和 MySQL 这种传统数据库比较起来使用

Redis

Redis 是一种典型的内存数据库,但是由于其应用真的是太广泛了,已经成为各大公司使用频度仅次于 MySQL 的开源软件,所以对 Redis 的了解要非常深入才能具备足够的竞争力:

  • Redis 的基本安装和使用
  • Redis 的各种数据结构以及使用场景
  • Redis 的各种命令以及常用配置的含义
  • Redis 的基本原理以及各种典型的使用场景

推荐看看 《Redis 的设计与实现》、《Redis 开发与运维》以及 Redis 在各大厂的典型实践案例,网上有很多文章,掌握了这些,面试基本没有任何问题。

图数据库

如果不是针对特定公司或者特定场景的,可以略过。

大规模分布式存储系统

这个要稍微提一下,有的公司会问 HDFS 以及 Ceph 这样的大规模分布式存储系统的基本原理,这方面如果没有实践经验可以了解一下基本原理和理论即可,可以不必深究,除非是面试的岗位就是做类似系统的,那就需要特别了解了。

操作系统和计算机体系结构

操作系统和计算机底层的一些知识一般绕不开,常见的包括:

  • 进程、线程、协程等的原理和差异
  • 进程间通信
  • 进程的在操作系统中的实现以及调度
  • 内存模型
  • CPU 模型
  • Linux 系统

这部分内容确实能区分出程序员的基本功力,推荐 《深入理解计算机系统》和 《计算机程序的构造和解释》,啃完这两本,几乎没有过不去的操作系统相关的面试。

计算机网络和协议

网络协议可以说是面试必考,包括 TCP\IP、UDP、HTTP、HTTPS、HTTP2,操作系统常见的网络模型,对于 TCP 应该至少掌握:

  • 三次握手和四次挥手的原理以及状态变迁
  • TCP 的可靠性是如何保证的
  • TCP 限流、慢启动、拥塞控制、长连接保证等等
  • TCP 的拆包过程、重组过程等
  • TCP 和 UDP 的基本区别,适用场景
  • DNS 解析的过程、各部分使用的协议以及缘由

推荐《TCP-IP详解卷一》中有关 TCP 和、UDP以及 IP 的章节,而且 TCP 的状态变迁本身并不是特别复杂,虽然状态不少,如果理解着记忆,并且结合着 tcpdump 多看一下各个场景下 TCP 的连接状态基本都能搞明白,很多公司喜欢问为什么不是二次握手,以及为什么不是三次挥手,并且会问原因,如果对 TCP 各个状态变迁没有做深入了解,这些问题会被绕晕。

HTTP 协议是 web 开发必须要掌握的,不只是后端程序员,前端程序员也有同样的要求,对于 HTTP 协议可以看 《HTTP 协议权威指南》 这本书足够了,不需要买任何课程,费钱。

HTTPS 要理解其原理和过程。

HTTP2 要理解其原理,以及和 HTTP 1.1 相比做了如何的改进。

和网络相关的还有一大块内容是 Linux 的网络模型,也就是现代高性能 Server 底层实现 epoll 等网络模型,包括但不限于 Redis、Nginx、Gunicorn、libuv 等底层都依赖于此,因此必须要掌握,推荐《unix 高级网络编程》这两本书。

如果比较懒,可以参考我写的书 https://sanyuesha.com/python-server-tutorial/

分布式基础理论

知道分布式解决的问题是什么,以及分布式带来的挑战是什么,知道基本的 CAP 理论,理解常见的分布式一致性算法,理解常见的分布式架构原理以及适用场景。

推荐 https://github.com/mixu/distsysbookhttps://github.com/heathermiller/dist-prog-book 两本书,推荐 https://raft.github.io/ 对 raft 一致性算法的介绍。

项目经验和工程能力

一般来说,大多数程序员的项目经验来自于工作时做的各种项目,因而对做过的项目在实现之后要能不断的总结提炼其中的精华部分,很多面试官喜欢让面试者 show 出自己所做项目的难点以及有深度的地方,这就是不断总结提炼的原因。如果平时能养成经常总结概括,回答这种问题基本可以做到即问即答。

工程能力是程序员的一大基础能力,工程能力的强弱决定了程序员能够胜任不同规模和不同复杂性项目的能力,工程能力是一种过程性得动态能力,其主要来自于对项目的不断实践和反复重构优化的过程中

因而作为一名程序员,要对自己所做项目的完整生命周期负责,从项目构建、单元测试、部署、日志收集、容量规划、监控报警、性能优化、扩容等软件生存过程要全程参与,如果没有办法做到全程参与,至少也要能理解整个服务链路的生命周期。

常用开源软件的理解、使用和应用

面试经常会被问到各种开源软件的使用和原理,这些问题非常具体,而且答案比较标准,对于此要对自己常用的软件原理最好都能掌握,并且对其使用场景要非常熟悉,拿后端程序员来说,包括但不限于:

  • NGINX
  • MySQL
  • Redis
  • MongoDB
  • ES
  • HBASE
  • HDFS
  • Kafka
  • MQ
  • ZK

最好能做到精通一个到两个,其他做到基本掌握和使用即可,没有面试官会要求一个面试者能掌握所有,但是很多面试官都期待面试者能至少对其中一个有非常深入的研究,如果面试者能做到这一点,将会是很大的加分项。

语言细节

有的公司对语言有强烈要求,比如 Java 生态的,有的公司对语言没有强烈要求,比如 Python 或者 Go 生态的公司,但都会提问面试者熟悉的语言一些非常微小的细节,比如 Python 中的迭代器内部结构,以及迭代器和生成器的区别,比如 Go 中的 slice 的内部机制以及如何扩容缩容等。因而面试者要对自己熟悉的语言要有比较深入的理解才行,如果是 Java 系的就要对 Java 的各种常用标准库的内部实现以及各种并发编程模型、锁等熟悉,如果是 Python 系的,就要对 Python 常用数据结构的用法,差异,垃圾回收机制,GIL,内部原理都能掌握,同样 Go 也是如此,其实不管是哪种语言,只要留点心,再不济 Google 一下各种语言常见的面试问题,这一关总体来说问题都不会太大。

思维能力和学习能力

很多公司对思维能力的考察一般是通过做算法题或解决一个特定场景的问题,算法上文已经讲过了,对于系统设计这种场景性的问题,解决之道也是在日常工作中能对自己遇到的各种问题不断优化总结以及做项目时多问几个问题逐步积累出来的

  • 如果在现有项目的规模放大十倍百倍这个项目应该如何设计和架构
  • 对于一个问题有没有更好的设计方案,如果有那该如何取舍权衡,如果没有,为什么

思维能力本质上反映出来的其实也是工程能力,也就是解决问题时能不能面面俱到的照顾到各个方面,并且权衡取舍到最优方案

面对这类问题,面试者一定要通过不断向面试官提问来缩小问题的范围和分析清楚问题的各种边界条件,争取考虑周全

学习能力考察一般会转换成让面试者讲述一门自己工作之外学习到的新技术或新技能,并且要阐述清楚其学习的目的以及这项新技术的原理和内部机制。所以任何时候都不要停止学习,因为我们都是程序员。

软实力

软实力是程序员能够在职场不断晋升,放大自身价值的必备技能,而这些能力确实需要每个程序员能根据自身条件来培养,完全因人而异。所以面试者要能非常了解自己的性格特质、能力边界、兴趣爱好以及对未来的规划期待等等。

推荐阅读 《黑客与画家》、《软实力:代码之外的生存指南》、《程序员的思维训练》。

选择

找工作和择偶很像,选择对方或者被对方选择,而这个选择在大程度上决定了未来一到两年自己职业的发展,甚至更远将来的选择,因而如何选择非常重要:

  1. 如果是应届毕业,优选大企业,对于刚毕业的程序员,公司比做什么更重要,大公司提供了更多的可能性,有更多选择的机会锻炼和历练自己
  2. 毕业两年到三年,已经经历了很多,大概知道自己的兴趣点和志向,此时根据市场热点选择一个自己感兴趣的方向,以及在这个方向上再选择一个上升型的企业,趁年轻可以获得公司成长的红利,也会得到更大的锻炼
  3. 毕业五年以上,这个阶段的程序员面临一个很大的职业选型的问题,走技术路线,成为专家,走带管理的路线,成为专家型领导,每个人的性格特质不一样,这个时候就需要特别了解自己,包括自己的性格特点,能力范围,兴趣志向,还要了解行业趋势,未来市场的行情等等,最终综合选择一个自己能够深扎的行业以及技术方向做下去。
  4. 时机来临选择创业或转行

危机中的幸运

很多人都说程序员是青春饭的职业,确实行业发展趋势中不可避免很多公司倾向选择更年轻的程序员,如果程序员想在行业长久立足只能是:不断提高自己的竞争力。写出更好的软件并不是拼体力,而是各种综合能力的体现,程序员想要持续享受 IT 行业发展带来的红利,唯有永远学习,不断提高个人能力。

三月沙 wechat
扫描关注 wecatch 的公众号