iOS 面试策略之代码考查到offer的比较和选择 - 图1

4.代码考查和系统设计的准备

1.如何准备代码考查

很多面试的能力都不是突击可以获得的。项目经历不是,代码能力也不是。如果说项目经历的获取还需要环境支持的话,代码能力的提高基本只需要自己投入就可以了。

在网上有很多练习编程的网站,特别是像面向求职者的 LeetCode 一类的网站,提供了各大公司的代码考察题目,并且大部分题目还有标准解答和示意代码。你可以在上面一遍一遍地练习,以提高自己的代码转换能力和逻辑思维能力。我建议大家至少做 100 道 LeetCode 里面 Facebook、Apple 这些大公司的代码题目,很多题目都设计得非常好,既是很好的练习题,又可能在实际工作中用到。Google 的面试题通常还要更难一些,对自己要求更高的同学也可以挑战一下。

我曾经面试过一个清华的应届生,考查他各种面试题目都解决得非常快,我就好奇他是怎么做到的。他回答说:他花了一年时间,把 LeetCode 上面的所有题目做了三遍。当时 LeetCode 上面大概有 700 道题目。你看,即使是清华这样厉害学校的学生,同样在代码练习量上非常努力。我自己觉得,这个应届生在努力程度上,就可以超过 95% 的别的候选人了。

如果是非科班的学生,在写代码前你还需要学习数据结构和基本的算法知识。相关的学习资料可以选择国外的公开课,或者国内 985 大学计算机专业的教材。麦克道尔著的《程序员面试金典》也是非常不错的学习资料。

除此之外,在纸或白板上写代码的能力也需要好好练习。纸上写代码麻烦的地方在于不方便及时涂改,所以需要思考得比较清楚再动手写。准备一些 A4 纸,然后拿 LeetCode 题目多练习几次,慢慢就会有感觉。

我自己在纸上写代码的经验来着早年在大学时参加的 ACM 国际大学生程序设计竞赛,这是一个 3 人组队参加的比赛。比赛时 3 个人可以合作答题,但是只有一台电脑可以使用。所以为了最大限度地提高电脑的利用率,我们同时做 3 道题,然后会现在纸上写代码,等自己在纸上完成代码的编写后,再使用电脑来录入和调试。为了备战 ACM 比赛,我差不多有几百道在纸上手写代码的经验。

我最后总结出来在纸上写代码的要诀是:一定要先把整体逻辑框架梳理清楚,然后再填充细节。所以你可以用文字、流程图或任何你喜欢的方式先把代码整体逻辑描述在纸上,然后检查没有边界问题后,再在纸上细化成具体的代码。

2.写代码之外的沟通

即使是做代码题目,必要的沟通交流也是必须的。我见过很多候选人听完题目就埋头写代码,完全不和面试官交流,这其实是非常错误得做法。如果写代码完全不需要交流,那么为什么不当做笔试题,而要耽误面试官的时间坐在你旁边?难道就只是为了监督吗?

其实,解决一道代码题目的思考过程是非常有价值的,面试官问你一道代码题目,其实是希望和你一起沟通交流,了解你的思路,帮助你找到最好的解法,最后才是把代码完成的事情。

所以,当面试官给你一道题目,你首先要做的是和面试官足够地交流。你可以首先确保你完整地理解了题意,这可以通过询问题目的一些细节来达到,比如问输入的数据范围,输出的具体要求,一些异常的情况是否要考虑等等。

等你完全理解题意之后,下一步就是将你的想法说出来。你完全不必担心没有一下子说出最好、最完美的解法,大部分好的代码题目都可以一题多解,你可以先说一个最简单直接的方法,然后说出这种方法的时间复杂度、空间复杂度。一般面试官都会问你有没有更好的做法,或者你也可以直接说想思考有没有更好的做法。接着你可以试试看能不能想出一些办法,即使一些办法没有完全想清楚所有细节,也可以说出来。好的面试官如果发现你的方法完全方向不对,还可以及时干预。

你如果在思路上有卡住,你甚至可以请求面试官给你一些 “提示”。虽然这可能使得你面试表现稍微减分,但是比起完全没有写出代码来说也要好很多。

除了写代码之前和面试官交流、确认解法,写完代码之后,你也需要和面试官讨论你的代码细节问题。通常代码中多多少少会出现一些问题,面试官会给你一些引导,帮助你发现并且修改有问题的代码。

3.如何准备系统设计

如果你是一个应届生,通常考查的系统设计题都不太难,你只需要有一些系统设计的基础,都不至于完全答不上来。在准备资料上,可以看看《设计模式》相关的书。如果有机会实习,可以多尝试一些不同的职位,如果你同时尝试过客户端和服务器端开发,在系统设计上就可以更加综合考虑设计方案在多端的实现难度,以便做出权衡。

另外,你可以通过学习分析一些开源项目的代码,来学习架构设计。在网上,你通常也可以搜索到一些常见的系统设计题目,在本书的上一节中,我也提供了好多系统设计题。把这些系统设计题目仔细研究,尝试自己实现一下,通过实践并且和同学讨论,相信你也会有不错的成长。

系统设计题目通常都不会有特别标准的解答,其实考查过程更看重一个人分析解决问题的思路。这样的思路可以保证即使未来遇到没有见过的问题,也可以从容地系统性思考和判断。所以,你需要给面试官展现你思考的过程。在面试中,了解需求细节,解释设计思路,讨论和判断一个设计的优缺点,都能够让面试官体会到你这方面的素质。

虽然没有标准的答案,但是系统设计还是有一些解题套路,下面我就给大家介绍一下。

首先系统设计题都非常考查一个人知识的全面性。所以大家应该平时多了解一些 iOS 之外的技术,比如适度了解一下 Android 端、Web 端以及服务器端的各种技术方案背后的原理。你可以不写别的平台的代码,但是一定要理解它们在技术上能做到什么,不能做到什么。你也不必过于担心,面试官在考查的时候,还是会重点考查 iOS 相关的部分。

在知识足够宽泛的情况下,你需要首先和面试官明确问题的各种细节,比如假如题目是“设计一个类似微博的信息流应用”,你需要了解清楚这个信息流应用更多的技术要求,比如:

  • 信息流的内容是否包括图片,文字,语音。
  • 平均每个用户每天有多少的信息流更新量。
  • 是否需要做图文混排。
  • 是否需要做图片的缓存,历史信息的缓存。
  • 断网情况下是否需要显示离线内容。
  • 发送失败情况下是否需要暂存内容。
  • 系统对核心功能的性能(例如发送,刷新)的要求是多少。

有一些技术细节可能是面试官想考查的,你问的时候他就会要求多一些;有一些技术方案明显很复杂的,你提出来,他即使不考查你,也会觉得你的考虑是足够周全的。

在确定技术细节要求后,你就可以开始讲你的系统架构设计了,这个时候讲的要诀是先框架,再细节。你需要先把各个模块的层次画出来,比如刚刚那道题目,你先介绍一下整体 App 是怎么和服务器通讯的,服务器端的信息流大概是如何存储的,然后你就需要详细介绍 App 的部分。

在介绍 App 的框架时,先画出 Model 层,Controller 层,View 层。然后再进一步细化,比如把 Model 层细化到本地存储,图片缓存,网络请求等模块。View 层如何处理图文混排,Controller 层如何与其它层通讯。

当框架介绍得差不多的时候,你需要把后续的选择交给面试官。面试官可能会选其中某一个模块,让你做更细一步的设计。比如让你设计网络通讯的 RESTful 接口,细化缓存相关的 API 名字。面试官甚至可能选一两个具体的函数,让你写写。面试官也可能进一步挑战你的一些设计细节,这个过程中,你可能需要修正自己的设计,也可能需要解释你的设计。

下图就是回答系统设计题的框架。

iOS 面试策略之代码考查到offer的比较和选择 - 图2

一道系统设计题的考查方式可以千变万化,需要的是你和面试官之间密切地交流,性格内向的程序员很可能在这方面吃亏。所以,除了有方泛的知识面以及扎实的架构设计基本功外,多和面试官讨论交流也是面试过程中的关键因素。

5.复盘

复盘是一个人持续提高和进步的源泉。也许你觉得你的面试表现很好,但是为什么面试没有通过呢?当你被拒的时候,与其抱怨面试官或者面试流程不公正,倒不如静下心来想一想,看看是不是自己忽视了某些细节或者关键点。如下图所示:
iOS 面试策略之代码考查到offer的比较和选择 - 图3

例如,当你的算法或系统设计题解决方案不太好时,面试官通常不会直接纠正你,他只会稍微引导一下。面试结束后,他更不可能给你做教学,教你应该怎么做答这些题目。所以,你的解决方案好不好,你其实只是凭感觉来的。你可能觉得你已经解决了这个问题,但是面试官可能心里想,这个解决方案虽然可以工作,但是是他见到过的最最愚蠢低效的办法。

所有的这一切,你都无法直接知晓。你只能在面试之后,特别是被拒之后,仔细复盘分析一下,看看自己可能哪些问题回答得不好。这个时候,找人请教和讨论也显得特别重要,你可以把你怀疑的一些面试糟糕表现描述出来,然后找人一起分析一下,通常情况下都会有一些收获的。

除了复盘算法和系统设计题,也需要复盘一下自己整体的面试流程是否表现正常。例如:

  • 我的自我介绍是否流利?
  • 我的项目沟通是否介绍清楚了?
  • 面试官有没有完全理解我介绍的项目挑战?
  • 我的时间控制是否到位?
  • 我有没有迟到,中途接电话,或者任何被认为不礼貌的行为?
  • 我做得不好的地方,有没有短期可以改善的?
  • 我做得不好的地方,短期不能改善的,我能不能用别的方式适当弥补?比如面试中强调自己的强项。

每次面试后,做一个小结,可以使得自己每次都会有一点点进步,几十场面试下来,相信大家都会有不小的成长。

5. 如何提问

有些时候前面的环节占用了太多的时间,面试官可能就不会给你提问的机会。但如果面试官说:“我的问题问完了,你有什么问题吗?” 那么恭喜你,你基本上已经完成了整个面试,而且还有一点时间可以交流一下。通常这个提问环节留给双方的时间不会特别多,所以可以就你关心的问题来提一到两个问题即可。

很多候选人会说:“我没有什么问题”。这是可以的,但是这个环节最好还是提个问题稍好一点,它能够显示出你对目标公司的关注和兴趣。提问的内容可以围绕着技术氛围、技术分享、公司的业务、未来的方向等等。比如:

公司在 iOS 端主要使用了哪些技术框架?
公司内部有技术分享或者别的学习交流机会吗?
公司当前团队有多大,希望我进去参与哪方面的业务?
公司当前有没有什么大的竞争对手?
未来公司希望在哪些产品上重点发力?
但是切忌不要问以下这些问题,否则会显得自己很不专业。

1.询问面试表现
很多人在面试结束后,都忍不住问:“我刚刚的面试表现怎么样?”面试官通常都不会当面评价候选人,因为这可能引起冲突。大部分候选人都不能冷静地面对面试批评。而即使你面试表现很好,是否录用也取决于你的竞争者的表现是否在你之上,所以面试官真的很难回答这个问题。

通常如果你问了这个问题,面试官要么糊弄地回答:“还不错”,要么就诚恳地回答:“我们通常不当面反馈面试表现”。

2.询问面试题答案
有人会在面试结束前问:“刚刚那道题目应该怎么做?”面试官听到这种问题通常只能苦笑一下。你要知道,这是面试,不是面试培训。面试官没有义务给你解答题目,而且通常为了保证面试题目资源的保密,面试官也不愿意把一道题目的最优解告诉你。如果你回去告诉了你的朋友,这道题目就没有考察的功能了。

如果你特别想知道面试题答案,还是应该自己在面试结束后仔细钻研。大部分公司也会要求候选人对面试题保密,所以如果你把题目放到网上共享,通常也是不被允许的,严重的情况下,可能造成通过的面试 offer 因此被取消。

3.询问薪资
大部分公司的薪资都是非常保密的,能知道薪资的人除了 HR 外,只有很高级的主管才有可能知道。大部分的面试官可能都不知道你的职位薪资。所以如果你有这方面的需求,应该直接找 HR 咨询,而不应该问面试官。

一般你的最后一轮面试官有可能是你未来的主管,他可能会询问你的薪资和期望,遇到这种情况,你可以趁机反馈出自己的意愿,但如果面试官没有提,最好你也就不要问这方面的信息,以免面试官拒绝回答造成自己过于尴尬。

小结
整体来说,面试的打分和提问环节相关性不大,所以大家只要别问敏感问题即可。

6. offer的比较和选择

恭喜你!经过努力,你最后拿到了好几家公司的 offer!这些公司有的规模很小,是成立不久的创业公司;有的已经是纳斯达克的上市公司,员工数量过万;有的是外企,有着复杂但是规范的流程;有的是国企事业单位,工资虽然不太高但是福利好并且工作压力不大。你该如何选择?

很多人都会纠结,我也曾经纠结过。现在回过头来,我觉得要做好选择,核心还是对自己的情况有一个清晰的判断。每个人不一样,所以最后的选择也不一定一样。

1.工作 vs 生活
这辈子打算怎么过,其实很多人都没有想得特别清楚明白。每个人的选择没有什么高低贵贱之分。也许你希望新工作能够尽量兼顾工作与生活,也许你希望新工作能够帮助自己快速在职业上成长。生活的目标不一样,答案也就不一样。想清楚了,答案就明显了很多。

如果你希望尽量兼顾工作与生活,那么那些工作强度大的 offer 自然应该就排在低优先级。哪些公司工作强度大?询问一下对方公司的 HR 或者面试官,平常的上下班时间,加班的频率,通常都可以得到比较客观的回答。如果你恰好有在目标公司上班的朋友,那么你应该可以获得更多这方面的信息。你也可以在网上搜索相关的关键词,获得信息。

其实在很多国家,人们并不是那么看重工作的,很多人更多的看重生活以及家庭。只是国内的环境以及我们从小的教育,使得我们很看重工作,以及工作的职业成长。

2.职业成长
大部分人看重职业成长,这一点非常好理解:程序员是一个需要持续学习和积累的工作,如果不能在工作中持续学习成长,几年之后如何在职场获得立足之地呢?但追求快速的职业成长不一定表示一定要去工作强度特别大的公司,其实核心还是看:

工作的内容
指导你的导师(我们行业内常常叫 Mentor)
一个有职业成长的 offer,其工作内容应该可以让你建立起对相关专业领域的完整知识,并且该工作内容很可能具有成长性和发展性。比如,如果是偏研究的工作,基于深度学习的研究就比别的人工智能研究更加具有成长性。又如,做用户产品就比做内部系统更具有成长性。

如果你的 offer 是去维护一个已经开发了 10 多年的老旧系统,除非是要你花大力气重构它,否则你的工作成长性也会较差,因为难的问题都已经被别人早解决过了。

行业的成长也很重要,比如互联网行业就比传统的软件行业好,移动互联网行业又比传统互联网行业好。选了一个好的行业,你的能力和待遇会随着行业的发展而发展。选错了一个行业,即使你做到这个行业的冠军,整个行业不挣钱,你的日子也不会好过。

除了工作本身的吸引力外,指导你的导师也很重要。一个领域的知识架构是什么样的,重要的观点和讨论,都是一个好的导师能够指引的。当然,你不要抱有什么事情都是导师手把手教这种幻想,这在公司里面既不现实,也不利于你自学能力的发展。

3.职业背景
有一些人,特别是学校不太好的人,会特别看重第一份工作的公司背景。因为大部分公司在挑选简历的时候,差不多主要就看两条:毕业院校和工作过的公司。所以,我建议学校不太好的同学,可以在考虑 offer 的时候选择名气比较大的公司。这样对你未来的简历,会有一定的加分效果。

但如果你已经是非常好的学校(比如 985、211 院校)的毕业生了,那么我建议你不用太考虑公司的名气。因为对于你来说,学校背景这一条已经够你用作未来面试的敲门砖了。

4.薪资的考虑
通常情况下,你的薪资是符合市场上相同工作年限的薪资范围的。在薪资范围内,你能拿到多少取决于新公司的内部薪资标准、你的面试表现,以及你以前的工作经历。

大部分人的直觉想法都是:「谁给的钱多去谁那儿」,但是我建议大家也综合考虑上面提到的职业成长以及公司的背景。如果一个工作没有职业成长性,那么给得钱再多,我也不建议大家去。

应届生的薪资通常都是不能谈的,但是非应届生因为每个候选人情况都不一样,很可能可以谈。

5.考虑创业公司
如果你的学校背景特别好,又在比较好的大公司实习过,那么如果有一些上升期的创业公司,其实也是不错的选择。

首先,在这些创业公司里面,你可能获得更多的锻炼机会。然后,你的学校背景和实习经历,使得你即使换工作,也不会因为在创业公司很受影响。最后,也是最重要的是,如果这家公司最终上市,你有可能因此获得极大的期权回报。

6.讨论与决策
以上我提供了一个基于工作和生活侧重点不同的考虑方式,考虑到每个人自身的具体情况,其实你还可以有别的考虑方式。比如有一些人可能父母身体不好,希望更多的离家近;又可能有一些人身体不太好,不希望太累。在你有了你的一套考虑逻辑以及结论之后,我还是建议你找你欣赏的人讨论商量一下,分享一下你的决策思路,也听听他的意见是什么。这些人可能是你的同学,朋友或者是导师,长辈。

一个好的决策应该是充分收集信息,并且独立决策的。所以你和少数人的讨论过程,有助于进一步判断你的思路是否有漏洞。一个人的 offer 还是会影响他好几年的职业生涯,所以在这个阶段多收集信息,多思考是非常必要的。但是我们也要切忌人云亦云地做决策,一定要自己独立的做判断,不要简单的盲从权威或者大众,因为没有任何人比你自己掌握的信息更多。

7.反馈
在你做完决定之后,你就需要给公司反馈你的结果了。对于拒绝的 offer,你应该礼貌地表示歉意,并且希望以后可以保持联络。谁知道你未来会不会再次考虑他们的 offer 呢?

对于你接受的 offer,你应该更加积极地获取更多的信息。比如看看能否有机会和未来的团队 Leader 见面,了解一下未来工作可能用到的技术栈,提前体验一下公司的产品或者做一些相关技术上的学习。这些都可以帮助你更好更快地融入新的公司和团队。

8.心态的调整
鱼和熊掌不可兼得。很多同学可能在 offer 选择的时候患得患失,最后即使做了决定,也会有后悔的时候。我想说大家还是应该调整好心态,没有哪个公司是完美的,在我们 IT 行业,也很少有人在一个公司待一辈子。所以调整好心态,决定了 offer 之后,就把该放的放下,努力把自己的思想放在未来的工作本身上。因为只有自己的能力提升了,才可能有更大的职业成长空间。

小结
总结一下,你首先要对自己的未来生活有一个规划,是更偏重于家庭和生活,还是更偏重于工作。

然后,如果你希望偏重于工作,那么你需要考虑:职业成长性、职业背景、薪资。如果你特别优秀,我也建议你考虑一下创业公司的机会。

最后,你的决策过程应该和重要的人讨论,但是决策本身仍然应该由你自己做出。做出决策后,你应该礼貌地拒绝掉不接受的offer,然后对于接受的offer,做进一步的信息沟通和入职准备。

小编推荐阅读