写在前面
在参加社招面试之前,我作为面试官面过一些校招的同学,能够从面试官的角度去思考,面试官想从一个问题考察候选人的什么能力。
举个例子,通常面试官经常考一些八股文,因此现在网上技术论坛及代码仓库流传着各种各样的Java知识点面经、分布式面经等等,我也面过一个类似的校招生,八股文背的那是相当滚瓜烂熟,信手拈来。
但在日常工作中,我们极少碰到和八股文相关的业务需求或技术演进开发。因为八股文的内容更类似于一种指挥编程的范式(Concept),在面对实际的应用场景里,更加频繁面对的问题是如何将现实的问题和抽象的概念关联,也就是将任务拆解成若干子任务与领域模型抽象的过程,而这种自上而下的拆解能力,与基础知识结合的能力,复盘的能力,流程的标准化能力才是一个优秀的技术开发的基本功。 因此,偏技术考核的面试官从考核上来说更加倾向于
- 设计背景需求/从工作上的某个需求出发
- 任务拆解
- 领域模型抽象/技术选型
- 安全生产/稳定性
- SOP
- 产品演进规划
设计背景需求
这一个部分一般是从某个工作场景提出,或者直接抽简历中的一段项目经历来聊聊 这里主要看如何抓需求的重点。如
- 是什么
- 给谁用
- 数据从哪来
- 业务场景
等等。
我采用主导面试流程的策略,导致这块放在面经里面就很难作为别人借鉴的内容,没有能够直接迁移到其他面试的题目。
不过这块我觉得要看自己的策略。比如我对简历上写的项目了如指掌,可以说是对其中的演绎方式是无出其右的,那这个策略肯定是最好的,可以全方面向面试官展现自己面对需求的拆解能力。
一面
- 自我介绍
聊项目
阐述过程为2个主线:
- 以某视图流平台为主线的产品需求
- 以入淘为主线的技改需求
进行阐述,分别描述了这两条主线的项目背景、技术背景
面试官:讲一讲某视图流平台
自我定位:DSL解析引擎开发、Debug能力开发
技术选型:antlr4、Excel 语法
这里采用了一些反客为主的面试策略,从自己对平台本身业务定位的认识以及工程能力设计的一些思考出发,以SOLID原则如何设计系统去讲述这个过程。
在这个过程中没有让面试官主动提及Spring及设计模式,讲了
- Spring Boot
- Spring Bean life cycle
- NameSpaceDefinition
- 自定义PostBeanDefinition实现Annotation registry
- Dynamic Proxy (JDK Proxy、cglib Proxy及实现的区别)
还有些细节顺便聊了聊,比如Optional的应用,链式调用的应用,如何判定对象自引用(A.b = B; B.a = A这种,如果出现这样的对象是有问题的)
性能问题(主动延伸)
benchmark、java dump、火焰图、足够的Unit Test覆盖
稳定性: 事前核对,事后核对,快照流水、前向纠错、交叉验证、影子表黑箱推演
面试官:如何保证系统间数据一致性
讲了一下快照、反查、对等逻辑验证,以及提了一种思考:信息前向纠错
面试官提问:出现Full GC以后如何解决
case by case,从系统本身的业务场景去分析,结合java层面的Full GC可能性+业务场景中常见的内存溢出问题去思考
如ThreadLocal的溢出、日志队列堆积、static实例对象关联关系没有解除等等
问了mysql union index原理、出了两个mysql union index的题目,这块做的不好,后面复习了一下了解这块从db层面的内部优化问题,有了一些新的认识
算法题
给出一个字符串,删除[0,1]个字母,判断是否为回文串
https://leetcode-cn.com/problems/valid-palindrome-ii/
朴素解和最优解都写了一遍,秒了
二面
- 自我介绍
聊项目
一面讲过的内容略过不表
问: 从你的角度整个公司的架构是怎么样的? 答:端->负载均衡->Restful API->RPC->前台业务域[前台视图应用->前台订单应用]->技术中台+业务中台(PaaS)->云弹性计算/中间件/基础设施(IaaS) 分布式协议
问了下对分布式熟不熟悉,对Zookeeper如何实现
知识盲区了,以后补一补(
(后面看了下,基本模型都是TCC( 闭着眼睛说都没啥问题。。。)
算法题
给定数组,查找第K大
可用分治思路去做,Leetcode给的解法是堆,这里可以直接按照算法导论的快排思想,随机抽一个数做哨兵,将数组分两部分,判断第K大在左边还是右边,递归这个过程知道能够判断第K大。
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
vector<int> left, right;
int pivot = *a.begin();
for(int i = 1; i < n; ++i) {
if (pivot < a[i]) {
left.push_back(a[i]);
}
else {
right.push_back(a[i]);
}
}
if (left.size() > K) {
return findKth(left, left.size(), K);
}
else if (left.size() == K - 1) {
return pivot;
}
else if (left.size() == K) {
int mx = INT_MIN;
for(auto element: left) {
mx = max(mx, element);
}
return mx;
}
else {
return findKth(right, right.size(), K - left.size() - 1);
}
}
};
三面
- 自我介绍
聊项目
一面、二面讲过的内容略过不表
讲一个工作经历中最有价值的项目(DSLx3),从项目背景、解决的问题、个人在其中发挥的作用、遇到的困难、如何解决困难、最终拿到的结果、后续的复盘、演进的方向、个人的思考讲一讲。
面试官:为什么不用现成的轮子实现DSL?(这个问题包含几个点:技术选型、对需求的分析、对用户的调研、前期实践的经验教训等)
- 没有目标DSL的开源代码
- 有开源工具的DSL学习曲线陡峭
- 综合用户平均使用习惯和水平,使用当前的语法逻辑更合适
- 性能达标
这里其实讲法其实大同小异,不过关注点和前几面不同,面试官希望了解的是从个人角度是如何认识需求、如何解决问题、如何从需求中进行复盘等,一些个人软实力方面的东西。
面试官:讲一下最近的一些需求。
入淘。讲了自己设计的一个Ability框架,用于解决代码内部的调用图化,能力解耦合,依赖关系抽象为入度和出度的一种设计,借鉴了bpmn的设计思路。
面试官:为什么不用现有的轮子
现有的轮子实现的粒度更粗,没有办法做到vm环境的解耦合,需要跟踪代码层面的执行关系。
调研过类似的框架如Activiti,这种和spring的耦合过深,开发难度比当前轮子大,关注的重点和现有框架解决的问题不同,希望能有一种耦合程度低的实现,可以实现代码逻辑快速迁移。
对话的推进也聊到个人未来的技术发展方向,这里讲了一下自己对未来的职业发展的一些规划,包括对行业的认识,自己对职业选择的原因
在反问面试官的环节和面试官聊了一下他对这个行业的定位、规划发展,目前的优势和劣势,尝试和他讨论了一下自己对这个赛道粗浅的看法。
HR面
HR面的问题主要关注非技术层面的东西
从前面几次面试有什么感想
- 对自己先前工作的复盘
- 对面试官工作的认识及认同
- 对选择的赛道的认可
- 对自己技术层面不足复盘
选择字节该部门的原因
认可B端业务赛道
对当前自己业务领域的一些反思
自己的职业规划发展
从后端技术到架构以及布道师的演进路线
飞书有什么优点
和钉钉对比了一下,讲了些不错的地方
同时也讲了下不足之处,Lark和飞书之间的问题
最终通过