今天正式入职了字节跳动。办公环境也很好,这边一栋楼都是办公区域。公司内部配备各种小零食、饮料,还有免费的咖啡。15楼还有健身房。而且公司包三餐来着。下午三点半左右还会有阿姨推着小车给大家送下午茶。听说入职以后很容易长胖来着。不过如果想要保持身材的话,公司二楼还提供专门的健身餐。周二周四还可以预约专业的按摩服务,有效调理颈椎和腰椎。生活服务得这么贴心,感觉在这里就只需要好好工作就好了吧,哈哈
为什么想去字节跳动
实际上,这次的工作变动并不在我计划中。只是在四月份的时候偶然得知字节跳动上海要搬到合川路地铁站附近,我就忽然心动了。为什么呢,因为我家距离合川路地铁站步行只要十分钟。本身宇宙条待遇高名声在外,也就是说,只要我能来这里的话,人生最美满的钱多事少离家近的不可能三角我能拿俩。所以在五月份的时候我就开始悄摸摸地准备面试头条了。为的就是以后可以过上早上八点半起床,然后慢慢悠悠走到公司还不迟到(可能还是很早来的人之一)的生活。
当然,这是我为什么想去字节跳动的原因。换算到你们自己的时候,你们也要想一想是因为什么想要换一份工作、想要去某个公司。为了薪资?环境?平台?还是大公司的名头?记住,不管是为了哪一个,都OK的。谈钱不伤感情,目标明确,心智坚定以后,才好围绕着这个目标做一系列的准备。面试的过程中每次面试官问我为什么想来字节跳动,我都是直截了当地说离家近,还说假如这次面不上,准备准备,过段时间再面试好了。反正你们公司就在我家旁边,三年五载的可能都跑不掉,哈哈。
因为这种面上OK,面不上也没事的心态,所以感觉面试的时候我的发挥也好一些。本身就是一个互相选择的过程,而且这个过程中,公司方相对来说固定一些,因为他的招人标准不太可能会有太大的变化。拿我经常用来怼人的一个例子来打比方:我常常和别人说,搞技术开发,英语很重要。你需要英语来看最新的技术文档,并且有些翻译并不准确,你可能需要看原文才能理解什么意思。有的人当时就会和我说,哎,可惜我英语不太好。这个时候我会回,没事,你现在英语不好不是你的错,但是如果我一年以后,甚至两年三年以后再来问你英语怎么样,要是你还和我说你英文不好的话,那你就得查一下自己的问题了。你根本就不想着学英语,英语怎么可能会好?
类比下来,如果你根本不想去这个公司,那你怎么可能来到这个公司?如果你真的想去一个公司,可能现在这个时候你暂时不满足要求,但是没事,只要咱知道别人是啥要求,咱认真学习,好好准备,一年以后再面试,两年以后再面试,甚至三年、五年以后再来试试,都可以的。人最怕的不是没有达成目标,而是没有一个真正的目标。所以,换工作之前,你要想清楚为什么,并且提前开始准备。
我准备了些啥?
其实我有好长一段时间没有正规地面试过了。三年前从数云换到GIO的时候,因为简历上的相关技术太过于匹配,所以基本上就和CTO聊了聊就确定过去了;后来再回数云的时候,也就和总监喝了一下咖啡就回来了。也就是大约5年的时间里面,我没有正规地接受过面试。所以在准备投字节跳动之前,我投了几个公司做了一下热身活动。记住,这个时候其实不需要有啥心理包袱。因为本身候选人面试成功的可能性比较低,一个合适的可以面试的人选他们也很乐意看看,而且万一你确实想换工作,但是心仪的公司面不上,而热身活动的公司拿到了offer,你也可以考虑考虑去看下。并且这个时候你没有任何的心理包袱,因为反正你也就是来面试看看的,所以面试时候的发挥可能也会更好点,因此说不定最终拿的offer会比最后想去的那家更好呢?
当然这里面不包括我。我第一次面试的时候就被血虐了T-T。参加中间件比赛的时候,我用的netty做的实现。个人感觉对netty还算有所了解的,结果面试官让我直接写出netty的源码结构,包括哪几个主要的类以及名称还有互相之间的关系……工作的项目里面我使用了kafka来做消息队列,来缓冲流量,保护系统,结果直接让我描述kafka的存储结构……比赛的时候我通过各种手段让程序无GC,结果直接就要我说出各种GC算法的原理和应用场景……PolarDB比赛我们自己写了KV,对标的是RocksDB,结果让我描述RocksDB的索引结构……
当然,虽然基本上他问的东西我都有所了解,并且清楚应用场景在哪里,但是到了细节里面的时候,就稍微有点蒙圈了。虽然每个细节我确认我稍微看一下就能搞定的,但是架不住面试的时候无法张口就来呀。这个时候,感觉仿佛我变成了年轻时候的杨过,忽然身边出现了一个金轮法王对我说:"杨兄弟,你的武功花样甚多,不过我倚老卖老说一句,博采众家固然甚妙,但也不免驳而不纯。你最擅长的到底是哪一门功夫?要用什么武功去对付郭靖夫妇?"。对呀,我的知识面很广,各种应用框架新技术可能都有所耳闻,但是我最擅长的是哪一个呢?虽然我深深地知道我最擅长的是Scala和Akka、Play、Lagom等,但是架不住没有人会问呀T-T。
事已至此,虽然我帅如杨过,但是此时也不得不考虑一下整理一下平生所学,找出强点和弱点,然后在面试的时候有的放矢。所以第一次热身面试之后的一个星期,我基本就在整理我的知识结构了。我大致按照如下结构做了一份思维导图:
1、JVM相关
运行时结构
GC算法
JVM调优
2、编程语言
Scala
Java
3、数据结构与算法
表、栈、队列
树
散列
优先队列
排序
高级数据结构
4、并发编程
Java内存模型
基本工具
无锁并发
反应式工具
5、微服务
微服务设计
服务治理
6、中间件
分布式缓存
消息队列
RPC
7、数据库
关系型数据库
NoSQL
NewSQL
8、机器学习算法
推荐算法
其中JVM、Scala相关、并发编程、消息队列什么的,我都仔细写了一下;Java语言太简单就没弄,数据结构稍微看了一下感觉脑海里面尘封很久的记忆忽然就被唤醒了,所以也没咋做笔记,微服务相关的太熟没弄,推荐算法太难了也没有弄;数据库相关的内容太多了,也没弄。但是大体来说索引结构在这里,拿到xmind之后,你可以按照自己的知识结构体系将其补全或者修改,然后学而时习之,甚至在面试之前也可以稍微看看加深一下记忆。
这之后我就进行了第二次面试。第二次面试技术相关的问题其实就没啥太大的问题了,主要考验我的是说话技巧相关的事情。我这人有点毛病,想的太多,想要做的事情太多。这些其实没啥大问题,但是我不确定的事情我也喜欢和人说,还不分场合地就和人说了。比如,我面的是中间件团队,但是我终面面试的时候却说我因为之前搞推荐算法对深度学习产生了兴趣,想要今年考个在职研究生学一下深度学习。可其实,这个时候我说这个干嘛呢?脑袋有点抽抽的吗?并且他问了我一个手写代码的题,我想了半天没有想出来。问题是如何去算根号2的值。我的第一反应很快,牛顿迭代法嘛!但是他说让我在纸上把代码写出来的时候,我就一直在想办法回忆牛顿迭代法是个什么鬼,应该怎么用来算根号2。然后一直在纸上推演导数啊什么鬼的……直到他提示我这个不是一个数学问题,二分查找就能算出来的时候,我才心不甘情不愿地开始弄二分查找的写法(内心OS:牛顿迭代法肯定比二分查找好的呀!为什么不给我时间回忆一下牛顿迭代!)。这个时候又暴露了我一个问题,我好久没有手写代码了。没有IDE的时候,我基本上啥都不是……写了半天勉勉强强地弄了个版本出来,估计也不是bug free的。所以,最终这个公司的offer也没拿到。辛苦为我推荐的普架了。
这之后我又知道了我出来面试的几个缺点。首先就是要合适地说话,与面试无关的话题不要扯;其次就是我得练习一下手写代码了。不至于要刷题,但是问到什么必须能至少写出个大概吧
字节跳动面试体验
字节其实我面试了两个职位。第一个职位的一面感觉挺好的,面试官很亲和,问的问题也蛮到位的,然后留给我的发挥空间也蛮大的,所以顺利过了。二面的时候就有点聊不来了,而且越聊越感觉职位不合适。所以后来朋友帮我重新推了一个职位,就是我现在所在的数据平台部门。一面的面试官又年轻又高大又帅气,而且基本上是针对我的简历问的问题。当然,第一个问题让我讲Akka的时候,我是真的呆了。完全不按套路出牌呀!我从来没有遇到过有人会问我Akka的!!!怎么会有人问我Akka!!!内心一阵狂喜和激动之后,我先收拾了一下心情,慢慢整理了一下自己脑海中一直在跳着举手喊着"讲我讲我"的Akka特性。于是先从线程模型开始讲起,讲了它的M:N实质,Actor模型依赖的消息传递模式,层级结构划分的监督职责,让它垮的失败处理,Akka集群支撑起的横向扩展,等等等等。然后围绕着Akka又问了一些小问题,基本很顺利的过去了。后来又问了一下缓存相关的内容,其中讲了一个缓存雪崩的问题我一时半会儿没有反应过来。问题其实很简单,就是忽然有一堆请求访问同一个key,而这个key在缓存中不存在。如此所有请求就会同时去访问数据库然后又同时去更新缓存。这样的缓存雪崩效应应该如何解决?这个问题听起来其实很熟很熟很熟的,但是当时我脑袋短路了没有想起来。后来想起来原来Akka-Http-Caching(以前的Spray-Caching)就是专门为这种情况服务的。老外给的说法是这种问题叫做惊群效应,讲的是很多请求在第一个请求完成之前,一起访问同一个键(This approach has the advantage of taking care of the thundering herds problem where many requests to a particular cache key (e.g. a resource URI) arrive before the first one could be completed.)。文档上说的This approach指的是缓存的时候,不要缓存一个值,而是一个Future[T]。这样,第一个请求获取值的过程也被缓存下了。后续的请求就会访问到这个Future,然后可以向其注册回调,等待缓存动作完成再完成回调。当然,这个没有答得特别好也没事,后续又问了我一下关于JVM相关的一些东西,最后手写了一个算法题。然后一面顺利地就过了。
之后二面的话基本也是围绕我的简历来问的,讲了一下当时做的推荐算法的原理,讲了一下Spark的基本原理,然后最后做了一个算法题,然后也顺利过了(其实还有一些其他问题,但是我忘了问的是什么了……)。当然这个算法题的实现并不是最好的。题目内容是26进制的加法,其实要涉及单个字符的加减和进位的处理的,这样实现下来细节就要处理好多东西,还很有可能出错。所以我取了个巧,我先把字符数字都转化成了整型,然后整型加减得到结果,然后再把结果转化成了26进制字符。虽然结果不是最优的,因为数字大了肯定会溢出的嘛。但是起码还是做出来了,所以二面也顺利过了。
三面的时候也是先围绕着我的项目问了一些相关的问题,所以答得蛮平淡的,但是也还行。然后他问了一下我如何做流量控制。问我流量控制哎!!!然后,我又强行按捺下了内心的喜悦,将《反应式设计模式》的第十六章流量控制的内容大致讲了一遍。也许就是给了这样一个我发挥的空间,所以我第三面也很顺利地过了。没多久就是HR面试大致谈了一些技术之外的问题。
HR面我就中规中矩了。当时面完感觉就稳了,但是等了好久好久还没有跟我沟通offer的事情,等的我有点难受了……之后HR联系我说,还要给我加面试,说团队老大要面我一下。原本字节面试一般3+1就OK了,然后突如其来地加面试让我感觉有点忐忑,所以后面的面试发挥没有前面好了。其实后来回想一下,我可能是以为前面面试表现不好,不能给我确定offer,才会有后来多的面试的。所以当时心态不好,答的感觉也没有之前果断。后来第五面完了以后,团队老大还是不确定,还要加一面交叉面试,这个时候我就豁出去了。无所谓,面上面不上没关系,反正字节跳动在我家旁边,只要庙不搬,我就进得去。所以最后一面跟隔壁leader聊的时候相对来说还好一些。问题没有问啥特别的,就是仔细问了下我最近做的一个项目,优点在哪里,缺点在哪里,难点在哪里。然后顺着难点来进行扩展,为什么是难点,怎么解决,有哪些方案,这些方案有哪些优缺点。幸好我平时工作还是有思考的,所以最终答的还不错。于是终于到了6月10号左右,HR和我确定要发offer了。
经验总结
整个面试过程,如果加上之前不合适的职位的话,总共8面,前后跨度一个多月。然后到了今天的时候,最终入职成功。说起来还是有点漫长的。如果再加上前面的两次热身面试,可能跨度就有接近两个月的时间了。说实话我并不是那种别人一看就很喜欢的工程师,因为一直在小公司做个小架构,而且主力编程语言比较偏门,所以适合我的职位范围相对来说很窄。实际上我今天看了一下和我工作相关的两个项目,一个go,一个python,我的scala技能可能在后面相当长一段时间要荒废了……不过没关系,离家近就行,而且跳出舒适区看一下其他风景,我感觉对我来说也是一件好事。
最终总结为什么能成功面上字节跳动,首先我的基础实际上还可以的,虽然第二次面试的面试官觉得我基础不好,但是其实很多内容在我深入的时候我就把思路、结构、来龙去脉整的明明白白的,所以就算忘了,回忆起来也能很快塞进体系里重新理解透彻;其次我有自己的拳头产品,面试不问就罢了,一旦问到Scala、Akka、Play、Lagom或者能扯上反应式架构的时候,只要嘉和和品神不在这条街,我就是这条街最靓滴仔!!!最后,我知道我为什么想去这家公司,并且就算不去也没啥大的损失,所以面试的时候可以不卑不亢,心平气和,于是发挥的就也还行。而且,反正公司就在我家旁边,这次没面上没事,过段时间再面呗。
这些经验换算到你这边:如果你说你现在基础不好,我会说没关系;但是如果一年、两年、三年以后你还和我说你基础不好,那是不是要自我反思一下呢?如果你说你现在没有拳头产品,我会说没关系;如果一年、两年、三年以后,你还是没有拳头产品,那你看我这篇文章有啥用呢?然后心态的问题可能就需要自己调整了。只要有基础,有拔高,然后心平气和地来面试,我相信你肯定能面试成功的。