2023年10月22日星期日

2023 年邀请链接(referral links)

我在 2018 年和 2019 年夏天都分享里一批我觉得值得推荐的服务和产品。疫情开始之后我就忘记了这回事,好多年都没再分享过。(不过我们《牛油果烤面包》还是每年年底做一期《好物推荐》的。)现在想起来,就写一篇 2023 年的吧。

我今年推荐的服务和产品包括:

  1. Neon
  2. Interviewing.io
  3. One Medical

以下是它们的详细介绍。

Neon

Neon 是一个三藩市湾区的亚洲菜外卖服务。跟其他随时点随时送的外卖不一样,Neon 是需要预订的,饭店会提前做好交给 Neon,Neon 每天下午派送。派送时食物是冰着的,重新加热一下就行。这些都是有门店的饭店,不是中央厨房,出品也是在门店能点到的菜色。

他们有 Koi Palace(鲤鱼门)的焗葡挞,一份 8 只或 24 只,我买回来用空气炸锅三分钟加热一下就很好吃。饭后作为甜品吃一个,一份可以吃一星期。(没有空气炸锅的话,烤箱也可以但就是慢。)两磅一份的咖喱牛筋腩也不错,完全冰冻的,重新蒸热了就能吃。牛筋这种在家里要煮很久才能煮烂的食材就很适合买别人煮好的。

他们有 Shanghai Dumpling King(包饺店)的小笼包,一份 10 只或 30 只。我买了之后冰起来作为备用的主食,什么时候需要了就拿 10 个出来,蒸 10 分钟就能吃了。他们还有 Harborview Restaurant & Bar(凯悦汇)的贵妃黄毛鸡和明炉烧鸭,这两个我也经常点。除此之外,他们还有其他东南亚菜系,都是由三藩市不同的饭店做的。

住在湾区,有时候不想做饭也不想出去吃的话,就会叫外卖。但是等饿了再叫的话,外卖又不知道要等多久才来。如果能够提前计划一下这周吃是什么的话,订 Neon 是很可靠的,通常下午 2:00 到 4:00 送到。因为 Neon 的食物需要重新加热,所以是当作食材来卖的,没有消费税。因为司机一天下午把整个湾区都送了,所以也没有转门的送餐费用,消费就随意了。

如果你使用我的邀请链接的话:

  • 你得到的好处:$15 的 Neon credit。
  • 我得到的好处:$15 的 Neon credit。

邀请链接:https://chen.cat/neon-referral

Interviewing.io

这是一个针对特定大厂(Facebook、Microsoft、Google、Amazon、Apple)匿名模拟面试(mock interview)服务。匿名是它最大的特点,你和面试官之间只有语音和代码,没有视频。面试官都是来自大厂的面试官,他们会用公司的面试流程和标准来面试你,如果你对某一家大厂的面试方式一无所知的话可以通过模拟面试来了解。面试结束后,你可以问匿名的面试官要反馈,也可以问他更多关于他公司的面试信息。

这些匿名的面试官会评价你的面试,如果他们觉得你通过了面试就会在 Interviewing.io 的系统里提交相关信息。如果系统发现你能稳定通过某一家大厂的模拟面试,它就会把你推荐给那家大厂进行 on-site 面试。你能跳过 technical phone screen,因为你已经通过了的 Interviewing.io 匿名面试就当作是 technical phone screen 了。

跟真实但匿名的大厂面试官进行模拟面试是要花钱的,具体价格由面试类型(coding、system design、behavior 等等)决定。除此之外,Interviewing.io 还提供免费的 peer-to-peer 面试预约,但面试官不是后台认证的大厂面试官所以质量就很难说了。如果只是想要多找人互相模拟面试,这是一个不错的选择。

如果你使用我的邀请链接的话:

  • 你得到的好处:首次消费时 $100 的折扣。
  • 我得到的好处:一次免费的算法模拟面试(必须在你消费之后)。

邀请链接:https://chen.cat/iio-referral

One Medical

今年 2 月份被 Amazon 收购的 One Medical 是一个连锁的诊所服务。有一些互联网大厂提供免费或打折的 One Medical 订阅服务,但就算没有公司打折的话也值得考虑全额自费购买。

One Medical 在美国各大城市(都市圈)都有诊所。在手机上预约医生面对面的门诊很方便,通常能约到一个星期内的。预约医生(可能包括 Nurse Practitioner)视频门诊的话,通常能约到一个小时之内的。疫情期间我每次出行回来都会用 One Medical 来约一次核算,流感等疫苗有时候我也会选择预约 One Medical 的(虽然 Walgreens 和 CVS 通常也有)。

总的来说 One Medical 提供了便利,不再需要自己去使用难用的医疗保险网站搜索医生,只要医疗保险能覆盖到 One Medical,就能直接在上面搜索附近的地点然后选一个最快能约到的医生。对于我这种以前在 Facebook 时习惯了园区内就有医生和牙医的懒人来说,非常方便。

如果你使用我的邀请链接的话:

  • 你得到的好处:第一年年费省 $50。
  • 我得到的好处:没有。

邀请链接:https://chen.cat/one-medical-referral

实体商品

我推荐的实体商品都会放在我的 Amazon Storefront 上面,今年我觉得值得推荐的是 Insta360 Link 摄像头第二代的 AirPods Pro(USB-C 版本)

Insta360 Link 是 Insta360 把便携智能云台用电脑摄像头上的结果,它能够通过人脸识别找到我,然后自动跟随我,还能根据我离摄像头的距离来调整变焦。作为 4K 摄像头,它的视频质量是没问题的。更重要的是,我不需要在视频会议前刻意调整我的摄像头角度了,Insta360 Link 一启动就会找我的脸。

AirPods Pro 应该不需要介绍了,大家都看过 Apple 官方的宣传片,降噪效果确实非常好。值得一提的是,此前有一个 Lightning 版本的我不小心连盒子扔进洗衣机洗了之后,拿出来干了竟然还能用。(偶尔有点小问题,但能用。)

2023年3月30日星期四

熟练使用 Google 或 Facebook 内部工具毫无用处?

有一部分 Google 和 Facebook 员工总是在担心一件事情:公司内部使用的所有工具都不是来源的,离开了公司就不会再用到,花那么多年把这些工具用到熟手了,一旦离职就会变成毫无用处的沉没成本。这种忧虑显得非常围城:在大厂外面的人觉得自己使用的工具不够好,想要进大厂看看到底人家有什么黑科技;在大厂里面的人觉得自己只用闭源工具,担心因为自己不懂其它公司都在用的来源工具而失去竞争力,想要花时间学习开源工具但又没有机会。

担心这种事情并非毫无道理,但我觉得这不是一个真正值得解决的问题,而且不是一个解决后就一了百了的问题。如果此时此刻在大厂,还不如专心做好眼前的工作,等到真正换工作的时候再根据工作需要现学。真正重要的能力,不是你现在懂什么,而是需要在未知环境中摸索时你能够学得有多快。(学校里建立激励机制是错的。根据你此时此刻懂多少来决定给予多少正向或反向激励,一旦你把这内化了就会造成职业上长远的负面影响。)


为什么说「不懂外部开源工具」这个问题不可能被彻底解决?这本质上还是因为技术发展的速度太快,如果一门技术此时此刻用不上,你学了之后就会逐渐贬值。

很多人只看到了现在成功的独角兽在用什么技术,但现在已经成功了的独角兽都是 10 后那一代创业公司了,它们创业时赶上了 AWS 的浪潮,但那时候大家用的 AWS 跟今时今日 AWS 提供的服务根本不是同一回事。那时候大家还是用 EC2 这样赤裸裸的机器,运维还是工作的一大部分,大家尝试做运维自动化但成熟度跟今时今日比简直就是玩具。

随着这一批 10 后创业公司的成长,它们对 AWS 的用量越来越大,遇到的运维问题越来越复杂,然后才出现了现在常见的这一些解决方案:用 AWS 管理界面太手工了,所以用 Terraform 来统一管理需要用到的 AWS 资源。自己在 EC2 上安装和维护软件太麻烦,关键的是缺乏一致性,公司内部做一套统一的容器镜像吧,把所有常用的东西打包进去。很多这些解决方案都是为大规模 AWS 运维设计出来的。

然而如果你看一下 20 后新生代的创业公司在用什么,你会发现你学会前面的一切都没用。20 后创业公司一上来就用 Firebase。EC2 是什么?虚拟机是什么?容器是什么?统统不知道,也不需要知道,赶紧把东西做出来,获得用户和拿到融资最重要。Firebase 当然有它的弱点和限制,大多是 20 后创业公司在扩大规模时都会遇到 Firestore 无索引筛选慢的问题,然后要把数据迁移到 GCP 或干脆把服务迁移走。

现实情况就是这样子,如果你离开大厂加入一家 10 后创业成功的独角兽,你就必须接受过去 10 年大家在 AWS 上建立起来的复杂生态环境,但即使你学会了你依然摆脱不了原来的忧虑:这些技术仅适用于这一批公司。你跳回去大厂,这些技术就没用了。你跳到 20 后早期创业公司,这些技术也没用。等它们 10 年后成长为独角兽时,你需要为它们解决新一代技术带来的问题,而不是去纠结上一代技术已经把上一代的问题解决得有多好。


你的职业发展如何,受你控制且最重要的部分是你能够为别人创造多大的价值。(这也是学校激励机制从来没有帮助你内化的东西。)从懂什么技术出发思考如何优化职业发展,这本身就是错误的方向。你必须从如何创造价值出发进行思考,如果没有充足的信息进行思考那就先尽心观察收集数据。

每一家公司要解决的问题都不一样,具体的某一种技术可能为解决特定的某一个问题提供了所需的手段,但越是通用的技术越需要针对特定问题通过定制化来落地。我见过很多人把「这在我上一家公司非常成功地解决了这个问题」带到新公司,尝试重复一边解决同样的问题,最终发现没有两个问题是一样的。在新公司不接地气,过去成功过的解决方案在新公司不能落地,最终都会失败。

我观察到一些人的成功路线,是借助在上一家公司打开的眼界,在下一家公司结合实际地解决问题,然后迅速地成长。例如说,在大厂当个 L5 接手维护一个曾经非常有开创性的系统,保证它的服务质量同时在上面添加功能。没错,这开创性的工作是轮不到你做了,几年前做这件事情的人升了 L6,但这样的机会只有一次,你不是第一个把路从无到有地踩出来的人,你就没机会升 L6。但你可以把这个系统和它解决的问题搞明白,接着去一家尚未解决过这个问题的独角兽,帮助他们解决这个问题。

对你来说真正有价值的是你见过这件事情能做成的视野。一件探索性的事情知道它能做成,你就已经成功了一半。(有很多探索性的事情,最终是做不成的,至少是在你有生之年人类无法达成。)但你不能把大厂的方案直接抄一遍,你需要理解在这个相似的领域这家公司独有的问题是怎样的,然后定制一个能在这家公司落地的方案。在一家独角兽迅速成长的那几年里,很多问题都是由于规模迅速扩张而造成的,曾经帮助这家公司成功的那批人对这些问题一无所知,而你在大厂见过规模成功扩张后的方案,所以他们会寄望于你来帮助他们解决问题。因为这件事情在这家公司还没有发生过,这个问题也没有被解决过,你在这家公司做出来就算是开创性的了,于是你可以在这里升 L6。

等你升完 L6,环视四周,发现升 L7 的好机会也都被别人挖掘完了,接下来在这家公司升 L7 会变得越来越难。没关系,你需要做的是把前面这个过程再重复一遍,这家公司已经被人利用过的 L7 机会,总有下一家还在路上的公司还没有遇到过相关的问题,等着你去解决。闭源的大厂,尤其是 Google 和 Facebook 这两家,里面有很多黑科技是外面大家根本不知道能做得这么好的,知道能做得这么好就是你最大的优势。(说得直白点,小厂是「贫穷限制了想象力」,而你见识过拥有几乎无限资源的大厂的想象力能去到的地方。)


回到文章的主题上来,熟练使用内部工具本身没有什么特别的价值,但知道这样的工具能做出来(而别人不知道这样的工具竟然能做出来)就很有价值,深入理解这些工具是如何被设计出来的以及它们被设计出来时的历史背景也很有价值。

2023年3月26日星期日

从人工编辑到算法排序

为什么作为企业内部沟通工具,Slack 在公司还小的时候那么好用,但在公司变得越来越大之后 Slack 会变得如此低效?这个问题我思考有一段时间里,我觉得这是一个数据规模的问题,在规模还小的时候 Slack 是一个很好的解决方案,但一旦规模大到一定程度 Slack 就不再有效率。

如果要跟 Slack 做对比,在 Facebook 内部使用 Facebook Workplace 的效率就很高。Workplace 有它自己的问题,例如说导致员工不停地在刷 newsfeed,因为总是害怕自己错过了什么重要的信息,所以一有空停下来就要刷。除此之外,在 Facebook 内部使用 Workplace 的体验很好,重要的信息总是会在 newsfeed 上出现。因为 Facebook 知道你是谁、你跟哪些同事的交互比较多、他们又跟哪些内容交互比较多,所以 Workplace 的排序算法能够把对你重要的内容有限显示出来。

为什么 Slack 和 Facebook Workplace 存在这样的区别?我思考的结果是,Slack跟 Workplace 的区别本质上很像 Yahoo 作为一个门户网站跟 Google 的区别。前者依赖于人工编辑,而后者使用算法排序。在数据规模有限时,人工编辑能够应付得过来而且效果可以非常好,毕竟这是让人亲自审阅这些内容然后决定什么重要、什么不重要、如何归类等等。随着数据规模变得越来越大,人工编辑最终会应付不过来,这就是 Yahoo 作为门户网站最终会输给 Google 的原因,同时这也是 Slack 不好用的原因。


面对大量没经过整理的信息,我们有两个非常不一样的选择:

  1. 尝试控制这些信息的产生和流动。
  2. 放弃对信息产生和流动进行控制。

这两个不同的方向,导致了截然不同的产品设置。

门户网站和搜索引擎的区别能够很好地解释这两个方向的差异有多大。门户网站相信自己可以人工整理和索引世界上所有的网站,或者至少是重要的网站。因此如果你要找某个网站,在门户网站上你要么能找到这个网站(有索引)要么不能找到(没索引)。这就好比图书馆,你不知道是否存在一本某个题材的书,但你可以根据图书索引找到这个题材的书所在的书架,浏览完书架上所有的书你就知道你想要的这本书是否存在了。

搜索引擎做了一个本质上截然不同的假设。沿用图书馆的例子,因为数据规模如此之大,你就算根据图书索引找到了你想要的书所存在的书架,你也会发现符合这一分类的书架如此之多你根本浏览不过来。在一个小图书馆里,可能计算机科学只是一个书架。在人类知识的图书馆里,计算机科学的书架区域可能有好几平方公里大。使用搜索引擎的前提,就是你选择了主动放弃对信息的控制,你让图书馆管理员帮你挑 10 本跟你想要题材最相关的书,他选好后拿过来给你浏览,你从中挑一本你觉得最合适的拿去读。

使用 Google 进行搜索时,虽然 Google 会告诉你总共有多少条结果、分开多少页显示,但大多数人根本就不会在乎,因为前几条有你想要的信息就是有,没有的话再翻几页也不太可能有。这就是我所定义的放弃控制:选择相信算法把对你重要的信息放在前面,放弃排在后面的信息。无论你从哪一个点开始选择不再看排在后面的信息,你都可以相信你已经浏览了相关性高的信息,而你不看的信息的相关性肯定不如你已经看过的高。


Slack、邮件以及公司内部人工编辑的门户网站,其实都属于第一种选择,相信人能够控制信息。Slack 可以通过 channel 控制信息分类,可以通过加入和退出 channel 来控制你具体接收的信息。邮件无论使用 Gmail 还是 Outlook 接收,都可以设置复杂的规则对邮件进行控制,例如说什么邮件不看,什么邮件不那么频繁地看。公司的内部门户网站也一样,编辑往往站在公司的立场来思考公司想要让什么员工获取什么信息,然后编写文章并发布到对应的频道。

Facebook Workplace 属于第二种选择。使用 Workplace 意味着你放弃了手工(包括通过设置规则)判断什么信息重要、什么信息不重要,你选择相信 Facebook 的排序算法帮你把重要的信息排在前面,因此无论你刷 newsfeed 刷到哪里停下来你都可以相信你已经阅读了比较重要的信息,排在后面你不去阅读的信息一定没有前面的那么重要。正是因为 Workplace 的这种特性,在 Facebook 这种规模已经非常大的公司内部 Workplace 会显得很好用。

今时今日已经没有人使用门户网站了,大家都使用搜索引擎,这是因为全球公开的信息的规模已经非常之大。然而企业面对的情况不一样,每一家企业都是从小开始做大的,在它们还小的时候 Slack 就会显得非常好用。(我自己经营一家几个人的公司,一个 Facebook Messenger 的群聊就够了,甚至不需要分多个 channel。所有人知道公司内部所有正在进行的讨论,因为根本就没有多少讨论。)然而当企业做大之后,切换到 Workplace 就很难。因为信息架构的本质区别,Slack 里面的信息不可能导入到 Workplace 里面,这就使得 Slack 拥有巨大的粘性。

Workplace 有些很成功的跨国公司客户,例如说 Walmart 和 Starbucks。对于这种规模的公司来说,使用 Workplace 非常合适。但创业公司上了 Slack 的船后就很难下来了,这就导致了今时今日很多创业公司有一定规模后需要想办法应对 Slack 带来的各种负面影响。我当然希望能够直接从 Slack 切换到 Workplace,但实际上这对于任何一家这种规模的公司来说这都是一个痛苦的迁移。

2023年3月19日星期日

在 React Native WebView 中使用自定义字体

在 React Native 中使用自定义字体(自己提供 woff2 或其他格式的字体文件)很常见,官方文档也说得很清楚。在 WebView 中使用自定义字体也是有文档可以参考的。但在 React Native 里面使用 WebView 并且要在 React Native WebView 里面使用自定义字体,我搜索了一下没找到现成的文档,只好自己根据 iOS 和 Android 原生 WebView 的文档研究对应的 React Native 方法。

这里说的是在 React Native WebView 中嵌入构建时已经打包进去的本地自定义字体文件。如果使用网络上的自定义字体文件的话,标准的 CSS @font-face 就能解决,唯一需要注意的是网络上的自定义字体文件是否跨源(cross origin)。跨源在 WebView 里也不是解决不了的问题,可以通过改变页面的 baseUrl 把本地生成的 HTML 页面变成同源。也可以把字体部署到自己控制的服务器上,把 Access-Control-Allow-Origin header 设置好。

iOS

React Native WebView 在 iOS 上使用的是 WkWebView,React Native 中的组件 API 跟原生 WkWebView 的很相似。原生有一个这样的 API 用来加载一个 HTML 页面:

func loadHTMLString(
    _ string: String,
    baseURL: URL?
) -> WKNavigation?

原生应用可以通过 Bundle.main.bundleURL 来获得应用目录的绝对路径 URL,也就是以 file:// 开头的一个 URL。在 loadHTMLString 时把 baseURL 指向这个 URL 那打开页面的绝对路径也就是应用目录的绝对路径了。假设打包时已经把 custom-font.woff2 文件当作资源打包进去放在应用根目录了,那在 CSS 中就可以以相对路径的方式指向这个文件了:

@font-face {
  font-family: "Custom Font";
  src: url("custom-font.woff2") format("woff2");
}

在这里 custom-font.woff2 等同于 ./custom-font.woff2,也就是在应用根目录的同名文件。这在原生很容易解决的问题,在 React Native 中的主要障碍是缺乏一个 JavaScript 可以直接读取的 Bundle.main.bundleURL。为此我们要自己写一个简单调用 Bundle.main.bundleURLNative Module

// WebViewBaseUrl.m

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(WebViewBaseUrlModule, NSObject)
RCT_EXTERN_METHOD(getBaseUrl:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
+ (BOOL)requiresMainQueueSetup
{
  return YES;
}
@end
// WebViewBaseUrl.swift

import Foundation
@objc(WebViewBaseUrlModule)
class WebViewBaseUrlModule: NSObject {
  @objc
  func getBaseUrl(_ resolve: @escaping RCTPromiseResolveBlock,
                  rejecter reject: @escaping RCTPromiseRejectBlock) {
    resolve(Bundle.main.bundleURL.absoluteString)
  }
}

获取到应用路径后,把它用于 React Native WebView 的 baseUrl,本质上跟 iOS 原生的 baseURL 没什么区别,只不过前者是 string 后者是 NSURL

const baseUrl = await NativeModules.WebViewBaseURL.getBaseUrl();
return (
  <WebView
    source={{
      html,
      baseUrl,
    }}
  />
);

(考虑到 macOS 的相似性,这个方法估计在 macOS 上也有效,但我没有测试过。)

Android

Android 的应用根目录路径跟 iOS 不一样,此外 Android 给 WebView 提供了一个神奇的但仅限于 WebView 的应用根目录路径,那就是 file:///android_asset/。在 Android 的原生代码里面是不能使用 file:///android_asset/ 访问应用内的文件的,但在 WebView 里面却可以使用这个神奇的绝对路径。

有了这个神奇的路径后,Android 上需要做的事情就很简单了。我们不需要从原生代码获取应用路径,只需要使用准确的相对路径就可以了。假设 custom-font.woff2 文件正确地放置到了 assets/fonts/custom-font.woff2 目录,便宜打包后这个文件就可以在 WebView 里面通过 file:///android_asset/fonts/custom-font.woff2 访问。为了跟 iOS 使用相似的 CSS 相对路径,我们可以把 baseUrl 指向 file:///android_asset/fonts/(假设 WebView 不需要用到其他本地编译时打包好的资源的话)。

let baseUrl;
if (Platform.os === 'ios') {
  baseUrl = await NativeModules.WebViewBaseURL.getBaseUrl();
} else {
  baseUrl = 'file:///android_asset/fonts/';
}
return (
  <WebView
    source={{
      html,
      baseUrl,
    }}
  />
);

这样就可以同时覆盖 iOS 和 Android 的场景了。React Native WebView 其实还支持 Windows,但我不需要支持 Windows 所以也没去研究。

2023年3月6日星期一

工程师成长到最后最重要的是什么?

有一个问题我最近在 career coaching 时连续被不同的人问了几次,第一次被问到时我想到什么就说什么,但被连续问了几次之后我觉得我需要好好思考一下。这个问题问的是,「工程师成长到最后,最重要的是什么?」

刚刚进入互联网行业的新人,往往觉得自己懂得还不够多,别人比自己厉害、比自己资深,是因为别人比自己懂得更多。按照这个逻辑进行推导,正确的目标自然是让自己懂得越来越多。再往前推导,既然每一个人的时间是有限的,那必须优先弄懂那些重要的事情,因此有了上述这个问题。大家都不想走弯路,希望找到直达终点的直线。


我觉得这个问题的答案并不是清晰可知的,因为清晰可知的事情迟早会被大家优化到极点。能够通过面试进入大厂的人,都聪明和勤奋到一定程度。如果存在这样一条直线,大家都或多或少地都沿着这条直线全力往前跑,最终跑出来的结果会存在一定的差别但不会存在巨大的差别,尤其是不会存在那种走直线比走曲线所应该获得的巨大优势。

那真正能够产生差异的是什么?那必然是一些别人没办法直接告诉你的事情。这是可以通过反证法证明的。如果有人能够教会你如何能够获得别人不能获得的巨大优势,他会选择教你吗?为什么?大家很容易产生一种错觉,「比我厉害的人肯定懂得比我多,这跟在学校里一样,但是他们不愿意教我所以我不如他们厉害。他们联合起来保守秘密,阻止我们获得他们拥有的知识」。

按照这样的假设,比你厉害的人当中只要有一个人守不住秘密,这种知识早就传播开来了。而且教授这种知识肯定是能赚钱的,所以比你厉害的人其实都有动机通过教授这种知识来赚钱,他们不可能真的联合起来保守秘密。这就可以反证,不是别人拥有你没有的知识而且不愿意教你,现实更有可能是他们没办法教你,或者说教你的成本太高所以不知道花时间去教。


有一个概念叫做「隐性知识」,英文叫做「tacit knowledge」,指代的是那些难以言述的知识。隐性知识类似于通过深度机器学习训练出来的一个模型:它可以用,它大多数时候是正确的,少数时候会出错。你没办法通过人和人之间很容易就能沟通的若干条规则把它描述清楚,因为能描述清楚的话就不需要用到机器学习了,用规则系统就可以了。你没办法很好地预测它什么时候对什么时候错,你也不太能解释它错的时候为什么出错了。

面对这样的模型,你可以选择把它整个拷贝走。但如果你不能拷贝呢?(因为人类还没有进行人脑到人脑拷贝的技术,也不确定这样的技术是否真能被发明出来。)如果你能使用这个模型但不能拷贝这个模型,你可以用这个模型作为基准和反馈从零开始训练一个相似的模型。这也是现在已知的传播隐性知识的方法:找一个把某件「只能意会不能言传」的事情做得非常好的人,你在进行训练时请他提供反馈,最终你训练出来的结果不可能跟他完全一样,但你的目标也只是获得相似效果而已。至于能否训练出来,以及要训练多久才能达到你想要的效果,这都是要尝试过才知道的。


现实就是这样子的:有能力进入大厂的人,通过过书本(或其他媒体)学习显性知识的效率肯定不会差。瓶颈往往出现在显性知识能学的都学了,学更多也不能变得更厉害了,但又没有意识到需要甚么样的隐性知识,或者是不知道从哪里能够获得需要的隐性知识。

所以工程师成长到了一定的阶段以后,搞明白自己需要什么以及找到跟谁能获得有效的训练是最重要的。具体怎么做就不是通过写一篇文章就能说清楚的,否则这就不叫做隐性知识了。我能给的建议是:找你相信真心关注你成长的人,请他们花时间观察你工作,问他们觉得你的成长需要什么、谁能够帮助你训练你所需要的。

2022年9月25日星期日

帮助别人的正确姿势

大家晋升到一定级别后就会被要求带新人,怎样带新人才算是成功?绩效评价时是只看有还是没有带人,还是要看带人具体的效果?如果要看效果的话那如何衡量效果?这是我在 career coaching 的过程中时不时会遇到的问题,我觉得可以把我的框架写下来分享一下。

首先,带新人以及更广泛的 mentoring 和 coaching 肯定是可以根据结果来衡量做得好还是不好的,但刚刚开始上手这项工作时更应该看重的是效率而不是效果。这不是说完全不看结果,而是说在合理的难度上能及格地完成工作但不追求更好的效果。

这有点像程序员刚刚开始学习编程时写代码的目标:要能够通过编译,执行结果要符合预期,但不考虑执行性能,也不考虑代码是否优雅。首先要会写代码,接着要多写,写得越快就能在同样的时间里写得越多。练习多了以后,再考虑如何提升围绕着编程的其它指标。如果一开始写不出正确的代码,或者练习的数量不够,其它指标均无法优化。


在有机会带人之后,首先要保证别人确实能够从你这里得到帮助。简单地问一句「你觉得这对你有帮助吗?」就够了,绝大多数时候别人都会说「有帮助」。如果你发现对方迟疑一下才告诉你「有帮助」,你可以再追问一下「有哪些方面可以改进吗?」可能你分享了很多信息,但没有回答到点上;可能你提供了很多理论,但对方还是不知道接下来该做什么。多尝试直接或间接地获取反馈,做到对别人提供有效帮助并不难。

在确认别人能够获得帮助后,接着就需要提高效率。我们可以用一个数值来衡量效率:杠杆比例——如果你花 1 倍时间来帮助别人就能让别人省 n 倍时间的话,这个 n 是多少。效率最低时 n=1,这意味着对方需要获取帮助的事情你帮他做了,而且你做得还不比他快多少。(如果 n<1 你要认真考虑一下你是否应该带人。)带新人的话往往一开始就能做到 n=2 甚至 n=3,毕竟你比新人要更熟悉整个技术栈,就算你帮他把他的工作做了,你也应该比他亲自做要快不少。

我通常建议的目标是 n=8,也就是说如果一天工作 8 小时,那你花 1 个小时就能帮助别人省 1 天的时间。从 n=2 到 n=8 有一段距离,没有人可以瞬间做到 n=8,但要把这做为一个长远的目标,不停地想办法优化以提高 n 的数值。这时候有一种意识很重要:只帮对方必须要获得外界帮助的东西,他自己能够缓慢学习提高的东西不需要帮。

打一个比喻:想象一个倾斜的平面上有一个因为摩擦力而没有向低处滑动的物体。因为静摩擦比动摩擦要大很多,重力无法抵消静摩擦所以物体不会运动,但有可能重力比动摩擦要大,只要运动起来就可以加速。你需要做的就是提供一开始克服静摩擦的那个力。如果没有这个力,这个物体可以相对平面永久地静止,但一旦它运动起来了,无论初速度有多低都能逐渐加速。

这跟「授人以渔」是不冲突的。你教会一个人基本的捕鱼技巧之后你就可以让他自己通过训练来提高捕鱼的效率,他应该自己想要捕更多鱼,这样子他才能从饿肚子变成能吃饱,再到能够卖鱼赚钱。他开头的阶段体验可能不太好,自己捕的鱼自己都吃不饱,饿着肚子又要去捕鱼了。但你效率也很重要,你效率越高就可以越大规模地帮助其他还完全不会捕鱼的人,这些人因为完全不会捕鱼都快要饿死了。(前提是确实有很多人能从你的帮助获得价值,都等着从你那里获得帮助。)

为了实现这个目标,在帮助别人之后最好自己复盘一下,想想自己有哪里的效率做得不够高,如果再遇到类似情况的话怎样能够提高性价比。


效率上去之后,你就可以开始关注难题了。就好像你在能够熟练编程以后,你就会想要找难题来解决一样。难题之所以难,是因为你不能通过提供信息(包括知识、数据等)来解决问题,真正的障碍往往来自于你想要帮助的人的意识。可能在他价值观深处藏着一些他自己也不知道的东西,阻止了他达成他的目标。可能你能看出来他的目标在南面,但他的价值观会引导他向北走。

有时候你提供信息(一张地图)给他就行了,他能够从逻辑上分析出来:要么调整价值观,使得价值观能够允许自己往南走;要么放弃这个目标。有时候你会遇到很顽固的人,他觉得只要往北走足够远就能绕地球一圈抵达目标。你需要挖掘他此前怎样的人生经历塑造了他这样的价值观,然后才能确定你是否能做点什么。这些难题的共同点只存在于这个层面:你不可能用你的知识和逻辑去帮助他,你需要搞明白这个人是经历了什么才成为了今天这样子。


这篇文章首发于我的 Patreon,对同类文章感兴趣的话可以考虑在 Patreon 上支持我,付费订户可以提前至少一周阅读到我的最新文章。同时也欢迎大家通过邮件RSS/Atom 免费订阅我的博客。

2022年8月24日星期三

求助于别人的正确姿势

什么情况下应该求助于别人?求助于别人是否就是伸手党,就会被人鄙视?我在做 career coaching 的过程中发现这是个常见问题,决定拿出来专门写一篇文章。Facebook 的 Bootcamp 在这方面对新人做了很多意识方面的训练,非常值得参考。

在 Bootcamp,专门有一个区域是给 mentor 提供 office hour 的,目标类似于学校里的 office hour(课后问答),如果作为新人的 bootcamper 在工作过程中遇到了问题,可以去这个区域进行提问。新人当然会问:那我该什么时候去提问?标准答案是:如果你自己捣腾了一个小时还是毫无进展,你就该去提问了。

跟学校作业不太一样的是,Facebook 布置给 bootcamper 的任务并不是标准答案已知的练习题,而是实际项目中不紧急也不重要的任务,每一个任务都不一样,mentor 不会提前知道问题,也不一定总能找到正确答案。新人在 office hour 提出问题后,mentor 都会问「那你都尝试了哪些办法?」如果有人说不出来,那 mentor 都会说「你先回去自己捣腾一下,如果一个小时了都毫无进展再回来提问」。

在新人解释完自己尝试过的办法后,如果 mentor 知道答案,可能会直接告诉他答案,把相关文档的链接发给他;如果 mentor 也不知道答案,他会亲自动手,把新人写了一半的代码拿过来 debug,试着解决问题;如果 mentor 解决不了,但知道谁可能提供有效帮助,他会把新人介绍过去。

就这样简单地一个过程,它强调了几种在 Facebook 成功必要的意识:

  1. mentor 必须授人以渔,bootcamper 必须求学捕鱼,不可以伸手要鱼。之所以问你尝试过什么办法但不成功,是因为接下来 mentor 必须要告诉你或者示范给你看什么办法能成功。你不能说「我捕不到鱼,请给我一条鱼」,正确的提问方式是「我用这样的方式捕鱼,我试过了但什么鱼也捕不到,请教我正确的捕鱼方式」。
  2. 即使面对你完全不懂毫无经验的问题,动手开干是最好的学习方式。动手开干不一定是写代码,动手开干也可以是搜索和研究。这跟在学校课程遇到问题存在一个本质的区别:学校课程能遇到的问题,都有已知答案,已知答案都属于一个清晰明了的知识体系,教材总能站在一个对该领域无所不知的角度帮你讲清楚一切。实际工作上的问题,往往你只能获取到碎片化的相关信息,然后再加上你自己的捣腾,产出一个可用的结果。你必须拥抱「真相在一定程度上不可知」然后冲上去捣腾。
  3. 你能直接接触到的人不一定有你需要的信息,你需要学会找到正确的人来获取正确的信息。这也是跟学校成体系的知识和课程结构很不一样的。在学校,你可以假设教这一课程的人对课程知识范围无所不知,你去 office hour 提问肯定能得到答案。在工作上需要获取的信息,有可能需要经过多个节点才能获取到,这个人建议你问那个人,那个人建议你问另一个人。你虽然不确定要经过多少个节点才能获取到你需要的信息,但你最好有一套方法能够收敛你和目标的距离。

修炼好这几种意识,即使不在 Facebook 工作也能让你更好地在需要时求助别人。即使你做不好后面两点,你至少要把第一点做好。


我在 career coaching 时有时候会遇到客户这样的顾虑:我向比我资深这么多的人求助,会不会是很浪费他们的时间?面对这种自我怀疑,你必须调整心态,把自己放在一个能够双赢的角度来思考你们的处境。

首先,你要确定你想要求助的事情确实重要。如果是工作上遇到的问题,你要确定解决这类问题是符合公司利益的,站在公司的立场来看这类问题确实值得解决。这时候无论是你解决还是别人解决,这类问题都是要解决的,这奠定了双赢的基础。

接着,你求助的态度必须是「请教会我捕鱼。我也不想总是找你要鱼,所以教会我捕鱼是符合双方利益的双赢选择。」对于公司来说,这是个三赢的选择,公司解决了符合公司利益的问题,你学会了可以重复使用的技能,帮助你的人将来不需要反复地帮助你。

最后你当然要把这实践执行到底,不能在别人教你捕鱼时捕到一条鱼就走人。尽管这一条鱼满足你此时此刻的需求,但很可能你还没有扎实的学会捕鱼,下次又要劳烦别人。你表明了你想学,你就必须比教你的人更投入地学。


「求助于别人的正确姿势」应该有一个镜像话题「帮助别人的正确姿势」。这是新手 mentor 时常会遇到的问题:我觉得帮助我的 bootcamper 非常消耗时间,但我不帮他又不行,怎样把握这个度呢?我可以下次写一写这个话题。这个话题不仅仅对 mentor 有用,对 mentee 也有用,因为在知道 mentor 如何才能更高效地帮助你之后,你也能更高效地利用 mentor 的时间。

这篇文章首发于我的 Patreon,对同类文章感兴趣的话可以考虑在 Patreon 上支持我,付费订户可以提前至少一周阅读到我的最新文章。同时也欢迎大家通过邮件RSS/Atom 免费订阅我的博客。