软件随想录:程序员部落酋长Joel谈软件(local.joelonsoftware.com/wiki)-8

8 学校只教Java的危险性

Thursday, December 29, 2005

    懒惰的孩子。

    辛勤工作这回事是怎么了?

    一直发牢骚抱怨「现在的小孩」,怪他们不愿亦不能做较困难的事情,这显然表示我已逐渐老朽了。


    你们很幸福啦,以前我们在化粪池里一个牛皮纸袋里住了三个月,早晨六点就得起床把袋子清干净,吃一块过期面包皮就开始工作(work down the mill?),日复一日每天工作十四小时,回到家后父亲还会拿皮带把我们轰去睡觉。

--Monty Python的飞行马戏团, Four Yorkshiremen


    当我还是个孩子的时候,我使用打孔卡片来学习编程,假若你出错了,很抱歉,没什么时髦功能可以补救(比如按倒退键来修正),只能扔了这张卡片然后重新开始。

    我在1991年开始面试程式员时,通常会让他们自行选择语言来解决我所出的编程问题。99%的机会他们会选择C。

    现在,他们倾向于选择Java。

    不要误解我:以实现语言而言,Java并没有任何问题。

    等一下,我要修正一下。我并不是要在这篇文章中声称,Java就实现语言而言没有任何问题,事实上它不对的地方可多了,不过那得等我写另外一篇文章来谈了。

    我真正要说的是,整体来看Java这种语言不够困难,无法区分伟大的程式员跟平庸的程式员。在工作上或许是个好语言,但这不是今天的重点。我甚至会进一步说,Java不够难这件事是个特色而非缺陷,可是它毕竟还是有这个问题。

    这样说可能很傲慢,不过就我卑微的经验而言,指针跟递归是大学计算机科学传统课程中,许多人永远无法完全理解的两件事。

   大学课程通常由数据结构这门课开始,里面有链表(linked lists)和哈希表(hash tables)等等都广泛的使用了指针。这些课程常被用来作为淘汰课程:它们非常困难,会让那些无法面对CS(计算机科学,后面都简称CS)学位智力挑战的人选择放弃。这是件好事,如果你认为指针很难,等到要证明不动点定理(fixed point theory)的题目时才会真正地知道什么叫难。

   有些小孩高中就在自己的Apple II上,用BASIC写出很棒的乒乓游戏。当这些孩子上大学修CompSci 101(一门数据结构的课程),接触指针这玩意之后,轰!他们的大脑马上被炸成一堆豆腐渣,接下来都跑去修政治学,因为法学院似乎是个更好的主意。我看过CS科系退学率的各种数字,通常介于40%到70%。大学当局视之为浪费,我则认为这是必要的排除手段,让那些以后无法乐于编程职业或因此成功的人及早出局。

   对许多年轻的CS学生来说,另一个难题是教授functional programming(译注:请参考wiki)(包括递归编程在内)的课程。MIT对这些课程的要求很高,不但创造了必修课程(6.001),还编写出一本教科书(Abelson &2 Sussman的Structure and Interpretation of Computer Programs),被数十甚至数百所一流CS学校拿来作为CS入门教材。(你可以也应该在线上看看旧版的教材。)

   这些课程的困难度极高。第一讲就几乎教完Scheme所有的内容(译註:Scheme是一种古老的程式语言,常见于AI领域),还介绍了把另一个函式当成输入的固定点函式。在与这种课程(宾州大学的CSE121)奋斗之际,我注意到很多学生(可以说是大多数)都撑不过。教材实在是太艰涩了。我写了一封声泪俱下的长篇电邮给教授,控诉这门课实在是不人道!宾州大学一定有人听到了我(或其他抱怨者)的心声,因为这门课现在已经改用Java授课了。

   我真希望他们没有听到这个心声。


   你认为自己搞懂了吗?在这儿测测你自己


   这就是争议所在。像我这样多年来发牢骚责怪懒惰的CS大学生,再加上业界抱怨主修CS的美国大学毕业生不足,已经对整体环境造成了极大的伤害。过去十年间,大量原本很优秀的学校已经完全转向Java。这真是赞啊,用grep过滤简历的招聘人员应该挺高兴的;而且最棒的是,Java里没有什么很难的东西,不能真正淘汰掉那些没有指针跟递归脑细胞的程式员,所以退学率降低,于是CS系所收的学生更多,预算也水涨船高,一切是如此的美好。

   Java学校教出来的幸褔小孩不需要用指针实现哈希表,因此从未遭遇segmentation faults这种错误。他们从不需要战战兢兢、发疯似地试着把东西塞进有限的空间。他们也永远不需要动脑想想,为何在纯粹functional程式中,一个变数的值永不改变,但却又随时在变!一种自相矛盾的东西!

   他们不需要可以让他们在学位上获得4分的那部分脑细胞。

   我就是像Four Yorkshiremen那样的老古板吗?才会一直吹嘘自己以前多么坚韧,能安然渡过这么困难的课程吗?

   嗨!在1900年,拉丁文跟希腊语是大学必修的课程。并不是因为它们能做什么,而是它们多少被视为受过教育的人所必备的知识。在某些概念上,我的论点跟支持学拉丁文的人没甚么不同(以下四个理由都是):「(拉丁文)训练你的心智。训练你的记忆力。阐明一个拉丁文句子可锻炼思考能力,是一个真正智力上的考验,并且是逻辑思维的良好起点」Scott Barker如是。不过我现在已经找不到任何还要必修拉丁文的大学了。那么指针跟递归算是CS的拉丁与希腊语吗?

   现在我要坦率地承认,如今写的程式九成都不需要用到指针,而且事实上在产品程式上使用指针相当危险。是的,没关系。而functional programming在实务上几乎都没人在用,这我也同意。

   不过它在某些最刺激的编程作业上依然有其重要性。举例来说,不用指针根本无法在Linux核心做事。假若你并不是真的完全了解指针,就无法理解任何一行Linux(甚至是任何作业系统)的程式码。

   不了解function programming,就无法发明MapReduce这个让Google具备惊人的函式,因此可以轻易地平行化同步处理。在他们回想之际,MapReduce实是是显而易见的演算法。Google发明了MapReduce而微软没有,这个事实可以解释为何当微软仍在尝试让基本搜寻功能能运作时,Google已经进到下个领域:建立Skynet这个世界上最大的平行处理超级电脑,我不认为微软真正了解他们在这波竞争中落后了多少。

   但是在这些表像的重要性背后,指针和递归有其真正的价值。在学习它们的过程中,能获得建造大型系统所需的心智复杂度,以及免于被相关课程淘汰的特殊资质。必须具备某种能力,才能理解并以抽象的方式思考指针和递归,而最重要的就是同时从数个不同的抽象层次看待同一个问题。因此,了解指针跟递归的能力与成为伟大程式员的能力有着直接的关连。

   在一个纯Java的CS学位之中,没有东西能淘汰缺乏处理这些概念的灵活心智的学生。身为一个雇主,我看到纯Java学校已经开始量产出一些根本不够聪明的CS毕业生,尽管他们可以勉强通过那些新简化过的课程作业,却不足以进行任何比「又一个Java会计管理程式」更复杂的工作。这些学生永远无法通过麻省理工学院的6.001或耶鲁的CS 323课程,坦白说,这就是雇主心目中,麻省理工学院或耶鲁的CS学位比杜克大学的CS学位(已经完全转向Java)更有份量的原因之一。宾州大学也放弃Scheme和ML语言(译註:此两种语言常见于AI领域上),尝试用Jave来教授那门几乎整死我和我朋友的CSE121课程。并不是说我不会雇用来自杜克或宾州大学的聪明孩子,我会的。只是对我来说,要分辨谁够聪明要难上许多。过去我能分辨出聪明的孩子,因为他们能瞬间解通一个递归的演算法,而且用指针实现链表的速度和在白板上写一样快。但是当Java学校的毕业生卡在这些问题时,我无法分辨是因为他们受的教育不足,或是他们根本缺少进行庞大编程工程所需的天赋。Paul Graham管他们叫做Blub程式员

   Java学校不能淘汰这些永远无法成为伟大程序员的孩子,这已经是很糟糕的事,可是学校可以辨称这不是他们的问题,但业界(至少那些用grep筛选简历的招募人员是如此)却是确实地吵著学校必须教授Java课程。

   然而Java学校也无法训练孩子们的脑袋更熟练、聪颖、灵活,让他们能完成良好的软件设计(我不是指那种花费无数时间改写程式码来重调继承架构,或是为了has-a还是is-a之类的假性「问题」烦恼的OO「设计」)。你需要训练才能同时在多个抽象层次上思考事情,而在设计庞大的软件架构时正需要这种思考能力。

   你或许会想知道,面向对象编程(OOP)是否能取代指针跟递归,成为良好的淘汰工具。简单的答案是「否」。撇开OOP的功过不论,它就是没有难到足以淘汰平庸的程式员。学校教的OOP绝大多数都是在背诵一堆像「封装」、「继承」之类的词汇,再做些多型与多载(overload)间差异的单选题小测验。OOP并不比在历史课上背诵重要日期和名字难很多,而是用不适当的心智挑战吓跑一年级学生。据称当你面对OOP问题时,程式仍然能工作,只是有点难维护而已。但是当你与指针问题奋战时,程式只会产生一行Segmentatidon Fault,除非你停下来深呼吸,然后真正试着集中精神同时在两个不同抽象层次进行思考,否则永远不知道发生了甚么事。

   另外我有很好的理由嘲笑那些使用关键字过滤简历的面试者。我从未看过哪个会用Scheme、Haskell和C指针的人,不能在两天内熟悉Java并写出超越5年Java经验老手的程式码。不过跟一般人力资源部门的懒人解释似乎是徒劳无功的。

   但CS学院的CS任务该怎么办呢?他们并不是职业学校呀!训练人们到业界工作并不应该是他们的任务。他们会说这是由社区大学和针对转职工作者的政府再教育计划处理的。他们应该是提供基本工具让学生可以生活,而不是为他们第一周上班作准备。不是吗?

   Cs1.png

   打孔机 -- 没错,我12岁时在这种机器上学写Fortran.

   还有,CS关乎证明(递归)、演算法(递归)、语言(lambda 演算)(译註:lambda calculus,为一套数学理论,请参考wiki)、作业系统(指针)、编译器(lambda 演算),所以不教C和Scheme课程的Java学校其实也没有在教计算机科学。对于真实世界来说,函式curry化(译註:function currying是一个数学方法,请参考wiki)的概念或许对真实世界没什么用,但对CS研究所来说显然是必要资格。我不能理解为何CS学校课程委员会的教授,竟然会让他们的课程沉沦至此,不仅无法产生有用的程式员,甚至不能产生可能获得博士学位并与他们竞逐教职的CS研究生。噢,等等,或许我真的了解原因了。

   事实上当你回头研究学术界在Java狂热时代所进行的讨论,就会注意到最大的议题为Java是否简单到足以作为一种教学语言。

   我的天呀,他们正试着让课程更进一步的简化,我这样想著。为何不干脆把所有东西都用汤匙喂给学生算了?让我们再请助教帮他们写考卷,如此就不会有人落跑到美国研究去了(译註:American Studies,研究美国文化、社会等等的单位)。如果课程已被仔细地设计,让所有东西都变得比原本更容易,怎能祈求有任何人可以从这学到任何事情?看起来似乎有个工作小组会在进行某个任务(PDF文件),想要找出某个简化后的Java子集来教育学生,这个计划制作简化的文件,小心地隐藏所有EJB/J2EE废话不让学生稚嫩的心灵接触,因此不再需要让他们的小脑袋去担心任何连简单无比的CS问题集都不用做的课程。

   至于CS系所为何如此执著于简化课程,最好的解释是这样能空出更多时间来教授真正的CS观念,不过这得假设不需要花两堂课对学生说明JavaintInteger间的差异。嗯,假设真是如此,6.001课程可以给你一个完美的答案:Scheme,一个教学用语言,它是如此的简单,对聪明的学生来说十分鐘内就可以教会,然后你可以用剩下的整个学期去教固定点理论。

   哈!

   我要回到0与1的世界了。

   (你有1吗?你幸运的混蛋!我们拿到的全是0)


   你是个大三学生吗?而且能瞬间弄通一个递归演算法,或用指针实现链表的速度和在白板上写一样快吗?看看我们在纽约的[暑期实习]!到期日是二月一日。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值