我讨厌计算机科学!
我就不对为什么你应该学习和练习所谓的“基础知识”进行长篇大论了。
我知道,反转链表与编写安全且 gas 高效的 智能合约 之间似乎没有任何联系。
在生产环境中,你可能从未需要实现过一个在 log(n) 时间内运行的算法。
即使你需要,你也只需导入一个库。而且你几乎肯定不需要调试编译器或向操作系统添加系统调用。为 UDP 数据包编写缓冲区?天哪,绝对不可能!
但无论如何,你都应该学习这些学科。
让我给你讲个故事。
学武术的孩子
记得小时候练习武术时,我总觉得自己在“被拖后腿”。
在空手道中,除非我们能以完美的技巧击打沙袋(并本能地格挡拳头),否则不允许进行实战对练。在柔术中,除非我们掌握了倒地缓冲和基本的摔投(擒抱技巧),否则不允许进行近身格斗。
有一半的练习时间是心肺功能和步法训练,这些似乎与和人打斗毫无关系。
这令人沮丧。我记得当教练终于允许我们揍同学的脑袋时,我感到如释重负。我不认为是因为暴力让它变得有吸引力,而是因为终于不用在所有人面前被分到初学者组了。公开进行被贴上“初学者”标签的练习,似乎本质上就令人反感。
回想起来,这种限制背后的智慧是显而易见的:如果你一上来就挥舞着双臂直接参加战斗,你的学习效率肯定不如直接进行基础训练。
如果实战对练能够利用现有的习惯,而不是从零开始培养技巧,那么它的效果要好得多。当另一个同学向你挥拳时,如果你还要去思考适当的技巧,会导致技能发展变得更慢。
实际的对练仅仅是基本功的总和:良好的步法、良好的击打、良好的格挡,以及不至于气喘吁吁。
钻研基础不仅是武术领域的专利。竞技国际象棋手和围棋手不会把所有时间都花在下棋上。相反,他们会研究包含特定场景的题集,这些题集旨在教授反复出现的模式,如中局、开局弃子、弃子战术等——即本文所谓的“基础知识”。
武术与计算机科学的艺术
软件工程也没什么不同。
人们总是面临着巨大的诱惑,想要直接跳入那些与你试图构建的最终应用程序只有一步之遥的技术。
机器学习?学 TensorFlow!区块链?学 Solidity!
(那些误导性地承诺工程师只要学习了这些技术就能获得更高薪水的教育工作者,正是这个问题的很大一部分原因)。
直接跳入 TensorFlow 或 Solidity 不会 让你成为一名高效的机器学习或区块链工程师。你将同时面对太多的底层技能。你会像那个挥舞着双臂、45 秒后就气喘吁吁的武术新生一样。你可能会偶尔击中一两次,但你将永远是一个受限的实践者。
首先掌握基础知识,并经常回顾它们。

涂蜡,擦蜡 —— 比特进,比特出
计算机科学中的每一个问题,无论属于哪个领域,都是一串比特输入,发生某些操作,然后一串比特输出。
每。一。个。问。题。
对这些比特的解释是特定于领域的,但它们都是比特序列的转换。
有一门科学专门用于推理这些比特串的转换。它叫做计算机科学。
让我来说明一下这种抽象是如何应用于开发中的一切的。
区块链的状态被建模为一串比特(每个人的余额和智能合约的状态)。你将该状态与另一串比特(一笔交易)结合起来,将两者放入一个转换中,并获得一个新的比特串:区块链的新状态。
机器学习也是同样的事情。数据 + 模型(都是比特串)产生一个新的比特串(训练好的模型)。在该领域中,我们在语义上将数据解释为“jpegs”,将模型解释为“网络文件”,并将转换解释为“训练”,但它们本质上仍然只是比特串和转换。
渲染网站是将 API 提供的 JSON 转换为网页上的 HTML 的过程。输入比特串,输出另一个比特串。这些抽象层次高于 JSON 和 HTML,但在底层,发生着相同的比特串转换。
为这些比特串赋予语义的有意义的方法数量已被详细记录,你可以对其进行严谨的研究。
无论在哪个领域,关于这些比特串转换能做什么和不能做什么,都有基本定理:
- 如果将比特串解释为计算机指令,它是否会导致无限循环?(这是不可判定的,即停机问题)。
- 如果将比特串解释为计算机指令,我们能否证明它与另一个比特串具有某种等价性?可以,但这通常是难以处理的。但如果我们将其建模为约束求解,我们可以高效地解决某些情况。
- 如果将比特串建模为传达信息,能否在没有任何信息丢失的情况下使其变得更小?你如何知道什么时候不能再让它变小?(这对于节省带宽很重要!)
- 如果比特串非常大,关于从相关子串中高效检索我们关心的信息片段,我们能得出什么结论?(数据库理论和分布式系统)
- 给定一个比特串和另一个比特串,输出另一个描述它们相似性的比特串。(搜索算法)
- 或者,如果一个比特串代表系统的状态呢?它是否会转换为不理想的配置?(黑客攻击和状态机)。
你明白了吗?
关于比特串操作的推理能让你擅长计算机科学中的任何专业。你实际上并不是在搬弄 1 和 0;你是在对 1 和 0 的解释之上应用强大的抽象。而这些抽象是历史上一些最杰出的思想家数十年研究的成果。你真的是在站在巨人的肩膀上。
这些抽象的分类构成了被称为“密码学”、“信息论”、“编译器”、“网络”、“虚拟机”等集群。你知道的,就是那些似乎不值得研究的学科,因为它们已经有了成熟的工具。
让我们回到武术的类比上。你可能会看到一些黑带选手展示了一场非常令人惊叹的对练,但在表象之下,它实际上只是步法、击打、格挡以及不喘粗气。同样的现象也支撑着编程“忍者”们所完成的惊人壮举。这仅仅是流畅执行的基础知识。
你在计算机科学中所做的一切,就是接收一串代表某种事物的比特,并将其转换为另一串代表其他事物的比特。(或者如果你是一名黑客,就是识别导致不良输出的输入)。
通过提高对建模和转换比特串的通用能力,你会更精通计算机科学,而不是通过编写你的第 10 个 NFT 铸造网站来实现。
你掌握的用于比特串转换的抽象和范式越多,你在计算机科学和开发的任何领域就会越有能力。
Leetcode 不公平吗?
这听起来可能像我在为科技公司进行 45 分钟的白板面试辩护。这样做确实有其价值,我捍卫的是这一原则,而不是典型的实施方式。
我们要求学生在参加 RareSkills 区块链训练营之前,必须通过一个简单到中等难度的数据结构和算法测试。不同的是,他们拥有比传统的 45 分钟更多的时间来完成它。
我坦然承认,让某人在 45 分钟内用干擦笔解决数据结构问题是相当残酷的。然而,完全无法解决这些问题的人并不是一名称职的程序员,也不应该被信任去创建持有数百万美元的智能合约。你会感到惊讶的。参加测试的申请者中有 30% 甚至无法解决哪怕一个问题(而 fizz buzz 的变体就是其中一个问题)。
我稍后会重新讨论这一点,但尽管数据结构和算法是计算机科学基础的重要方面,甚至可能是最重要的一部分,它们并非计算机科学中唯一有影响力的部分。
但是对于框架的职位要求呢?
雇主通常直觉上知道基础知识比应用更重要,即使大多数人并没有明确地说出来。
有人会指出,“但是 Jeffrey,大多数职位描述都说他们需要两年 React 经验、一年 Solidity 经验、Kubernetes 的生产环境经验等等。这显然才是我应该优化的方向!”
如果你还没有注意到的话,大多数职位描述都是相当异想天开的。
让我们算一笔简单的账。假设有 12 种真正重要的框架和语言。一个普通的开发者在 5 年的职业生涯中真正能掌握的只有其中 4 种。开发者恰好学了雇主想要的这 12 种里的那 4 种的概率是 1/495。
(即 4/12 * 3/11 * 2/10 * 1/9 或 C(12, 4))
软件职位的描述常常听起来就像是一个普通人想要和一位受过常春藤联盟教育、同时还是福布斯 30 位 30 岁以下精英的超级模特约会。祝你好运。你的机会是 0.2%。公平地说,许多软件工程师也有不切实际的期望。将软件工程师与工作进行匹配就像传统的约会一样混乱。不管怎样,我跑题了。
尽管人们匹配职位要求的概率很低,但最终还是能匹配成功。雇主为什么要雇佣不完美符合职位描述的人?(或者同样地,人们为什么要和没有满足所有条件的伴侣约会?抱歉,我又跑题了,但很有启发性)。
这是因为他们能看到这位开发者具有计算机科学领域的通用技能,并且能够将其适应公司需求。(回到约会的话题上,人们结为伴侣是因为他们看到对方具有成为好伴侣的底层特质,而不是因为他们拥有与好伴侣相关联的表面特征)。
我并不是说一家公司会为了高级前端的职位去聘请一个从未构建过前端应用的人。但我要说的是,在我们所划分的“前端、后端、智能合约、基础设施等”这些大类中,聪明的雇主更看重通用能力,而不是框架经验。
英语中的空白
这并不是说招聘广告在误导你;而是主导软件开发的英语和美国文化在简洁表达某种能力上存在空白……
“在一个领域内的通用能力,这种能力比单纯的聪明更具体,但又比死记硬背一堆事实更宽泛——这种人能‘get 到点’,这里的‘点’是指一系列重要的元技能,这些技能适用于本周需要解决的问题与下个月可能需要解决的问题之间的共同联系……而且当他们解决问题时,他们理解伴随该解决方案在该领域内产生的副作用,以及这些副作用如何可能泄漏到其他领域。”
哇,这话可真长。
(如果我非常有文化并且想炫耀一下,我会说出与之对应的{日语、法语、印地语或非英语的其他语言}单词,但可惜,我并没有那么有文化,即使我有,这种词在另一种语言中的存在也解决不了眼下的问题)。
我们还面临另一个困难:“foundations”(基础)、“first principles”(第一性原理)和“fundamentals”(基本功)等词往往带有“初学者材料”的意味。用线性代数的术语来说,我们没有一个词或俗语在指代知识空间的基向量时,而不暗示研究它的人是个菜鸟。(瞧,我没放过向你炫耀线性代数知识的机会吧)。
尽管存在术语上的空白,武术教练和技术招聘经理还是能直观地理解这个概念。但由于缺乏合适的语言来表达它,他们使用了像“有运动天赋的”、“有经验的”或“学得快的人”这样具有误导性的词汇。
好吧,我们确实有“expert”(专家)和“mastery”(精通)这样的词,但这些词已经被那些声称能通过教授你如何玩转当下被炒作的任何框架的小把戏,从而赋予你“专业知识”的教育工作者们给严重淡化和滥用了。
即使你已经使用了要求的框架五年,如果你所做的只是盲目地复制网上的教程,那对你毫无帮助。你的能力缺陷通常会在面试阶段被发现。所谓的“多年经验”是关键因素,也不过如此吧?雇主期望你理解这些框架是如何工作的,而不仅仅是如何调用它们的 API。
所有框架归根结底都是基础知识。它们获取你通过 API 提供的比特串,并返回另一个比特串作为状态更改或查询结果。它们正在我前面列出的基础领域中执行相同类型的基本数据转换。
想要精通这些框架吗?你知道我下一句要说什么了!
所以,研究基础知识,而不是研究框架。这样你才能成为能够快速学习任何框架的人——甚至自己创建框架。这才是雇主真正想要的,即使目前的语言无法让他们简明扼要地表达这种愿望。
常青与高杠杆知识
因为“基础知识”听起来像“初学者的东西”(也就是,你必须到角落里对着那个沙袋打上一百次,然后才能和腰带颜色比你深的人对练),所以我将某些计算机科学概念称为“常青”和“高杠杆”:“常青”是因为它不会过时,而“高杠杆”是因为它能加速相关知识的获取。
学习另一种语言,比方说 Rust,肯定会对你有所帮助。
但是学习编译器是如何工作的将帮助你更快地学习任何语言。
学习 CPU 架构和机器码是如何运作的将帮助你优化任何区块链上的任何智能合约。
请注意,反过来是不成立的。学习另一种语言并不能教你太多关于编译器的知识。但学习编译器会帮助你掌握编程语言。这就是为什么传统上称之为“基础性的”,尽管在本文语境中,我更喜欢称之为“高杠杆的”。
学习数据结构和算法是如何运作的将帮助你破译庞大的代码库,因为你可以按合理的块来阅读架构,而不是逐个变量地阅读。此外,经历了以多种方式建模和转换比特串的训练后,当你在“现实世界”中编码时,优秀的解决方案会更快地出现在你脑海中。最后,你还将理解框架为什么要以特定的方式对数据进行建模,这将帮助你更快地学习新框架并在竞争中保持领先。
“可是 Jeffrey!我要花一年的时间才能学会这些东西,到那时我肯定就跟不上区块链的时代了!”
这就是“常青”部分发挥作用的地方了!
猜怎么着?一年以后,无论你今天如何学习当前的材料,你在区块链领域都会显得过时。你永远都会是过时的。关键是通过让自己具备更快学习的能力,比你的竞争对手更好地驾驭那些即将过期失效的信息。
支配信息编码和转换的宇宙法则永远不会过时。
深度优先搜索已经有超过一个世纪的历史,至今仍然息息相关。基数排序(在许多应用中比快速排序还要快)也有一个世纪的历史。作为所有计算理论基础的图灵机是在 80 年前被概念化的。密码学所依赖的假设同样没有改变。归根结底,就是加密文本(再说一遍,即比特串)按照形式定义是否“显得随机”。
计算机科学仅仅是对比特序列的操纵。一直如此。支配它的规则是常青的。

保持与时俱进的秘密
保持与时俱进意味着快速领悟最新那些聪明人是如何重新组合现有知识的。
重大创新在底层是非常循序渐进的。只不过是重大创新增减了几个关键变量,却带来了极其不成比例的成果:
Bitcoin 仅仅是将数字签名与工作量证明结合了起来(在 Bitcoin 发明时,这两个都是已有数十年历史的概念)。Ethereum 采用了 Bitcoin 的执行核心并使其成为图灵完备的。Chat GPT 采用了自注意力机制的 Transformer(当时已有 4 年历史)并扩展了其规模,然后添加了一些硬编码的业务规则。
“创新”通常只是某个关键变量机缘巧合的增量,并带有一种不对称的结果(换句话说,就是一丝不苟地重新组合和改进某些东西,直到发生不同且/或良好的事情)。如果你能在新创新推出时,从根本上理解其中什么被增减了,你掌握新技术的速度将让你的同龄人感到困惑。
让你的求职申请脱颖而出
这里有个秘密。去做一些疯狂的事情,比如从零开始构建一个编译器,或者从数学原理入手实现一个重要的密码学算法。这类项目将比向他们展示你构建了一个猫咪分类器或第 100 个带有质押功能的 NFT 市场,更能吸引潜在雇主的注意。
前一个项目表明你知道如何照着教程做。而后一个项目则证明你可以迎难而上解决困难的课题,并且能够处理可能出现但未出现在职位描述中的无数问题。
信不信由你,Solidity 编译器中存在 bug。雇主更愿意聘请谁呢?是一个遇到问题就两手一摊的工程师,还是一个注意到问题、深入研究编译器源代码、在 GitHub 上提出 issue、并重新设计 Solidity 代码来规避该问题的工程师?第一个工程师可能在他们的 GitHub 上有十几个 DeFi 质押应用,但与那位能够打破砂锅问到底的工程师相比,那就显得黯然失色了。
现在我明白了:在早期阶段,很难看出递归反转二叉树与编写高效智能合约之间有什么联系。
这种感觉就像我当年学武术时一样:“当我们应该去踢别人脸的时候,为什么却在这里做开合跳?这联系似乎太遥远了!”
我可以告诉你,绝对的死磕基础知识,让我在接触这个概念后不到两年就能在一家大公司领导一个机器学习部门,并在全职做区块链后不到一年就在 Udemy 上开设了唯一的专家级 Solidity 课程。不管接下来还会出现什么炒作的领域,我学习它的速度都会比 98% 的工程师都要快。
为什么?因为每一项技术都是从相同的第一性原理自底向上构建出来的,只是组合方式不同而已。
你掌握的第一性原理越多,你在计算机科学的新子领域中学习的速度就越快,因为你不再是从零开始学习了。取而代之的是,你只是在组合你已经掌握的信息。
但是我们公司的 Staff Engineer 很牛,而且他不会做 Leetcode 题!
基础知识的范畴远比 Leetcode 宽泛得多。我并不是说因为你能在数组中移动两个指针,你就能迅速掌握软件开发的任何领域。学习数据结构和算法在达到某一点后会产生边际效用递减(尽管我认为大多数工程师还没达到那个拐点)。
Leetcode 不会考察你关于网络、语言理论、信息泄露、虚拟机、操作系统、编译器等方面的知识。
虽然超出了讨论范围,但在高层面上,软技能非常重要。我不想忽视这一点。但我们可以达成共识,在软技能大致相当的情况下,技术成熟度更高的工程师将会脱颖而出。
如果你大量接触了迫使你处理基础知识的问题,并且能快速识别出模式,你仍然能够建立对基础知识的直觉。然而,直接研究基础总会比碰运气学习来得更高效。你可能不会像你们的 Staff Engineer(主任工程师)那样幸运。
如何钻研基础知识 —— 不仅仅是 Leetcode
- 学习一门无用的函数式编程语言。这会迫使你以不同的方式来看待比特串。
- 用这门语言在 Leetcode 上做到中等难度(Medium)题目。
- 从零开始编写一个编译器。
- 从零开始创建一个简单的操作系统或虚拟机,或者修改现有的一个。
- 学习复杂性理论(提示:它不仅仅是 O(f(n)) 分析)。
- 学习密码学课程并切实地重新实现其中的算法。
- 如果你在做机器学习,去上一门正经的线性代数和统计学课程。
计算机科学中的一切都只是一串比特进入某个黑盒,然后作为另一串比特输出。你可以在复杂性理论中学到这一点。所有这些领域都只是对比特串应用抽象和有用解释的方式。你掌握的抽象越多,你就会成为一个越强大的开发者。
你应该先学习基础知识吗?
如果你对编程完全是个新手(既然你在阅读本文,很可能你并非新手,但我还是会加上这一节),我不认为首先学习基础知识是绝对必要的。我看到许多计算机专业本科生经历了和我当年作为年轻武术学员时一样的经历。在不明白为什么重要的情况下学习材料并不是最理想的。如果你有一位能激励你有信心掌握第一性原理的老师,那太棒了,但并非每个人都有这种奢侈。
我认为一个合理的学习旅程大致如下。这也是那些非常成功的自学工程师或 Web2 训练营毕业生的学习历程。
刚起步 → 教程地狱 → 在实践中学习 → 掌握基础知识。
一个成功的四年制计算机学位学生的学习历程可能是这样的:
掌握基础知识 → 在实践中学习 → 重新回顾基础知识。
如果你仍在努力构建功能性应用的基本操作中苦苦挣扎,那么推迟学习基础课题也是可以的。但不要仅仅满足于构建功能性的应用程序,因为如果你不掌握基础知识,你就会停滞不前。
是的,教程地狱是切实存在的,而解决它的办法就是毅然决然地投入去构建项目。
但是一旦你走出了教程地狱,下一步不是去开发更多的应用程序,而是去编写那些能培养通用计算机科学技能的代码。
如果你不会构建应用程序,你赚不到钱。但如果你没有基础知识,你就无法被聘请到一份理想的工作,更不用说获得理想的晋升了,除非你具备所需的核心骨干技能。
作为一名面试官
我并不是提倡每位雇主都应该进行 Leetcode 风格的测试,或者考查我前面概述的基础知识。如果你只是在构建相对简单的应用程序,那么仅测试工程师的这种能力也是合理的。然而,本文的目标读者是那些寻求职业发展的工程师(这正是 RareSkills 提供的)。职业的晋升绝不会来自于一遍又一遍地构建同一个应用程序的某种变体。
结论
我们在软件开发中所做的一切,说得好听一点,是对比特的解释和转换。数据转换是一项可以通过刻意训练直接发展的技能。你研究的计算机科学领域越多,你可以运用到当前问题中的“词汇量”就越大。最优秀的工程师会刻意去培养这些技能。普通的开发者则会直接去使用框架。框架会过时。而信息编码和操纵的基本定理不会。
你和那个比你多赚 100,000 美元的工程师之间的区别,不在于对某种语言或框架的知识了解。而在于对框架组成部分的知识了解。而这些组成部分直接依赖于计算机科学的基础。
走不寻常的路。
学习并练习那些看起来毫无用处的、令人生畏的学科。
从长远来看,这不仅仅是一条捷径。
这是唯一的途径。
RareSkills
感谢阅读本文。如你所见,我对开发者教育充满热情。这就是我创立 RareSkills 的原因。这是为了以正确的方式教授区块链开发代码。因此,请查看我们的区块链训练营。我们提供从面向完全没有 Web3 编程经验新手的课程,到面向专业 Solidity 开发者的各类课程。
我们一半的学生已经拥有作为智能合约开发者的工作,因此我们比任何典型的训练营都要进阶得多。并且因为我们非常强调基础知识,你所学到的内容甚至在区块链之外的领域也会息息相关。
原载于 2023 年 2 月 8 日