Java语言学校的危险性(译文)

下面的文章是More Joel on Software一书的第8篇。
我以为翻译难度很大,整整两个工做日,天天8小时以上,才译出了5000字。除了Joel大量使用俚语,另外一个缘由是原文涉及"编程原理",好多东西我根本不懂。但愿懂的朋友帮我看看,译文有没有错误,包括我写的注解。
====================
JAVA语言学校的危险性
做者:Joel Spolsky
译者:阮一峰
原文: http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html
发表日期 2005年12月29日,星期四


现在的孩子变懒了。 多吃一点苦,又会怎么样呢? 我必定是变老了,才会这样喋喋不休地抱怨和感叹"现在的孩子"。为何他们再也不愿意、或者说再也不可以作艰苦的工做呢。 当我仍是孩子的时候,学习编程须要用到穿孔卡片(punched cards)。那时可没有任何相似"退格"键(Backspace key)这样的现代化功能,若是你出错了,就没有办法更正,只好扔掉出错的卡片,从头再来。 回想1991年,我开始面试程序员的时候。我通常会出一些编程题,容许用任何编程语言解题。在99%的状况下,面试者选择C语言。 现在,面试者通常会选择Java语言。 说到这里,不要误会个人意思。Java语言自己做为一种开发工具,并无什么错。 等一等,我要作个更正。我只是在本篇特定的文章中,不会提到Java语言做为一种开发工具,有什么很差的地方。事实上,它有许许多多很差的地方,不过这些只有另找时间来谈了。 我在这篇文章中,真正想要说的是,总的来看,Java不是一种很是难的编程语言,没法用来区分优秀程序员和普通程序员。它可能很适合用来完成工做,可是这个不是今天的主题。我甚至想说,Java语言不够难,实际上是它的特点,不能算缺点。可是无论怎样,它就是有这个问题。 若是我听上去像是妄下论断,那么我想说一点我本身的微不足道的经历。大学计算机系的课程里,传统上有两个知识点,许多人历来都没有真正搞懂过的,那就是指针(pointers)和递归(recursion)。 你进大学后,一开始总要上一门"数据结构"课(data structure), 而后会有线性链表(linked list)、哈希表(hash table),以及其余诸如此类的课程。这些课会大量使用"指针"。它们常常起到一种优胜劣汰的做用。由于这些课程很是难,那些学不会的人,就代表他们的能力不足以达到计算机科学学士学位的要求,只能选择放弃这个专业。这是一件好事,由于若是你连指针很以为很难,那么等学到后面,要你证实不动点定理(fixed point theory)的时候,你该怎么办呢? 有些孩子读高中的时候,就能用BASIC语言在Apple II型我的电脑上,写出漂亮的乒乓球游戏。等他们进了大学,都会去选修计算机科学101课程,那门课讲的就是数据结构。当他们接触到指针那些玩意之后,就一会儿彻底傻眼了,后面的事情你均可以想像,他们就去改学政治学,由于看上去法学院是一个更好的出路[1]。关于计算机系的淘汰率,我见过各式各样的数字,一般在40%到70%之间。校方通常会以为,学生拿不到学位很惋惜,我则视其为必要的筛选,淘汰那些没有兴趣编程或者没有能力编程的人。 对于许多计算机系的青年学生来讲,另外一门有难度的课程是有关函数式编程(functional programming)的课程,其中就包括递归程序设计(recursive programming)。MIT将这些课程的标准提得很高,还专门设立了一门必修课(课程代号6.001[2]),它的教材(Structure and Interpretation of Computer Programs,做者为Harold Abelson和Gerald Jay Sussman Abelson,MIT出版社1996年版)被几十所、甚至几百所著名高校的计算系机采用,充当事实上的计算机科学导论课程。(你能在网上找到这本教材的旧版本,应该读一下。) 这些课程可贵惊人。在第一堂课,你就要学完Scheme语言[3]的几乎全部内容,你还会遇到一个不动点函数(fixed-point function),它的自变量自己就是另外一个函数。我读的这门导论课,是宾夕法尼亚大学的CSE 121课程,真是读得苦不堪言。我注意到不少学生,也许是大部分的学生,都没法完成这门课。课程的内容实在太难了。我给教授写了一封长长的痛哭流涕的Email,控诉这门课不是给人学的。宾夕法尼亚大学里必定有人听到了个人呼声(或者听到了其余抱怨者的呼声),由于现在这门课讲授的计算机语言是Java。 我如今以为,他们还不如没有听见呢。 这就是争议所在。许多年来,像当年的我同样懒惰的计算机系本科生不停地抱怨,再加上计算机业界也在抱怨毕业生不够用,这一切终于形成了重大恶果。过去十年中,大量原本堪称完美的好学校,都百分之百转向了Java语言的怀抱。这真是好得没话说了,那些用"grep"命令[4]过滤简历的企业招聘主管,大概会很喜欢这样。最妙趣横生的是,Java语言中没有什么太难的地方,不会真的淘汰什么人,你搞不懂指针或者递归也不要紧。因此,计算系的淘汰率就下降了,学生人数上升了,经费预算变大了,可谓皆大欢喜。 学习Java语言的孩子是幸运的,由于当他们用到以指针为基础的哈希表时,他们永远也不会遇到古怪的"段错误"[5](segfault)。他们永远不会由于没法将数据塞进有限的内存空间,而急得发疯。他们也永远不用苦苦思索,为何在一个纯函数的程序中,一个变量的值一会保持不变,一会又变个不停!多么自相矛盾啊! 他们不须要怎么动脑筋,就能够在专业上获得4.0的绩点。 我是否是有点太苛刻了?就像电视里的"四个约克郡男人"[6](Four Yorkshiremen)那样,成了老古板?就在这里吹嘘我是多么刻苦,完成了全部那些高难度的课程? 我再告诉你一件事。1900年的时候,拉丁语和希腊语都是大学里的必修课,缘由不是由于它们有什么特别的做用,而是由于它们有点被当作是受太高等教育的人士的标志。在某种程度上,个人观点同拉丁语支持者的观点没有不一样(下面的四点理由都是如此):"(拉丁语)训练你的思惟,锻炼你的记忆。分析拉丁语的句法结构,是思考能力的最佳练习,是真正对智力的挑战,可以很好地培养逻辑能力。"以上出自Scott Barker之口(http://www.promotelatin.org/whylatin.htm)。可是,今天我找不到一所大学,还把拉丁语做为必修课。指针和递归不正像计算机科学中的拉丁语和希腊语吗? 说到这里,我坦率地认可,当今的软件代码中90%都不须要使用指针。事实上,若是在正式产品中使用指针,这将是十分危险的。好的,这一点没有异议。与此同时,函数式编程在实际开发中用到的也很少。这一点我也赞成。 可是,对于某些最激动人心的编程任务来讲,指针仍然是很是重要的。好比说,若是不用指针,你根本没办法开发Linux的内核。若是你不是真正地理解了指针,你连一行Linux的代码也看不懂,说实话,任何操做系统的代码你都看不懂。 若是你不懂函数式编程,你就没法创造出MapReduce[7],正是这种算法使得Google的可扩展性(scalable)达到如此巨大的规模。单词"Map"(映射)和"Reduce"(化简)分别来自Lisp语言和函数式编程。回想起来,在相似6.001这样的编程课程中,都有提到纯粹的函数式编程没有反作用,所以能够直接用于并行计算(parallelizable)。任何人只要还记得这些内容,那么MapRuduce对他来讲就是显而易见的。发明MapReduce的公司是Google,而不是微软,这个简单的事实说出了缘由,为何微软至今还在追赶,还在试图提供最基本的搜索服务,而Google已经转向了下一个阶段,开发世界上最大的并行式超级计算机----Skynet[8]的H次方的H次方的H次方的H次方的H次方的H次方。我以为,微软并无彻底明白,在这一波竞争中它落后多远。 除了上面那些直接就能想到的重要性,指针和递归的真正价值,在于那种你在学习它们的过程当中,所获得的思惟深度,以及你由于惧怕在这些课程中被淘汰,所产生的心理抗压能力,它们都是在建造大型系统的过程当中必不可少的。指针和递归要求必定水平的推理能力、抽象思考能力,以及最重要的,在若干个不一样的抽象层次上,同时审视同一个问题的能力。所以,是否真正理解指针和递归,与是不是一个优秀程序员直接相关。 若是计算机系的课程都与Java语言有关,那么对于那些在智力上没法应付复杂概念的学生,就没有东西能够真的淘汰他们。做为一个雇主,我发现那些100%Java教学的计算机系,已经培养出了至关一大批毕业生,这些学生只能勉强完成难度日益下降的课程做业,只会用Java语言编写简单的记帐程序,若是你让他们编写一个更难的东西,他们就一筹莫展了。他们的智力不足以成为程序员。这些学生永远也通不过MIT的6.001课程,或者耶鲁大学的CS 323课程。坦率地说,为何在一个雇主的心目中,MIT或者耶鲁大学计算机系的学位的分量,要重于杜克大学,这就是缘由之一。由于杜克大学最近已经所有转为用Java语言教学。宾夕法尼亚大学的状况也很相似,当初CSE 121课程中的Scheme语言和ML语言,几乎将我和个人同窗折磨至死,现在已经所有被Java语言替代。个人意思不是说,我不想雇佣来自杜克大学或者宾夕法尼亚大学的聪明学生,我真的愿意雇佣他们,只是对于我来讲,肯定他们是否真的聪明,现在变得难多了。之前,我可以分辨出谁是聪明学生,由于他们能够在一分钟内看懂一个递归算法,或者能够迅速在计算机上实现一个线性链表操做函数,所用的时间同黑板上写一遍差很少。可是对于Java语言学校的毕业生,看着他们面对上述问题苦苦思索、作不出来的样子,我分辨不出这究竟是由于学校里没教,仍是由于他们不具有编写优秀软件做品的素质。Paul Graham将这一类程序员称为"Blub程序员"[9](www.paulgraham.com/avg.html)。 Java语言学校没法淘汰那些永远也成不了优秀程序员的学生,这已是很糟糕的事情了。可是,学校能够无可厚非地辩解,这不是校方的错。整个软件行业,或者说至少是其中那些使用grep命令过滤简历的招聘经理,确实是在一直叫嚷,要求学校使用Java语言教学。 可是,即便如此,Java语言学校的教学也仍是失败的,由于学校没有成功训练好学生的头脑,没有使他们变得足够熟练、敏捷、灵活,可以作出高质量的软件设计(我不是指面向对象式的"设计",那种编程只不过是要求你花上无数个小时,重写你的代码,使它们可以知足面向对象编程的等级制继承式结构,或者说要求你思考到底对象之间是"has-a"从属关系,仍是"is-a"继承关系,这种"伪问题"将你搞得烦躁不安)。你须要的是那种可以在多个抽象层次上,同时思考问题的训练。这种思考能力正是设计出优秀软件架构所必需的。 你也许想知道,在教学中,面向对象编程(object-oriented programming,缩写OOP)是不是指针和递归的优质替代品,是否是也能起到淘汰做用。简单的回答是:"不"。我在这里不讨论OOP的优势,我只指出OOP不够难,没法淘汰平庸的程序员。大多数时候,OOP教学的主要内容就是记住一堆专有名词,好比"封装"(encapsulation)和"继承"(inheritance)",而后再作一堆多选题小测验,考你是否是明白"多态"(polymorphism)和"重载"(overloading)的区别。这同历史课上,要求你记住重要的日期和人名,难度差很少。OOP不构成对智力的太大挑战,吓不跑一年级新生。听说,若是你没学好OOP,你的程序依然能够运行,只是维护起来有点难。可是若是你没学好指针,你的程序就会输出一行段错误信息,并且你对什么地方出错了毫无想法,而后你只好停下来,深吸一口气,真正开始努力在两个不一样的抽象层次上,同时思考你的程序是如何运行的。 顺便说一句,我有充分理由在这里说,那些使用grep命令过滤简历的招聘经理真是荒谬好笑。我历来没有见过哪一个能用Scheme语言、Haskell语言和C语言中的指针编程的人,居然不能在二天里面学会Java语言,而且写出的Java程序,质量居然不能赛过那些有5年Java编程经验的人士。不过,人力资源部里那些平庸的懒汉,是没法期望他们听进去这些话的。 再说,计算机系承担的发扬光大计算机科学的使命该怎么办呢?计算机系毕竟不是职业学校啊!训练学生如何在这个行业里工做,不该该是计算机系的任务。这应该是社区高校和政府就业培训计划的任务,那些地方会教给你工做技能。计算机系给予学生的,理应是他们往后生活所须要的基础知识,而不是为学生第一周上班作准备。对不对? 还有,计算机科学是由证实(递归)、算法(递归)、语言(λ演算[10])、操做系统(指针)、编译器(λ演算)所组成的。因此,这就是说那些不教C语言、不教Scheme语言、只教Java语言的学校,实际上根本不是在教授计算机科学。虽然对于真实世界来讲,有些概念可能毫无用处,好比函数的科里化(function currying)[11],可是这些知识显然是进入计算机科学研究生院的前提。我不明白,计算机系课程设置委员会中的教授为何会赞成,将课程的难度降低到如此低的地步,以致于他们既没法培养出合格的程序员,甚至也没法培养出合格的可以获得哲学博士PhD学位[12]、进而可以申请教职、与他们竞争工做岗位的研究生。噢,且慢,我说错了。也许我明白缘由了。 实际上,若是你回顾和研究学术界在"Java大迁移"(Great Java Shift)中的争论,你会注意到,最大的议题是Java语言是否还不够简单,不适合做为一种教学语言。 个人老天啊,我内心说,他们还在设法让课程变得更简单。为何不用匙子,干脆把全部东西一勺勺都喂到学生嘴里呢?让咱们再请助教帮他们接管考试,这样一来就没有学生会改学"美国研究"[13](American studies)了。若是课程被精心设计,使得全部内容都比原有内容更容易,那么怎么可能指望任何人从这个地方学到任何东西呢?看上去彷佛有一个工做小组(Java task force)正在开展工做,创造出一个简化的Java的子集,以便在课堂上教学[14]。这些人的目标是生成一个简化的文档,当心地不让学生纤弱的思想,接触到任何EJB/J2EE的脏东西[15]。这样一来,学生的小脑壳就不会由于遇到有点难度的课程,而感到烦恼了,除非那门课里只要求作一些空前简单的计算机习题。 计算机系如此积极地下降课程难度,有一个理由能够获得最多的赞同,那就是节省出更多的时间,教授真正的属于计算机科学的概念。可是,前提是不能花费整整两节课,向学生讲解诸如Java语言中int和Integer有何区别[16]。好的,若是真是这样,课程6.001就是你的完美选择。你能够先讲Scheme语言,这种教学语言简单到聪明学生大约只用10分钟,就能所有学会。而后,你将这个学期剩下的时间,都用来说解不动点。 唉。 说了半天,我仍是在说要学1和0。 (你学到了1?真幸运啊!咱们那时全部人学到的都是0。) ================ 注解: [1] 在美国,法学院的入学者都必须具备本科学位。一般来讲,主修政治学的学生升入法学院的机会最大。 [2] 在麻省理工学院,计算机系的课程代码都是以6开头的,6.001代表这是计算机系的最基础课程。 [3] Scheme语言是LISP语言的一个变种,诞生于1975年的MIT,以其对函数式编程的支持而闻名。这种语言在商业领域的应用不多,可是在计算机教育领域内有着普遍影响。 [4] grep是Unix/Linux环境中用于搜索或者过滤内容的命令。这里指的是,某些招聘人员仅仅根据一些关键词来过滤简历,好比本文中的Java。 [5] 段错误(segfault)是segmentation fault的缩写,指的是软件中的一类特定的错误,一般发生在程序试图读取不容许读取的内存地址、或者以非法方式读取内存的时候。 [6] 《四个约克郡男人》(Four Yorkshiremen),是英国电视系列喜剧At Last the 1948 Show中的一部,与上个世纪70年代问世。内容是四个约克郡男人竞相吹嘘,各自的童年是多么困苦,因为内容太夸张,因此显得很是好笑。 [7] MapReduce是一种由Google引入使用的软件框架,用于支持计算机集群环境下,海量数据(PB级别)的并行计算。 [8] Skynet是美国系列电影《终结者》(Terminator)中一个控制一切、与人类为敌的超级计算机系统的名称,一般将其看做虚构的人工智能的表明。 [9] Blub程序员(Blub programmers)指的是那些企图用一种语言,解决全部问题的程序员。Blub是Paul Graham假设的一种高级编程语言。 [10] λ演算(lambda calculus)是一套用于研究函数定义、函数应用和递归的形式系统,在递归理论和函数式编程中有着普遍的应用。 [11] 函数的科里化(function currying)指的是一种多元函数的消元技巧,将其变为一系列只有一元的链式函数。它最先是由美国数学家哈斯格尔·科里(Haskell Curry)提出的,所以而得名。 [12] 在美国,全部基础理论的学科,一概授予的都是哲学博士学位(Doctor of Philosophy),计算机科学系亦是如此。 [13] 美国研究(American studies)是对美国社会的经济、历史、文化等各个方面进行研究的一门学科。这里指的是,计算机系学生不会由于课程太难被淘汰,因此就不用改学相对容易的"美国研究"。 [14] 参见http://www.sigcse.org/topics/javataskforce/java-task-force.pdf。 [15] J2EE是Java2平台企业版(Java 2 Platform,Enterprise Edition),指的是一整套企业级开发架构。EJB(Enterprise JavaBean)属于J2EE的一部分,是一个基于组件的企业级开发规范。它们一般被认为是Java中相对较难的部分。 [16] 在Java语言中,int是一种数据类型,表示整数,而Integer是一个适用于面向对象编程的类,表示整数对象。二者的涵义和性质都不同。 (完)
相关文章
相关标签/搜索