JavaSchools 的危害

9 minute read

这是软件行业“思想家” Joel 的另一篇文章,该文章写于2005年,关于 JavaSchool(所有课程使用 Java 来教授的学校)给整个行业带来的危害,内容有些争议,但不妨一读。

以下是翻译正文。


懒惰的孩子。

勤奋工作到底怎么了?

我进入衰老期的一个确定迹象是对 “现在的孩子” 发牢骚和抱怨,以及他们如何不愿意或不能再做任何艰苦的事情。

当我还是个孩子时,我在打孔卡片上学习编程。如果你犯了一个错误,你没有任何像退格键这样的现代功能来纠正它。你只能扔掉卡片,重新开始。

当我在1991年开始面试程序员时,我通常会让他们使用任何他们想要的语言来解决我给他们的编码问题。99%的时候,他们选择C语言。

现如今,他们倾向于选择 Java。

不要误会我的意思:Java 作为一种实现语言并没有错。

等一下,我想修改一下这个说法。在这篇文章中,我并不是说 Java 作为一种实现语言有什么问题。它有很多问题,但这些问题要等另一篇文章来讨论。

相反,我想说的是,总的来说,Java 不是一种足够难的编程语言,以至于无法用来区分优秀的程序员和平庸的程序员。它可能是一种很好的工作语言,但这不是今天的主题。我甚至可以说,Java 不够难这一事实是一个特性,而不是一个错误,但它确实有这样一个问题。(注:Java 创建之初要解决的一个问题就是指针太容易出错了。)

恕我直言,根据我的经验,在大学里有两样东西是传统上作为计算机科学课程的一部分来教授的,但很多人从来没有真正完全理解过:指针和递归。

在大学里,你曾经开始学习数据结构课程,包括链表和哈希表之类的东西,并广泛使用指针。这些课程经常被用作筛选课程:它们非常难,以至于任何无法应对CS学位的心理挑战的人都会放弃,这是件好事,因为如果你认为指针很难,那你应该试着证明关于 fixed point 的理论。

所有那些在高中时用 BASIC 为他们的 Apple II 写乒乓游戏的孩子,到了大学,选修 CompSci 101,一门数据结构课程,当他们遇到指针时,他们的大脑就会完全爆炸,接下来你懂的,他们转而主修政治学,因为法学院似乎是一个更好的主意。我见过CS专业辍学率的各种数据,它们通常在40%到70%之间。大学倾向于认为这是一种浪费;但我认为这只是对那些不会在编程职业中获得快乐或成功的人的必要淘汰。(注:如果一个人无法从编程中获取快乐,那么转行是最好的选择)

对许多年轻的CS学生来说,另一门难学的课程是学习函数式编程,包括递归编程。麻省理工学院为这些课程设立了很高的标准,创建了一门必修课(6.001)和一本教科书(Abelson & Sussman的《计算机程序的结构和解释》),这些课程被几十甚至几百所顶级CS学校用作事实上的计算机科学介绍。(你可以,而且应该在网上观看旧版的讲座)。(注:即使对于工作多年的人说,把这门课的所有练习都做出来也很难,但是你会有非常多的收获,远远超过任何其他一门课程)

这些课程的难度是令人吃惊的。在第一节课上,你已经学会了几乎所有的 Scheme,而且你已经被介绍给一个以另一个函数为输入的定点函数。当我在宾夕法尼亚大学的 CSE121 课程中苦苦挣扎时,我看到许多甚至是大多数学生都没能成功。因为学习材料太难了。我给教授写了一封长长的泣诉邮件,说这是不公平的。宾夕法尼亚大学一定有人听了我的话(或其他抱怨者之一),因为那门课现在是用 Java 教的。

我希望他们当时没有听进去。

争论就在于此。像我这样懒惰的CS本科生多年来的抱怨,再加上工业界对美国大学CS专业毕业人数少的抱怨,已经造成了损失,在过去的十年中,大量本来很好的学校已经100%采用 Java。它很时髦,使用 “grep” 来评估简历的招聘人员似乎很喜欢它,而且,最重要的是,Java 没有难到可以真正淘汰那些大脑里无法处理指针或递归的程序员,所以辍学率较低,计算机科学系有更多的学生和更多的预算,皆大欢喜。(注:这里的grep指的是那些只看简历上有没有写 Java 的招聘者)

JavaSchool 的幸运孩子们在尝试实现基于指针的哈希表时,永远不会出现奇怪的 segfaults。他们永远不会因为要把东西打包成 bit 而变得疯狂。他们永远也不会去想,在一个纯粹的函数式程序中,一个变量的值永远不会改变,但它却一直在改变!这是一个悖论!

他们不需要那部分的大脑来获得专业4.0的成绩。

我是不是像“四个约克郡人”一样,只是那些老式的古惑仔之一,吹嘘我是多么坚韧的人,才能在那些艰难的事情中生存下来?

见鬼,在1900年,拉丁语和希腊语是大学的必修课,不是因为它们有什么作用,而是因为它们被认为是受教育者的一种明显要求。在某种意义上,我的论点与支持拉丁语的人(那四个人)的论点没有什么不同。”[拉丁语]可以训练你的思维。训练你的记忆力。解开一个拉丁文句子是一个很好的思维练习,一个真正的智力谜题,也是逻辑思维的一个很好的入门,”斯科特-巴克写道。但我现在找不到一所要求学习拉丁文的大学了。指针和递归是计算机科学的拉丁文和希腊文吗?

现如今,我坦率地承认,编写的90%的代码都不需要使用指针进行编程,事实上,在生产代码中使用指针是非常危险的。好的,没关系。而函数式编程在实践中应用得并不多。同意。

但对于一些最令人兴奋的编程工作来说,它仍然很重要。例如,如果没有指针,你将永远无法在 Linux 内核上工作。如果不真正了解指针,你就无法理解 Linux中的一行代码,或者说,任何操作系统都无法理解。

如果不了解函数式编程,你就无法发明 MapReduce,这种算法使谷歌具有如此大规模的可扩展性。Map 和 Reduce 这两个术语来自 Lisp 和函数式编程。回过头来看,对于任何一个记得6.001之类课程的人来说,MapReduce 是显而易见的,纯粹的函数式程序没有副作用,因此是可并行的。谷歌发明了 MapReduce,而微软没有,这一事实说明了为什么微软仍然在努力追赶,试图让基本的搜索功能发挥作用,而谷歌已经转向了下一个问题:建造世界上最大的大规模并行超级计算机 Skynet^H^H^H^H。我不认为微软完全了解他们在这一浪潮中落后多少。

但除了指针和递归的表面重要性之外,它们的真正价值在于,构建大系统需要你从学习它们中获得的那种心理灵活性,以及你需要避免被所教授的课程淘汰的心理才能。指针和递归需要一定的推理能力、抽象思维能力,最重要的是,需要同时在多个抽象级别上查看问题。因此,理解指针和递归的能力与成为一名优秀程序员的能力直接相关。

一个所有课程使用 Java 的CS学位并没有真正淘汰那些缺乏处理这些概念的思维敏捷性的学生。作为一名雇主,我看到100%的Java学校已经开始培养出相当多的CS毕业生,他们根本不够聪明,无法从事比 “另一个Java会计应用程序” 更复杂的程序员工作,尽管他们确实成功地完成了这门新的枯燥乏味的课程。这些学生永远无法在麻省理工学院(MIT)或耶鲁大学(Yale)获得6.001或CS 323学位。坦率地说,这就是为什么作为雇主,麻省理工或耶鲁大学的CS学位比杜克大学的CS更重要的原因之一。杜克大学最近采用了所有课程使用Java的方式,而宾夕法尼亚大学则在试图教授差点害死我和我的朋友CSE121的课程里用Java取代了Scheme和ML。并不是说我不想雇佣杜克大学和宾夕法尼亚大学的聪明孩子——我想——只是我很难弄清楚他们的能力。我过去能够分辨出聪明的孩子们,因为他们可以在几秒钟内完成递归算法,或者使用指针以在白板上书写的速度实现链表操作功能。但作为一名JavaSchool毕业生,我无法判断他们在这些问题上挣扎是因为他们受教育程度不够,还是因为他们实际上没有大脑中的那部分特殊能力,而这部分能力是他们完成优秀的编程工作所需要的。保罗-格雷厄姆称他们为Blub程序员

JavaSchool 未能剔除那些永远不会成为优秀程序员的孩子,这已经够糟糕的了,学校可以有理由说这不是他们的问题。工业界,或者至少是使用grep的招聘人员,肯定会吵着要教授Java。

但是,JavaSchool 也没能把孩子们的大脑训练得足够熟练、敏捷和灵活,以进行良好的软件设计(我指的不是面向对象”设计”,在那里你花了无数的时间重写你的代码来重新调整你的对象层次结构,或者你为假的”问题”(如has-a vs. is-a)感到烦恼。你需要训练自己同时在多个抽象层次上思考问题,而这种思考正是你设计优秀的软件架构所需要的。

你可能想知道,教授面向对象的编程(OOP)是否是一个很好的剔除指针和递归的替代品。快速回答:不是。在不争论 OOP 的优点的情况下,要淘汰平庸的程序员是不够难的。学校里的OOP主要包括背诵一堆词汇,如 “封装 “和 “继承”,以及参加关于多态性和重载之间区别的选择题测验。OOP 并不比在历史课上背诵著名的日期和名字难多少,它带来的心理挑战不足以吓跑一年级的学生。据称,当你努力解决一个OOP问题时,你的程序仍然可以运行,只是有点难以维护。但是,当你与指针斗争时,你的程序会产生Segmentation Fault,你不知道发生了什么,直到你停下来,深呼吸,并真正尝试迫使你的头脑同时在两个不同的抽象层次上工作。

顺便说一下,那些使用grep的招聘人员在这里被嘲笑,这是有原因的。我从来没有见过一个会做Scheme、Haskell和C语言指针的人不能在两天内学习使用 Java,并写出比有五年 Java 经验的人更好的 Java 代码,但是,试着向普通的 HR 机器人解释这些吧。

但是,CS部门的CS使命是什么呢?他们不是职业学校! CS部门的工作不应该是培训人们在工业界工作。他们会告诉你,那是为社区学院和政府为流离失所的工人提供的再培训项目。他们应该给学生提供生活的基本工具,而不是为他们的第一周工作做准备。对吗?

尽管如此。CS是证明(递归)、算法(递归)、语言(lambda calculus)、操作系统(指针)、编译器(lambda calculus)– 因此底线是,不教C语言和不教 Scheme 的 Java 学校也不是真正在教计算机科学。尽管 function currying 的概念在现实世界中可能是无用的,但它显然是CS研究生院的一个先决条件。我不明白为什么CS学校课程委员会的教授们允许他们的课程被愚弄到不仅不能培养出能胜任工作的程序员,甚至不能培养出可能获得博士学位和胜任工作的CS研究生。哦,等等。不要紧。也许我确实明白。

事实上,如果你回去研究一下 Java 大转变期间学术界发生的讨论,你会发现最大的担忧是 Java 是否简单到可以作为一种教学语言使用。

我的上帝,我想,他们正试图进一步降低课程的难度!为何不干脆用勺子把所有东西一点点喂给学生?让助教也为他们做测试,这样就不会有人从CS专业转到美国研究专业了。如果课程被精心设计成比现在更容易的东西,那么学生怎么能学到东西呢?目前,似乎有一个工作组正在(PDF)找出一个可以教给学生的简单的 Java 子集,制作简化的文档,小心翼翼地把所有的 EJB/J2EE 的垃圾从他们稚嫩的头脑中隐藏起来,这样他们不必担心自己的小脑袋,因为不需要做任何简单的CS问题集。

对于为什么CS部门如此热衷于简化他们的课程,最令人同情的解释是,他们需要有更多的时间来教授实际的CS概念,不然的话,他们需要花整整两节课的时间来让学生搞清Java intInteger 的区别。如果是这样的话,6.001为你提供了完美的答案。Scheme,一种非常简单的教学语言,整个语言可以在10分钟内教给聪明的学生;然后你可以把剩下的学期花在fixed points上。(注:这里作者用 fixed points 类比整个CS的概念)

哼。

我回到1和0里了。

(你有1?幸运的混蛋!我们有的只有0。)

(全文完)