说明:在大学生普遍习惯应试模式的学习的背景下,我提倡大学生以实践开路,保证学习的效果,找到学习的方法,以此将理论和实践结合起来。也不断有学生咨询如何开展实践,实践要做什么。在拙作《逆袭大学——传给IT学子正能量》中,在这方面写了不少文字,现将其中的9.1节全文摘录在此文中,以供参考。
第9章 让专业学习更有效
9.1 一切让代码行数说话
程序设计是一门艺术,这门艺术只有通过实践才能掌握。检验计算机技术学习成果的标准是实践,我们对此寄予厚望。只有代码量达到足够多时,量变引起质变,才能够有机会见识到足够美丽的风景,水平才能真正提高。有业内人士描述:当你写过一百行代码的时候,对编程有了一个朦胧、感性的认识;当你编码的行数达到一千的时候,差不多掌握了编程的基本结构;当你写过一万行代码的时候,可以做自己喜欢的小玩意儿了;超过了十万行代码的时候,你会对自己编码能力充满自信。
开车也是一个实践性的工作。要评价一位司机的开车水平,拿出一个硬指标,那就是里程数。一千公里还算是新手,两万公里算出徒,要说自己是老司机,开完十万公里先。
学计算机的你要去求职了。面试官很忙,要用一个简单的指标代表你的水平,说出你在大学编过的代码行数。这是一个让人服气的指标,李开复的建议是,四年写完十万行代码。好司机,用里程数说话;好程序员,就用代码行数说话。
用指头敲出对编程的爱
有一位网络工程专业大一学生小A在给我的来信中谈道:
我在程序设计课程中每次课都很认真听,甚至期中考试的成绩是专业第一。不过因为期中考试更多的是选择题,编程只有一题,还是只需要自己填几空就能运行的。我现在觉得力不从心是因为我忽然发现,我只能看懂程序,却不能很容易地敲出属于自己思想的代码,甚至是不能敲出。有时候我觉得这是因为自己敲的代码太少了,基本上只有课堂上老师让练习的时候才练习。一个学长说重在思想,关键不是做的多不多的问题。我不知道自己究竟问题出在哪里,真的很困惑。
小A的困惑,其实是应试出来的“好学生”们共同面临的疑惑:跟着老师的学习远远不够,需要课后再拓展。要知道大学里,考试成绩高往往也说明不了什么。小A提到的期中考试只有一道编程题,并且“填几空”就能做出,这是老师的不妥。我知道我的一些同行们,在教学难以达到目标要求的情况下,他们不敢考学生,常用容易让学生得分的方式进行考试,以避免成绩单上的尴尬,也让学生不至于“有意见”。但这样的做法,根本上是误人子弟,又间接地鼓励了学生不去改变学习方式,其实也掩盖了他自己教学不力的事实。学生在不会编程的情况下,也能得到高分,这样的成绩让学生都觉得好笑。
考试方式的问题按下不表,单说小A只重视了看书、做作业的学习形式。他在学习中的问题实际上自己已经给出了答案,“敲的代码太少了,基本上只有课堂上老师让练习的时候才练习”。小A需要做的是,需要将实践充分重视起来,需要自己安排另外的练习,在编程体验中学会编程。别人喂不饱,就得自己去找食吃。关于编程实践的内容,可以从很多途径得到。
在学长的建议中,前半句“编程重在思想”说对了,“关键不是做的多不多的问题”也对,但是他是要讲给一位做编程题做不下去的学弟学妹,最多算对一半。我要对此更正:要建立编程思想,离不开足量的实践。大学的各门课程,尤其是各种专业基础课,目标都是针对着对计算机的理解、对编程的理解,是用于建立编程思想的,看来这位学长真也继承他的老师的衣钵,程序设计课的考试只考一道填空型编程题就够了。编程要在编程思想的指导下进行,但编程思想可以从日后的学习中得来一些,这是学校传授的套装知识中的一部分,但一定要有个人足够的体验,这是获得学习兴趣,将个人经验与套装知识中前人经验结合起来,形成自己的编程思想的过程
在编程思想建立起来之前,足量的实践必须坚决贯彻。程序设计的实践,就是让学到的知识,转换为可见的代码。在我的教学实践中,大一的学生,一年的C++代码行数平均可以达到一万行左右。到了这个平均数的同学,即使随后的学习进程会有小的停顿,但任何时候想要回归,都有资本再次上路。为了达到这个代码行数,跟我的学生要付出不少精力,课外有很多的时间得花在机房里,有时还为找不到机位而发愁。我曾经教过的学生和我讲,大一跟着我忙了一年,习惯了围绕课程积累代码行数,到大二后,同年级的不少同学觉得没有事干,而他们尽管不跟我了,但知道要做什么事,仍然在忙。每到这时,我都暗喜,这就是大学,忙就对了。
父母对孩子有着高尚和无私的爱。这种真爱是从“一把屎一把尿将孩子拉扯大”的过程中得来的。只有在不计代价的编程实践中,才能得到对编程的爱,才能够享受到学习编程的乐趣。对编程的爱,有人挂在口头,有人是自心头涌出,还有人,是用指头敲出来的。只挂在口头的爱,转眼可能就会见异思迁,有其他好玩的立马走人;发自内心的爱,必是有所体会,这种好感觉能伴人走得很远;而编程如过日子,其中有苦有乐,只有在踏实的工作中,才能见到平凡中的伟大。编程中,唯有用指头敲出来的爱,才是挚爱。
未来的程序员就是在代码行数的积累中成长的。然而新的问题是,为了代码行,要做些什么?有些同学,尽管心急如焚,却也等不来谁布置作业。要想到大学有帮助的自学了,其实,要做的题目和项目有的是,但需要自己用心去把握。
大学课程内要求的题目和项目
每上一门课程,老师备课、讲课、布置作业、检查作业,学生预习、听课、做作业、复习,这是一个固定的套路。作业中,是老师要求学生完成课外学习的内容,最常见的形式就是题目。在大学,每个专业都会安排一系列的实践环节,有各种实习、实训。根据专业不同,开展的形式各有差异,工科的还有课程设计,文理科的做学年论文,所有的本科生都要完成毕业设计或毕业论文。
培养方案内的设置可以算是周全的了,有不少同学按部就班地完成这些学习任务,获得了该有的能力提升,将理论与实践联系起来。无论是做作业中的题目,还是完成实践,我们可以看见大学中的众生相:有人轻松完成,有人知难而进,有人伺机搭车,有人坐享其成,有人知难欲进却无奈退却,有人置之不理,有人心生得意,有人暗生悔意,有的人是另外一种的洋洋得意。就在不同的学习进程中,众生在热闹的大学中各自找定了位置。我见过不少“能干”的同学想在分组的实践环节中与兄弟们并肩找到不孤单的感觉,最后却也在无奈中独自拉起大车,捎同学一程。我也见证了这些“负重”而行的学子,在走出校园时的轻松,在就业市场上的自如。如果有人和他们一起拉车,原本车的分量可以更沉一些,他们能得到的体验更多一些。培养方案的安排本是周全的,事情本来应该是什么样子,就应该如何去处理,这大概是我们共有的选择。明知走偏了,还要那样走下去,留下的只能是遗憾。
作为老师,我曾经是不愿意给学生布置作业的。课后做什么题都需要老师指定,这样的大学,没劲。但后来发现,不布置作业,给有些学生传递的信号就是没有作业,就是意味着课后不用学习。于是我开始布置作业。再后来,我不敢给学生多布置作业,当我控制不住抄袭的时候,何必要在这样一个群体内部制造虚假的繁荣呢?我想起自己在上大学的时候,大部分老师都不布置作业,但默认教材中的习题是要全做的,做完以后自己找资料核对答案,这也是不少同学的选择。
大学的课内要求,无论是理论学习,还是实践能力的培养,都只是一个基本要求。对于想真正学有所成的大学生,我更看重他们在课外可以从事的题目和项目,这注定了大学生活各具特色的精彩。
羽翼未丰的IT菜鸟身单力薄,写代码的课外习题成为首选。我在课外专业学习指导中,极力鼓动学生摆脱只靠着一本教材学习的习惯。看同类的教材或著作,与读书同步,完成其中的习题,这是课外题目的一个来源。课外的读物要瞄准经典的教科书,有位同学感叹道:“狠狠地读,认真地把书里的习题都给做了,对于打下扎实的基础有极大的帮助。”
有些同学选择了将看过的书中的例题自己做一遍的做法。这种模仿对于起步无门的初学者很合适。只不过,我不赞成照着书抄下来的做法,在“抄之有道”的建议中,我谈到可以采用先看懂,然后自己写出的做法。可能需要多次的重复,但如果绕开该有的重复采用所谓的捷径,效果并不能保证。
目前网络很普及,想多做一些编程题目的同学可以很容易地从网络上找到合适的题目做。最好的资源,莫过于各个学校建设的在线评判(Online Judge,OJ)平台了。本校没有OJ平台的,可以使用别的学校的OJ平台,略加搜索,会找到一大批这样的资源。本着ACM竞赛开放、共享的理念,只要去完成注册,有互联网在,各个学校的OJ平台上有做不完的题目在等待。刷题可以从“水题”开始,高手眼中的“水题”,可能恰是你正需要的宝贝。回头看,哪个高手不是从做水题开始的?找到一个可以归宿的OJ平台,也就找到了一个可以依赖的组织,大家一起营造在实践中进步的氛围。刷题,参加在线的周赛、月赛,与未谋面的学友们共同进步,这是一条成为高手的可行之路。
做编程题目多了,会对算法提出新的要求。在算法类知识的学习的阶段,也要有针对性地对某类数据结构和算法进行实践。教科书中的算法一般用伪代码描述,将之用某种具体的语言实现,建立自己的算法库,这是一类非常好的题目。在实现算法的过程中,会在抽象的层面上,得到更大的提高。
做题目最高的境界,是自己给自己写题目。有个段子,说某人考试只做60分的题,多1分不要,少1分不可能。传说中的这种人,是真正的高手。如果能够在学习中给自己拟出题目来,那是真正在学习中掌握了主动。在我的学生中就有这样的人。做完了7位评委打分的歌手大奖赛计分程序,他想到了评委人数不是7个怎么办?评委打分要求不是0~10分,而是百分制,又将如何?运行一次程序只计算一个歌手的成绩,要20名歌手不间断计分又如何处理?如果歌手人数不定时,怎么办?评委人数很多,要去掉两个最高分和两个最低分,又有事做了。输入各评委的打分得到正确的输出结果了,比赛结束最后还有要汇报平均成绩之类的任务,输出结果如何保存?比赛结束后要对于成绩进行复查,以防止在计算中有意无意的差错,对数据存储提出了新的要求。顺着这样的思维,任务还可以拓展。一个题目,或者在现实生活中遇到的一个问题,就可以一直拓展下去,俨然有点形成一个“项目”的趋势了。而在完成这些题目的过程中,各种技术都可以融合进来,学习中的激情何愁不来?“不知道这些东西学了有什么用”之类的问题,怎么会对这些善于自我探索的同学造成障碍?
做题目,能够针对具体的方法和技术,解决小型的,精心设计限定了范围的问题,从而获得学业上的提高。这是一种见树木,而不见森林的做法。这种做法是需要的,一口吃不成胖子,需要有这样的耐心。这样做的时间久了,有了更大的野心和更多的疑惑。
有学生在我的博客中留言问道:
老师,能给说一下链表、队列、树、哈希表等数据结构实际工作中的用途吗?怎么把理论和实际联系起来?
面对这个很泛很大的问题,我先“呵呵”一个,说一千道一万,不如指路一条,回复道:
看来你是已经学过了这些知识,面对这个到处都有答案的问题,我建议你现在可以接近实际工作自己去体会了。试着做点小项目如何?小游戏、通讯录、图书管理系统一类的题目就不错。
有了做题目的积累,实践能力得到提高,就应该到做项目的层次上去小试牛刀了。面对初学者,我们对项目不作严格的定义,那些规模稍大一些,需要的代码行数稍多一些,具有相对完整功能的系统都可以称为是项目。能用百十行代码搞定了题目,做千余行的项目,会面临新的问题和挑战,在积累代码行数的道路上也将会有新的体验。
做题目和做项目也并不是两个截然分开的阶段,没有一个标准规定题目做了多少才能做项目,时机合适就可以开启一段新的体验。例如,在大一,为学习C语言而做题目,与此同时,自学了一些Dreamweaver和HTML,可以考虑做一个班级主页,这可以算作是一个小项目了;而在大二初期,用C语言做课程设计的项目,同时开始学Java语言,又要做一些题目了。这种交叉的体验,将不断将你推向一个个新的高度。
项目从何而来?课程设计、大作业的内容可以视为一个练手的项目。自己做,不搭车,这是应该把握的一个底线。做不出来,说明学得不够,可以选择熬夜突击。要为此早做准备,平日的学习也就有了动力。套用做题目中的思路,从教材、参考书中可以获得练习项目的来源,从网上能找到别人拟好的项目需求,还可以自己提出创意自己开发。记得我在大三时,想用刚学的FoxBase+编一个小型数据库系统,完成母亲负责的农村信用站存取款业务。这样的开发永远不会有人采纳投入实际应用,但对一名大学生而言,还是一个可选的好项目。最终这个项目半途而废了,但我从中获得了不少的感悟。
课外自主学习的题目和项目
做编程题目中可以利用ACM竞赛与OJ平台,做项目也可以抓住参加一些专业性比赛的机会。我所在的山东省每年都有齐鲁软件设计大赛,吸引了不少学子参加,学院也给这项门槛不是很高的专业竞赛以场地、资金方面的大力支持,主要看重的就是同学们的参与经历。很多大学生选择利用暑假的时间,完成一件具有创意的作品参赛,收获了专业学习中的第一个项目,找到了专业学习的目标。由于有共同的目标,几个人能够团结在一起,共同攻克遇到的难题,这样的合作学习历程也令人难忘。现在类似的比赛机会非常多,只要在搜索引擎中输入“软件大赛”、“应用大赛”之类的关键词,你会发现政府部门、行业协会、著名企业组织的各种比赛。微软、阿里、腾讯、百度等企业更是常年不断地推出与前沿技术相关的应用大赛,参赛者借此增加阅历,提高水平,赢得资金及实习机会,甚至得到了进入大企业的入场券,这些都是额外可能的回报。企业在组织相关的比赛过程中,一方面意在增加自己的影响力,另一方面也希望能够从思维活跃的年轻人中间找到发展业务的好点子。这形成了参赛者与企业之间双赢局面的可能,我提倡参赛者能够自己提出独特的需求,并体现在作品中,这是另外一种能力,也是当代的技术人员应该具备的素质,需要在实践中形成。未来的工程师应该有能力自己提出需求和创意,想想苹果公司通过改变交互方式从而重新发明手机的成功案例,就知道创意的价值了。最前沿的工程教育方法CDIO中,也将构思(C)作为工程师必备的能力。而不少热衷于技术的同学只顾着要学习的技术,往往对创意却不太在意。大学生需要观察周围人们的生产、生活还需要点什么,有什么以后会更方便,更有趣,更有效。用一个好的创意,而不是现有擅长的技术,带动起课外的自主性学习,这是一个能站得更高的方式。
除了竞赛,可以围绕着各种开放开发平台找到机会。现在,很多IT企业和学术机构已经在云计算平台、社交网络、电子商务、微博、多媒体、安全等领域建立了不少开放资源,如新浪云平台、Google Developers等,用于支撑web应用、移动应用等领域的开发。当编程经验积累到一定时候,可以借此起步,开启一段新的探索之旅。
通过互联网,大学生还可以找到真正的做项目的机会。很多网站和社区提供项目交易的平台,比如隶属于CSDN的CSTO是一个中文软件外包和项目交易平台,目标是为企业和个人提供各类软件外包解决方案。在CSTO中,展示了数不清的项目需求,从几百元到几十万元的项目等待着开发者去竞标,内容涵盖移动应用开发、网站建设,应用软件开发及多媒体等各种项目。作为在校大学生,从简单、廉价的项目开始做起,积累技术开发经验,同时也了解了市场,在未来求职的简历上,放下一枚重量级的砝码。类似的项目交易平台很多,这不由得让人感慨,生在这个机会多多的时代的幸福。
在开源项目日渐深入人心的今天,参与开放源代码运动也是大学生积累项目经验的一个很好的途径。开放源代码对程序员来说意义非凡,从开源代码中,不仅可以学到多种编程方法,提高编程能力;还能获得好的思想,激发编程灵感。对于大学生而言也是这样。在学习开源的过程中,通过阅读、测试、修改bug等环节,将学得架构与模式,以及相关领域的结构与算法。参与开源项目之前可以通过阅读简短的程序积累一些经验,选定自己感兴趣的领域,从简单的项目入手。围绕开源,还有不少开源软件竞赛和针对大学生的暑期代码夏令营,可供大学生选择。
课外做项目面临的一个实际问题是缺乏指导。事实上,周围的老师,他们并不是所有人都不愿意帮助学生。学生主动一些,会发现身边的好老师。在我的身边,就有大学生通过前期主动的技术积累,而后,与老师取得联系,获得了参与老师科研工作和项目开发的机会。老师的项目需要人手,而大学生需要积累开发经验,这是一个双赢的局面。即使学生不能为老师直接提供什么,大多数老师还是愿意为追求进步的大学生提供资金、场地等有形的条件,以及指导、鼓励等无形的帮助。其实要获得指导的途径也不限于老师。高年级的学生、研究生都可以请教,现在社交网络很方便,找到已经毕业的师兄师姐,在论坛中找到某领域中的专家,这些全都是可行的途径。毕竟在课外学习中做项目,如同未来的独立工作,要立足于自主,找到合适的人,能够指点一二,其余的事情都需要自己去做。
无论是做题目,还是做项目,如果能够有一个小型的团队,相互鼓励和支持,共同克服学习中的困难,这都是难能可贵的事情。有大学生给我写信,讲起了他们的团队和在选择题目中的考虑。的确,人多了,事也就多了。
我现在已经大三了,我们班有几个基础差不多的同学,组建了一个团队,其中有学图像识别的,有学Java的,有学C的,还有学网络的。我们想在毕业前自己做做项目,这样对我们所学的知识做一个总结,也希望能在找工作时给我们提供帮助。我们刚组建起来,不知如何做项目。想请老师指导一下我们如何利用自己的长处,做什么样的项目好。
到大三了,组成团队做项目,非常好的做法。不过从他的描述中,“有学图像识别的,有学Java的,有学C的,还有学网络的”,我担心他们已经过早地给自己贴上了标签,这样会限制住他们的发展空间。我在回复中表示了这样的担心,并提示了他们另外一种设计项目的思路,这样前述的自编项目、参赛项目、开放平台中的项目、服务外包交易平台中的项目,统统可以纳入考虑范围。下面是我回复中的一部分:
网络可以算作是一个专业方向,图像识别是一个研究方向,Java和C,只是编程语言层面的一个基础,这只是你们各自已经具备的能力中的一部分,不是你们未来的全部,我建议你们的学习还要从深度和广度两个方向分别进行下去,千万不要让现有的一点专长,封住了通向其他的可能的途径。
形成小团队做点事情,他们想要利用好几位同学现在的优势去设计项目,这是“因人做项目”的思路。我建议了另外一个思路,要结合但也要先放下这些已有的基础,选定一个项目以后,再确定大家怎么分工,还需要补足各方面不具备的知识和技能。这是“因项目决定人如何参加”的思路。这符合工程中需求驱动的原则。在实践中,也几乎没有“因为会做什么就干点什么”的情况,而更多的是需要做什么,安排人去做,能发挥的优势最好,不懂的需要去自学,这也需要参与者在知识、能力上作必要的扩展。这种思路对学习阶段的学生而言,显然其价值更大。