大家好,我是对白。
今天给大家分享一位朋友上个月从算法岗转工程岗的血泪史,当你做的算法方向非常小众,且不能带来较大的业务收益时,不妨换个组或转岗试试,以下为原文。
一、背景
本人目前开发经验两年(其实是一年多)在第一次跳槽(2022年3月)中收获阿里、腾讯、滴滴等公司的offer,从跳槽动机、准备、面试等角度去复盘这次跳槽,希望对自己和读者(尤其是校招和短经验社招背景的读者)都能有所收获。
我在2020年的7月份从某个双非本科的毕业后进入某个互联网公司工作,入职的岗位是算法工程师,依稀记得校招面试的内容是些公式推导、项目介绍以及LeetCode题(每年关于校招算法岗内卷程度的形容词层出不穷,从诸神黄昏到灰飞烟灭,我当然也不能幸免)。
在入职之后,部门组织了一次部门校招生的培训,培训时长一个多月(期间脱产,感觉国内能给校招生全职脱产学习的公司真的不多),由于部门中算法的同学比较少我们是和工程同学一起培训的,这也算是为后续转工程埋下了一颗种子。
在后续短暂的算法工作之后我发现,这个方向相当的小众,国内做的公司基本屈指可数,国内的论文基本都出自某两个大学的实验室,相关方向的比赛参加的人数也只有小几百人,只有热门比赛的零头(虽然说人少成为开拓者的机会更大,但我深知自己才学疏浅),恰逢隔壁工程组有hc,沟通后决定转工程,文字记录看起来似乎轻描淡写,但是当时做了相当多的思考,好在我相信一切都是最好的选择,包括现在回头看似乎也是一个正确的决定。
转到工程组之后,导师给我的第一个转正任务是一个简单CRUD实现,需要设计数据库表结构以及实现对应资源操作的接口,实现的语言是go,给的时间是一个月,当时我的工程水平基本维持在本科课设水平,面对一个正常后端同学大概几天就能实现的任务(这个任务并不会设计到高并发的问题),搞了一个月才搞出一个基本能满足上线要求的东西出来,记得当时的code review 建议有100+,勉强搭上了同届开发同学转正答辩的顺风车,在答辩会议上我颤抖的声音和流水账般的PPT和其他同届如诗般的流畅演讲简直是天差地别,所幸算法转工程成了我的最后的遮羞布,也庆幸评审们很给面子没有撕下这块布,顺利转正了。尽管已经过去一年多,我还是会时常看看这个部分的代码,每次看都能发现很多问题,毕竟吾(太)日(多)三(bug)省(要)吾(改)身。
转正后导师后跟我沟通说答辩的评级是B,我一点也不意外,我深知还有很长的路要走。
转正后的第一个大的任务是大部门的OKR,当时收到这个任务是非常兴奋的,想到能把一个这么重要的OKR交给我,那不是离升职加薪不远了?(实际上是我想多了)这个OKR的内容大概是需要负责一个开源项目从0-1的二次开发和内部适配工作(由于涉及具体工作内容,后续简称"亲儿子"系统),需要接触的开源中间件有很多,这些中间件如果只需要学会接口的调用非常简单,但生产环境遇到的问题远远比想象的多外加中间件团队更多是运维的角色,逼迫着需要去了解对应原理和代码,这样的环境背景也算是一个契机,养成了喜欢看开源实现的习惯。
大部门的OKR持续了一个季度左右,在2021年的四月初,由于部门的业务拆分,亲儿子被划分到另外一个业务线,到了和亲儿子道别的时候,迅速交接出去之后我被要求加入到某个自研的基础系统(由于涉及具体工作内容,简称”养子“系统)的开发中去。
“养子”经过七八年的迭代,架构图已如同蜘蛛网,代码也分散在三四个仓库,语言也有PHP、Python、golang、Java,虽然系统中冗余了相当多的可以合并的业务逻辑,但是依旧还是有相当多的可学习的地方,自研的rpc框架、自研的基于tcp的通讯协议、一套MySQL的内存ORM、简陋但有效的高可用等等,在这个自研系统中我主要参与缝缝补补的工作,例如性能优化等。
为了更好的适应工作内容,我在业余时间恶补基础知识,计算机网络,操作系统等等,对自己的要求也有所提高,不再拘泥于如何实现而是为什么这样实现、为了解决啥问题。个人认为自我学习的驱动力主要来自收益以及对应的激励机制,就比方我个人会在达成某个阶段性目标的时候给我自己奖励也许是一顿大餐或者是一个数码产品。
二、萌生离职的导火索
导火索1:奇怪性质的OKR。亲儿子的OKR之所以背在我身上是因为当时原先打算接手的老哥提了离职,急需一个人”背锅“恰巧我属于比较空闲的人力,所以我才得到这个”背负重任“的机会,这个事项的本质是一个”政治形式“的OKR,整个项目处于赶鸭子上架的状态,无论是产品和主管都不清楚需要达成什么目标,对于的时间线是啥,使得我完全处于被动状态经常出现一个需求反复返工的情况,尽管我从这个项目中学到了相当多的东西,但是我也意识到了部门内存在的一些问题。
导火索2:频繁变更,深夜oncall。自从接受”养子“系统的大约几周后,我开始担任系统的开发值班(简称客服、oncall工具人),我一直认为能够把自己的系统推广出去使用以及解决用户使用上的问题也是一种有意义的工作,直到9月份,由于我们疯狂的上线需求,带来了很多系统稳定性的问题,导致oncall的几位同学常常需要半夜起来解决线上问题,为此也反馈过多次(尽管可以申请调休,但是没有人喜欢在深夜被电话铃声叫起来,然后拖着沉重的脑袋去查一些边界条件…),但是由于在深夜对用户影响不大这个问题就被团队忽略了。直到一次长达四小时的不可用故障,我们一伙开发人员和主管只能大眼瞪小眼的盯着服务监控而不知所措,从这开始我意识到系统已经复杂(与其说是复杂不如说是冗余)到团队内没人能快速定位问题的地步,只能等故障自动恢复。在故障结束后排查的任务给了我,最后虽然成功定位但是我对当前工作的内容也产生了一些质疑,是否我当前写的一些自认为”优雅“的代码,在未来的迁移中是否也会成为累赘?
导火索3:拆东墙补西墙的人员变更。在去年的年底,由于业务调整(咋又是业务调整?)原本隔壁组归属的业务出现了人力不够的情况,需要我去支援,也就是需要再次去从0接手某个系统,也就是意味着短短的一半年不到的时间内我已经接手了3个系统(其实是有4个,并且这在组内是常态),频繁的转换方向意味着完全没法在一个方向上深入,我认为对团队和个人都是无益的。
自从21年年底萌生离职的想法后,我开始着手制定计划准备,基本的计划是
每天刷题一道,周末拿出一天时间来刷题(通常可以刷十来道)
剩余时间准备八股文和项目相关
2.2 刷题
在两年经验的招聘中,算法题是会占到相当大的比例,每轮的技术面试都会有1~2道的算法题目,通常的难度是mid,推荐的题目集是《剑指offer》和LeetCode的hot100,以及LeetCode上各个公司的热门题集。我是刷了200+道,面试就基本够用了。这里推荐一种刷题方式,首先是按照题集中的tag去刷题(常见的例如字符串、数组、链表、树、动态规划这类tag),当遇到不会做的题目看题解的顺序为标签->提示->评论->题解,尽量在看完每一步之后都有自己的思考才能在相似的问题上有清晰的思路,遇到刷过但是还是不会做的题很正常反复刷就可以了。
2.3 项目
项目在社招面试中占据相当一部分时间,可以从几个方面介绍自己的项目
项目背景以及解决的问题
项目实现具体细节
项目难点
项目达到的可量化指标
最开始我的认知是自己做的项目细节肯定一清二楚,所以没有付出额外的时间准备,实际面试中往往会发现我不知道怎么完整的能让面试官理解的说出整个项目做的事情以及最终达到的成果,所幸在面试的早期发现这个问题,后续重新组织练习下就可以改善这个问题,这个也算是软实力的一部分,毕竟如果在这条路上走的越远软实力也是很重要的一环。
2.4 八股文
对于我自身的工作内容八股文可以分为几部分
语言:golang
数据库:mysql,mongodb,redis
大数据:kafka,elasticsearch
基础:计算机网络,操作系统
这部分的最大难点我个人认为是多,个人积累的八股文记录已经有8w+字,记录大部分是简短的表述和引用链接,如果展开的话内容预计翻十倍(计划以后整理然后分享出来,因为我自己找的实在太累了…) 。外加如果只是单纯通过背诵的方式记忆显然是满足不了面试官的提问,举我面试中遇到的问题为例
redis内存满了之后不能删除数据要怎么做?
写一个死循环累加某个值,一秒钟可以加到多大?
这类问题都是属于开放性题目,逻辑自洽切能解决问题即可,但是需要相对牢靠的知识体系支撑。
对于八股文,难免会有不会的地方,这时候说如果要是我来设计我会怎么做,如果这时你给出了一个可靠的方案往往会更加加分。
下面我推荐一些课程和书籍,仅是我个人看过并且认为还不错的,并且遵循少即是多的原则(网上很多电子版,这里还是推荐有条件的可以考虑支持下正版),每一部分展开讲都巨多东西,这里先挖个坑以后再来填。
mysql我推荐学习经典的极客时间的《MySQL实战四十五讲》,慢慢看下来并且做笔记记录,成长会很大,绝大部分的问题都能cover
redis我推荐直接看源码,网上有很多源码解析的系列文章初期看不懂的话跟着看就可以了
golang我推荐看《Go语言设计与实现》有纸质版也有免费的电子书,个人认为配合go源码来看非常棒,看完之后收获很大
kafka我推荐看《深入理解kafka核心设计与实践原理》,整体讲的挺通透的,比较适合没时间看源码的人
三、社招之路
终于讲到自己的社招经历了。从今年的2月开始,我开始投递简历,投递的岗位是后端(我对语言没有特殊的执着,所以感兴趣的岗位都会投递)。可以随机拿一个岗位JD具体分析下。
阿里某岗位JD
这个阿里某个岗位的JD,可以提取出一些需求信息
语言:Java
数据库:oracle,分布式缓存
方向:大型电子商务系统
操作系统:Unix以及shell脚本
总的来说,对于校招/短经验的社招,移不开的四座大山是,编程语言,数据库,操作系统,计算机网络
但是否需要所有的条件都满足才能投递岗位参加面试呢?其实不是的,对于经验较短的岗位公司往往能接受转语言/转方向的人。比如我完全不会Java也通过了JD上写着熟练使用Java的岗位,在面试中面试官也会省略掉Java的部分(吐槽一句,Java的八股文可太多了…)
下面拿我面试的三家公司来讲讲面试经历,分别是阿里、b站、大疆。这里谈谈我对面经的看法,很多人可能习惯面向面经准备面试,我个人认为是不太合理的但也许有时候会相当有效,个人比较合理的方式应该是系统学习某个领域或者中间件然后再通过面经去查缺补漏。下面的面经不会记录项目的部分,项目因人而异问题没有通用性。
B站
b站是我面试最早的一家公司,做的主要是主站相关的业务,例如up主上传视频、审核、发布这条业务流。分为三轮技术面、一轮HR面。
一面:
怎么理解分布式系统?
mongodb的objectId是如何生成的?
mongodb怎么做数据迁移?怎么做故障转移?
一致性hash解决了什么问题?遇到不均衡的场景要怎么做?
使用mongodb时遇到过什么问题?(数据不均衡,shard key设置以及chunk分裂和迁移)
go里面的sync.Map是怎么实现的?(cas,读写分离,脏数据提升,标记删除)
多路复用,select,poll,epoll以及go里面的netpoller
kafka的ISR是什么?怎么做数据同步?
elasticsearch的倒排索引实现(前缀树,fst,and/or条件快速合并)
算法题:LeetCode 74,
二面:
go里面context的原理,如果要你实现一个定时器你会怎么实现?(堆)
mysql中几个隔离等级,分别为了解决什么问题?(脏读、幻读、不可重复度)
mysql的buffer pool设计,如何解决热点缓存?
kafka怎么处理提交offset的?(有个特殊的topic)
elasticsearch的写入流程?是否是强一致性?为啥叫准实时?
进程、线程、协程的区别,使用场景
go的GMP调度和线程调度
什么是用户态和内核态,为什么切换的成本高?进程、线程的上下文都有啥?
什么是中断?
算法题:LeetCode 15,
三面:
怎么设计分布式唯一键?(雪花算法,数据库id自增,分段缓存)
说说raft协议?
聊人生
技术面就是按照流程,八股文,项目,最后来道LeetCode题,基本都是属于hot 100的题目,因为做过所以基本能bug free,但是由于是白板编程也没让跑。除此之外,还问了一些所谓的“系统设计题”,例如问怎么设计唯一id?怎么设计朋友圈?怎么设计群聊已读功能?这种时候需要考虑的关键指标是性能,需要怎么解决读写放大的问题,不过其实也有基本的套路。由于项目的相关性不是很大,所以项目就简单问了问。
让我印象比较深的是三面的面试官,应该是某个部门的负责人,最后问我有什么问题的时候,我问了说能不能介绍下您从事这个行业的生涯历程,面试官愣了一下,估计心里想不按套路出牌咋不问业务啥的,不过还是花了十来分钟详细给我介绍了下,并给了我些人生建议,我还是相当感激的,虽然最后因为种种原因没去b站。
大疆
一面:
tcp和udp的区别(可以从头部的差异来记忆)
tcp三次握手,拥塞避免,流量控制
http1.0、2.0的区别以及存在的问题
redis的slot是什么?为啥slot的16K的大小?
redis几种数据结构以及分别的实现方式,ziplist是咋实现的?
redis快的特点?
redis大key怎么删除?(unlink,和分批缓删)
reactor网络模型?
mysql的mvcc以及rr是否能解决幻读?
b+树,三层b+树可以存多少数据?
mysql覆盖索引,聚簇索引
二面:
raft协议,成员变更的流程,怎么解决脑裂?
画系统架构和讲解
lsm树模型为什么写入更快?
ssd场景的写放大问题
elasticsearch倒排索引
开源二次开发时有什么注意点?
什么是大小端?go写个代码判断下
怎么理解自动驾驶?为啥要离职
三面:
为什么想着换赛道(互联网->自动驾驶)
为什么离职,有没有和主管沟通过?
大疆是负责自动驾驶工程相关的岗位,可说的东西也不是很多,也是三轮技术面,一轮hr面。让我印象深刻的是一面面试官看起来很疲惫,也许是深圳疫情在家办公的问题,因为亲身经历表明在家办公很难把工作和生活分开往往会更累。
二面面试前专门提醒了需要画系统架构图,当我画完详细的架构图之后,面试官表示你们的系统为啥那么复杂,我只能通过业务场景复杂的理由搪塞过去,虽然内心的os是我也不知道…后续也出了个自动驾驶的场景题,还问了我对大疆车载的认识,因为没有提前准备所以基本答不上来,介绍业务的时候介绍的非常详尽说了20分钟左右,让我这个小白也能明白目前的业务情况以及如果入职要做的事情。三面是大疆车载的沈教授,面的时间很短,也没啥可说的。
阿里
一面:
怎么理解虚拟地址空间?
段表、页表是什么?
为什么需要段表?多级页表是啥?
进程切换的TLB了解吗?
mmap是为了解决什么问题?什么是零拷贝
select,poll,epoll的区别
redis的多reactor模型是怎么样的?核心线程是多线程吗?
mysql的b+树和b树的区别
redis的zset为啥不用b+树/红黑树
lsm树模型详细说一下?
lsm树合并是怎么做的?没有WAL(预写日志)怎么保障数据不丢?
elasticsearch中什么是分段、分片?副本的作用?
做道题吧,二叉树的右视图,面试官怕我不会直接跟我说可以用层次遍历做 哈哈
二面:
项目中的有状态服务怎么做到可横向扩展?项目中redis和mongodb的作用,为啥不能只用mongodb?
mongodb怎么做到高可用,故障转移咋搞?
一致性hash和普通hash的区别?
进程、线程、协程的区别?为啥go的协程做的比较好(个人认为核心是有栈协程)
怎么做的分布式链路追踪?原理是啥?
倒排索引是为了解决什么问题?你们为啥考虑直接修改索引结构而不是考虑加缓存的方式?
kafka为啥用page cache而mysql要自己实现buffer pool
顺序写为啥性能高?
kafka的使用上你们有遇到什么问题吗?
为啥要离职?
你认为阿里哪里比较吸引你?
三面:
你们团队有多少人?人员是咋分布的?有没有晋升
需求开发的流程?
说下raft协议,有看过具体实现吗?
说说etcd的raft实现
说说关系型和非关系型数据库的区别?三范式是啥?
过来要写一些Java可以接受吗?会给学习时间
学习路线是咋样,平常是咋学习的,说说你最近看的书(数据密集型应用系统设计)
阿里面的岗位是匹配度最高的,所以一路下来聊的都比较开心,业界一直说阿里的面试体验很好果然名不虚传,只有一面的时候做了个算法题(也是白板并且只是大概说了思路然后面试官瞟了一眼),二面和三面更多怼的是项目上的边界条件,例如高可用、横向扩展、一致性、数据量、怎么在开源基础做二开、具体项目中怎么优化索引的结构之类的问题。一面的面试官看起来非常年轻,以为是未来同事没想到时team leader,三面面试官后来查了下发现是p11还是很意外的,总体来讲阿里的面试推进以及面试感受都是很不错的。
四、总结
这次跳槽整体来说是相当顺利的,在面试中收获了非常多的东西,意外的是在“互联网寒冬”的2022年,各家给的offer很大方。
最后以一句我很喜欢的话收尾,也送给也许在工作/生活深陷泥潭的各位。
与其诅咒黑暗,不如点亮灯火。
你好,我是对白,清华计算机硕士毕业,现大厂算法工程师,拿过8家大厂算法岗SSP offer(含特殊计划),薪资40+W-80+W不等。
高中荣获全国数学和化学竞赛二等奖。
本科独立创业五年,两家公司创始人,拿过三百多万元融资(已到账),项目入选南京321高层次创业人才引进计划。创业做过无人机、机器人和互联网教育,保研清华后退居股东。
我每周至少更新三篇原创,分享人工智能前沿算法、创业心得和人生感悟。我正在努力实现人生中的第二个小目标,上方关注后可以加我微信交流。