2021年12月25日星期六

互联网选大厂还是小厂:读了本书还是写了本书

这个系列上次写到《互联网选大厂还是小厂:数据中心里有朵云》,这次简短地写一个小一点的区别。在小公司,你更容易遇到同事说「我读了本书,书上说的这个事情能解决我们遇到的问题。我把书上说的事情投入实际应用后,得到了这么好的效果。」在大公司,你更有可能遇到同事说「我是这本书的作者,有问题欢迎来问我,我也可以定期组织相关的研讨。」

有资格写书的大神门往往聚集在大厂中,小厂很厉害的话或许能抢到一个这样的大神。这些人已经工作很多年了,积累也很深了,有心情就把知识整理出来写本书。科技理论的前沿往往发生在学术界,但科技落地的前沿是在大厂。大厂把学术界早就搞明白的事情拿过来,然后进行从来没人实践过的落地。在这方面,大厂提供了更多的机会去做探索。因为前人没做过,就算理论摆在那里,也不可能有书把这件事情描述清楚。

小厂正好是反面,走的路往往是无数前人已经走过的路,成长过程中遇到的问题很多其它公司早就遇到过,已经有人把解决问题的方法抽象出来写成书。这即是优点又是缺点,要看你站在什么角度去看。从创造影响力的角度来看,这是优点,一个应届生新人,不需要很强的原创性,不需要很好的研究能力,读本书就有机会为公司解决大问题,然后得到升职加薪之类的回报。在大厂,这是不可能的,写书的作者都在这里了,如果有利用这本书上的知识就能创造影响力的机会,早就已经做了,怎么可能轮到你呢?但在大厂里,你可以直接接触到作者哦,你可以跟他一起工作,直接从他身上学习,这是小厂没办法提供的。

2021年12月4日星期六

互联网选大厂还是小厂:数据中心里有朵云

时常会有人来问我,应该加入大厂还是小厂。提问的方式有时候是很具体的,例如说「我有这几家公司的 offer,他们规模不一样,这会对我的职业发展产生什么影响呢?」有时候是很抽象的,就是讨论一下以后找工作到底应该专注于大概是什么规模的公司。我曾经想要写一篇长长的文章,从不同的角度来对比大厂和小厂的区别,最后发现很难完成。现在我决定换一个方法,想到哪里就写到哪里,写完一个具体能进行对比的角度,我就发一篇文章。

在这篇文章里,我想要对比的是大厂和小厂在规模上的本质区别。如果你希望接触到一些特大规模的技术问题,你就只能选择进大厂,因为小厂不会遇到这类问题,也就没有机会让你去接触这类问题。这里有一个很有意思的故事,叫做「数据中心里有朵云」,是个很好的例子。

Facebook 早期跟那个年代的其它公司一样,也是在别人的机房租机位开始的。后来做大了,就有了自建机房的需求。机房需要廉价的土地、电力和制冷,荒漠能够很好的满足这三个需求。Facebook 为了节能,专门设计了利用荒漠低温空气对服务器进行降温的通风系统,一旦发现室外温度比室内空调温度还要低,巨大的风扇就会启动,吸入室外温度更低的空气进来降温。

荒漠通常是零降水的,但有一次傍晚真的下雨了,导致室外气温迅速下降,机房开始从室外吸入冷空气降温。因为刚刚下过雨,室外空气虽然温度低但湿度非常高,进入室内后迅速被服务器温度加热升温。数据中心天花非常高,高温度高湿度的空气自然会往上跑,最终空气中的水分冷却后变成云。据说当时在数据中心的人听着服务器发出霹雳啪啦的火花声音,但没有任何办法去抢救服务器。他们把这次事故描述为「There is a cloud in the data center」。

Facebook 后来学聪明了,不能简单根据室外空气温度来判断是否应该吸入室外空气来降温,还要加上室外空气湿度作为限制条件。这种类型的问题,现在世界上也就只有几家公司能够遇到,因为现在绝大多数互联网公司只需要用别人的云服务,不需要自己拥有物理机器,更不需要自建数据中心。如果你想要接触到这类其它公司都没解决过的前沿问题,那只有大厂能够有足够的规模去触发这类问题,小厂根本触发不了。

类似的问题在 Facebook 其实不少,但也就只有这种规模的公司能遇上。举个例子,Facebook 曾经用 BitTorrent 来部署 web 服务器的更新,因为 web 服务器数量过多(百万级别),向每一台 web 服务器单独上传几个 GB 的编译文件效率太差。更新不是就覆盖几个 PHP 文件吗?为什么是几个 GB 的编译文件?因为 Facebook 那时候使用 HPHP 把 PHP 转译为 C++ 再编译为二进制文件。那为什么 Facebook 要发明 HPHP?因为 PHP 执行效率太差,当时有人根据历史数据进行拟合,发现 18 个月后 Facebook 的用户服务器比(用户总数除以服务器总数)将会下降到 1.0,就算 Facebook 有那么多钱买服务器,世界上也没有那么多机位放服务器,所以必须想办法提升执行效率。

所有这些规模导致的问题都是一环扣一环的,一个发明创造解决了上一个规模导致的问题,同时也带来了机遇给下一个发明创造。这种类型的发明创造只能发生在大厂里,因为小厂触发不了这个级别的规模问题,也没有充足的资源去进行发明创造。

2021年9月18日星期六

面小厂就比面大厂更容易吗?

在我做 career coaching 的过程中,我发现不少人觉得「如果进不了大厂的话,那就降低一点目标,总能进小厂吧」,然后他们发现小厂 offer 也拿不到,于是怀疑自己能力是不是如此之差。大家从升学考试的经验出发,「进不了这一档次的学校就尝试下一档次的学校吧」,把这种逻辑推广到「进不了大厂就尝试小厂吧」看起来很合理,但很不幸人才和公司的匹配并不适用这种模式。


我时常用这样一个比喻来描述大厂和小厂招聘的本质区别:

大厂招聘,就如同 Walmart(沃尔玛)去采购两吨苹果用来上架。作为一家超市,Walmart 肯定有一套经过长期优化的采购标准,一个苹果只要满足采购标准 Walmart 就愿意要。Walmart 不在乎这些满足标准的苹果之间有什么个体差异,因为绝大部分都会被顾客买走,一小部分会卖不掉然后烂掉,但这早已在营收当中考虑到,Walmart 并不会亏钱。

小厂招聘,就如同个人消费者去买两个苹果。无论你个人对挑选苹果有什么准则,你肯定会按照你的准则挑选两个最好的。每个人的挑选准则都不太一样,如果有足够多的消费者,绝大部分的苹果都会被买走。

应聘时你就如同是一个苹果。如果你想被 Walmart 采购,你就要满足 Walmart 的采购标准。但因为 Walmart 是一个非常成熟的超市,所以采购标准相对稳定和可预测,反而更容易有针对性地做优化。如果你想被个人消费者挑选,反而很难抓住具体的某一个消费者让他挑你。每一个个人消费者的挑选准则都不太一样,你猜不到当前在挑苹果的这一位消费者是怎么想的,如果他不挑你你也没有办法,再等下一位消费者吧。这个过程比较看缘分。


为什么大厂和小厂的招聘模式会截然不同?

小厂招聘往往是针对一个或几个很具体的职位做的。举个例子,公司创业一开始还没找到产品方向,想要招一两个什么都懂但不用太精通的全栈工程师,创始人想要尝试做什么产品,熬个夜第二天就把原型做出来了。尝试了多个产品方向后,公司终于找到了一个靠谱的方向,开始缓慢地有用户积累,顺便招个前端工程师来打磨用户体验。用户增长持续加速,当初熬夜写出来那个单体后端已经支撑不住了,于是要招个有 micro-service 经验的后端工程师来重新设计后端架构,把后端拆成多个服务,并且为将来 sharding 做准备。服务拆了之后,单体数据库通过 replica 还撑了一段时间,终于也要不行了,需要赶紧招一个精通数据库优化的程序员。小厂每时每刻面临的问题都不一样,用固定的标准招通才并不能有效解决问题。

大厂可以用固定的标准招通才,尤其是 Facebook 和 Google 这种全公司统一招聘的。虽然大厂内的每一个团队都好像小厂一样,拥有此时此刻特定的招聘需求,但因为团队数量足够多,所以在统计学上大厂可以无视这些差异按照一个标准来招人。由于大厂的招聘标准如此的稳定和可预测,针对大厂的招聘标准做准备反而更容易。你可以尝试搞清楚大厂的招聘标准,搞清楚后这套标准不会变来变去。一旦你满足了这套标准,你不需要太过关心个体差异。

如果你达不到大厂的标准,要参与小厂的招聘,那马上就会变成跟上述苹果比喻一样看缘分。你不知道具体哪个小厂正好需要你,你要明白到大部分的小厂当前的需求都跟你不匹配,从统计学的角度来说你必须通过大量的小厂去找一个匹配的。这时候你的体验会变得完全不一样,从只需要针对几个大厂做准备变成需要跟很多小厂打交道。


从升学考试经验推导而来的期望在这时候完全不成立。如果你高考差几分上不了北大清华,你很可能还是能去非常好的学校。但在找工作时,差一点进不了大厂并不意味着马上有小厂意识到你的价值把你招走,你需要在茫茫大海中搜索跟你匹配的小厂。这时候设置正确的期望很重要,大量小厂跟你擦肩而过,但这不代表你能力有问题,你需要坚持下去。

小厂的招聘流程并不像大厂那样标准化和可预测,那意味着他们扔掉你简历时并不一定是你简历有问题;他们面试时不像大厂一样按套路出题,他们会针对特定的招聘需求来出题,所以你答不上来不一定是你能力有问题;经验有限导致他们的面试并不一定能有效挑选人才,你觉得自己面得很好但他们不要你,同样不一定是你能力有问题。这个过程的负反馈可能比应聘大厂难受很多,你唯一能选择的就是坚持住继续尝试。

2021年6月27日星期日

如何有理有据地说服其他程序员

TL;DR 当两个相对聪明和胜任的程序员对同一个问题持有截然不同的观点时,往往问题出现在大家对问题的定义不一样。争辩观点对错的往往并不能达成一致,这时候必须先确认大家在讨论的是同一个问题。如果没办法对齐(align)问题,尤其是当双方的优先级(priority)不一致时,争辩问题的解决方案是不可能有结果的。

人际矛盾

人际矛盾是行为面试(behavior interview)中常见的考点,作为面试官我自己经常问相关的问题。例如说,我在 Facebook 时就经常问以下两个问题:

  1. 有没有试过你和你的同事各持不同的观点,而且双方都坚持认为自己是对的,最后你成功说服了对方?
  2. 把上面的问题反过来,有没有试过最后你被对方说服了?

对于不同级别的程序员,我们对人际矛盾有不同的期望值。初级程序员,就算不能把矛盾解决,至少不能把矛盾激化。高级程序员,需要有能力把矛盾化解掉,从而推动自己的项目前进。更资深的程序员,需要有能力梳理组织当中错中复杂的利益和矛盾关系,优化组织提高效率。

在这篇文章里,我们的关注点是如何化解人际矛盾,这是很多初级程序员需要学会的技能,也是很多高级程序员需要持续提高的技能。在 career coaching 过程中,我时不时也会遇到客户提出这方面的问题,我给出的方案都是类似的,因此我觉得用一篇文章来解释会更好。

两个聪明人解同一问题……

我还在 Facebook 时,一个非常资深(总监级别)的华人程序员在一次吃饭时分享了一个观点:如果两个聪明人尝试解决同一个问题,但他们各自得出了不一样的答案,往往并不是其中一个人错了,而是他们拥有的信息不一样,各自根据自己拥有的信息进行推理就会得到不一样的答案。这时候双方必须先互通有无,把自己拥有的信息都摆到台面上来,然后再一起利用眼前的信息解决问题。

这一个观点是我的理论基础。我见过很多人因为意识不到这一点而陷入无效的争辩,甚至激化双方情绪。尤其是强调逻辑思维能力的程序员,很容易推理出这样一个结论:因为一个问题必然有且仅有一个正确的答案,又因为我和你的答案不一样,所以我们两个当中至少有一个人是错的。因为我很确信我自己是正确的,所以你必然是错的。因为你是错的,所以你比我笨。

这个推理过程是正确的,但前提是两个人在解决的是同一个问题。否则就如同考试后对答案发现两个人的答案不一样,争辩半天谁对谁错后才发现这场考试分 A 卷和 B 卷,大家做的根本不是同一道题。很多聪明人都犯过这样的错误,也就是跟别人争辩为什么自己的解法是对的,而忘记了检查大家是不是在做同一道题。

先定义问题再讨论解法

对于很多名校毕业或者大厂工作的程序员来说,其实自己和身边的人都已经足够聪明了。如果发现自己在跟别人争辩观点争辩不出来结果时,最好就先审视一下双方是不是在讨论同一个问题,如果不是很确定的话就先把问题定义清楚。当然,复杂的问题不可能方方面面都定义得很清楚,还是会涉及很多假设。如果双方对约束和优先级做了不同的假设,得出不同的结论是很正常的。所以我会建议大家先明确约束和优先级都有哪些。

对约束进行不同的假设

两个人从广州出发去北京,A 说往左走,B 说往右走。这时候看起来「从广州去北京」是同一个问题定义,但可能 A 想着的是去机场搭飞机,B 想着的是去火车站坐火车,所以走了不同的方向。如果两个人对于交通工具没什么看法,那澄清一下自己假设使用的交通工具矛盾就化解了。「我以为我们去搭飞机呢,原来你想着的是坐火车。我其实没什么所谓,你想要搭什么我们就一起走吧。」

但如果有更深层次的原因导致他们做出这样的假设呢?例如说,B 没有钱搭飞机,他只能坐火车。这就是一个约束了,加上了这个约束问题定义就不再是「从广州去北京」,而是「用有限的钱从广州去北京」。如果 A 不知道 B 有这个约束,那 A 和 B 在解决的就不是同一个问题。接着 A 和 B 可以就飞机好还是火车好大战五百回合,但矛盾仍然是解决不了。要化解这个矛盾,就必须要让 A 知道 B 有一个钱的约束,之后问题可能多种解法。A 可以说「那我陪你一起坐火车吧」,也可以说「我多出点钱请你搭飞机吧」。但如果 B 觉得没钱搭飞机是一条必须隐藏起来的信息,那这个矛盾就非常难解决了。(你需要一个情商非常高的 A,在获得这一条信息后按照这个约束来解题,同时又不暴露自己掌握了这一条信息。)


我在管理某个 iOS 的团队时就遇到过由于对约束的假设不一致带来的矛盾。我们在做一个新的 app,一边是两位很资深的程序员,他们拥有丰富的创业经验,他们用创业的风格迅速的写了一版原型;另一边是几个大厂培养出来的高级程序员,他们接过这个原型,把它打磨成最终能发布的产品。这种一边是特种兵另外一边是正规军的配合,很快就出现了矛盾。其中有一个矛盾我印象深刻,因为这个矛盾明显就是由约束不一致造成的。

正规军觉得特种兵写的原型代码是渣渣,接手后就开始大规模重构,按照 iOS 的思路把东西都封装进不同的 ViewController 里面。特种兵觉得正规军在浪费时间重构,正规军觉得这样做才符合大厂规范。这个矛盾我深挖到底,才发现源头来自于哪里。在特种兵打头阵写原型时,他们负责解决的是最难的技术问题,因为这些问题交下去给别人写可能就解决得不够好。其中一个技术挑战是,这个 app 在云端有三万张照片时,客户端要能够流畅地滚动和浏览照片。这个挑战在原型中是解决了的,但重构的过程中为了进行封装,一个原本 O(n) 的算法就被迫重写为 O(n^2),于是客户端在有三万张照片时滚动就不再流畅。

这里的隐藏约束就是「有三万张照片时要能流畅滚动」,这是当初特种兵带头立项时定下来的需求之一。但这没有很好地沟通给所有人,所以当正规军接手后就不知道有这个需求。在没有这个约束时,重构一下能提升接下来的工作效率那当然应该重构,于是就重构到不再符合这条约束了。这个矛盾的本质跟前面的例子一样,「显示云端照片」和「显示三万张云端照片且能流畅滚动」不是同一个问题。

对优先级进行不同的假设

A 和 B 又要从广州去北京了,这时候 B 已经有钱搭飞机了,但 A 反而想要坐火车了。A 尽管有钱搭飞机,但他最近想要存钱投资,觉得坐火车省钱更好。B 则想要快点到北京,多一点时间在北京玩。这时候看起来问题都还是「从广州去北京」,但两个人的优先级是不一样的。A 要解决的问题是「用尽量少的钱去北京」,B 要解决的问题是「用尽量少的时间去北京」,这自然会导致不一样的解法。

不同优先级带来的矛盾更难解决,因为有时候就算双方都把自己的优先级摆上台面了,但因为双方都只在乎自己的优先级不在乎对方的优先级,问题定义无法达成一致,最终问题不可能被好好解决。如果 A 坚持要省钱,B 坚持要省时间,那就算双方把问题定义清楚了,还是不能一起解决。最终的方案可能是,A 提前出发坐火车,最后跟 B 同一时间达到,这样 A 省了钱同时 B 省了时间,但两个人就不能同行了。


这种矛盾在那些前后端明确分工的公司还挺常见的:后端的优先级是自己少干活,最好就是 API 数据结构和数据库直接存在映射关系,复杂的场景就让前端调用多个不同的 API 然后自行组织数据维护状态吧。前端的优先级也是自己少干活,最好前端要做的每一件事情都只需要一个对应 API 调用就能解决,如果多个 API 调用之间需要维持状态那就应该由后端来维持。这种优先级的矛盾,如果双方都隐藏起来不说,再怎么争辩什么是「更好的系统设计」都没有用。如果双方愿意把自己的优先级说清楚,明白到对方的苦处,找个折衷方案,各自承担一部分的负担,那才能把矛盾化解掉。

总结

最后总结一下,当你发现你跟别人争辩不出结果时,尤其是你觉得自己是对的但对方好像也有道理时,你最好检查一下你们是不是在解同一道题。往往你会发现你们在解的不是同一道题,这时候你们就应该先讨论问题的定义,把问题定义清楚往往很快能找到一个双方都同意的结论。当然有时候因为双方优先级不一致,无法接受同一个问题的定义,那就是另外一类问题了。有空我可以再写写如何应对优先级不一致造成的矛盾,大家可以订阅/关注我,这次就先写到这里。

2021年3月7日星期日

SystemsExpert 测评

SystemsExpert 是 AlgoExpert 新出的一系列针对系统设计面试的内容,包括系统设计常见概念的科普型视频,以及若干模拟面试题和答案。它的内容非常适合从来没有面过系统设计的人,用来了解系统设计是面什么的,以及需要用到哪些知识点。

我接触到不少学生,毕业时通过了算法面试、成为了软件工程师,工作一段时间后跳槽时发现需要面系统设计,但因为从来没接触过所以觉得心虚。其实大家工作一段时间后,都或多或少地在实践中接触到了系统设计,要么是看过已有系统被设计成什么样子,要么是自己设计如何把新功能添加到已有系统上。但是可能因为没有非常刻意地做设计、覆盘、沟通,所以知识不成体系。SystemsExpert 能够帮助大家解决这方面的问题,通过二十多个视频系统地讲述每一个常见的系统设计概念。可能你看完后会发现,很多概念是你已经在工作中用到了的,只是现在变成了一个很具体你能拿来跟面试官交流的东西。

现阶段 SystemExperts 包括以下这些概念的视频:

  • 客户端-服务器端模型
  • 网络协议
  • 存储
  • 延时和吞吐量
  • 可用性
  • 缓存
  • 代理
  • 负载均衡
  • 散列化(Hashing)
  • 关系型数据库
  • 键值存储
  • 特种存储(Specialized Storage Paradigms)
  • 复制和分片(Replication And Sharding)
  • 领导选举(Leader Election)
  • P2P 网络
  • 轮询和流式传输(Polling And Streaming)
  • 配置
  • 限速(Rate Limiting)
  • 日志和监控
  • 发布/订阅模式
  • MapReduce
  • 安全与 HTTPS
  • API 设计

除此之外,SystemsExpert 还有一个视频提供系统设计面试的概述,简单介绍系统设计面试是考察什么的。每一个视频十分钟上下,不需要花很多时间看,内容很容易理解,但不会讲得很深入。

以上是 SystemsExpert 的优点,但它也不是没有缺点的。缺点是模拟题不可能好像 AlgoExpert 或 LeetCode 那样给你任何的反馈,唯一模拟了的地方是面试官回答你的 clarifying questions。除此之外,模拟题就提供一个白板,让你自己书写你要怎样回答这道题目。至于模拟题的答案,SystemExpert 跟 AlgoExpert 一样提供了高质量的官方答案,包括一个长视频讲解,和对应的图文解释。

如果此前没有系统设计的面试经验,或者觉得自己没有系统学习过,花 $79 买一年的 SystemExpert 是值得的。如果你决定要买了,可以考虑用我的折扣码。点击以下链接打开 AlgoExpert 的网站,然后选择购买 SystemExpert,或是 AlgoExpert + SystemExpert 的套餐,记得在付费前在「promo code」一栏输入「catchen」,然后就可以享受九折。请记得一定要输入「catchen」这个折扣码,单纯使用链接打开是不会自动打折的。

https://chen.cat/algoexpert-referral

P.S. 如果你不知道 AlgoExpert 是否值得一起买的话,可以去看我之前的《AlgoExpert 测评》。