南大陈道蓄教授:学生从第一门程序设计课中究竟该学会什么?
网上见到有自称计算机专业毕业的学生问:“我不会编程,请各位指点我如何找工作。”看到这样的话,我不由得心生愧疚。我们毕竟是计算机专业的教师,那么我们到底教了学生什么呢?
我们到底是怎么让他们毕业的呢?这个问题也可以反过来思考:如果一个学生觉得自己“会编程”了,那么又意味着什么呢?“会编程”的标准很难描述,是会正确处理程序语句,还是要有几万行的代码编写经历?
说实在的,“会编程”的标准真的很难描述。我们是否可以将问题聚焦到针对教第一门程序设计课的老师:你认为能拿到你这门课学分的同学应该会什么?可能得到的回答是:“应该会用某种语言写程序。”这个回答并没有太大意义,因为程序用于实现某个问题的求解,如果不考虑问题,只说“会某种语言”,可能只是知道了语言成分的含义,知道了正确的语法形式。这还不是真正的“编程”。我没有调查过学完第一门程序设计课程的同学如何看待自己“是否会编程”,但我确实不止一次地听到教后继课程的教师抱怨学生“不会编程”。
在一本编程教材的篇首我见过这样一句话:“Programming isn’ t about what you know; it’ s about what you canfigure out.”(编程不关乎你知道什么,而关乎你你能弄出什么)。书中标明那句话是主演过“星际迷航”的著名演员Chris Pine 说的。我不知道他是在什么样的场合说的这句话,但我确实非常认同这句话。这里所谓“弄”出什么是指针对问题给出解。我们可以自然将这个意思延伸到程序设计课程:这个课无关乎知识点,而是要让学生解题。
可能有些老师会说:一年级同学还没学过数据结构和算法,我能要求学生解什么题呢?我也看到不少程序设计课的上法:把语言成分与结构当作知识点一个一个展开讲解,大半学期过去了,学生除了针对通用语言成分,“对号入座”式地编一点例子外,确实解不了什么“问题”。
但我们真没法让学生解一些“好玩”的问题吗?这里举一个简单例子。
对于计算机专业学生,不管其所在专业自认为是“学术型”还是“应用型”,都一定会学离散数学,知道命题演算公式是什么。我们可以利用离散数学知识,让学生通过建模与编程进行推理。
考虑如下的问题:Adam,Bob 和Charlie 三人分别获得比赛的前三名,没有并列。我们已经知道以下事实:
● 如果Charlie 是第二,Bob 就是第三;
● 如果Charlie 是第三,Bob 就是第一;
● 如果Bob 不是第二,Adam 一定是第三;
● 如果Adam 是第一,Charlie 一定是第三。
要求编个程序,以确定每个人的准确名次。
这个问题涉及的人很少,不用计算机也不难推出答案(恐怕也未必每个人都觉得很容易),但如果利用计算机,我们就可以用同样的思路解决规模更大、条件更复杂的同类问题。
“会编程”其实应该包括建立模型、设计算法、编写代码、正常运行。第一门程序设计课不可能涉及太多模型和算法,但并不意味着只能教给学生某种语言的语法。
解上述例子中的问题对于知道一点命题演算(真的只要一点)的同学应该不难:用a,b,c 表示3 个人,定义命题变元xi 为“真”当且仅当x 得到第i 名(总共9 个命题变元)。由此我们很容易将题目条件表示为命题演算公式,具体说可以表示为合取范式(就这个例子而言,每个子句长度均为2,而且9 个变元不会全出现),求解无非就找一个能够使公式满足的指派而已。
命题演算公式的可满足问题是著名的NPC 问题,但在一年级教学中完全不必解释CNF-SAT 问题及其算法。对于人数不多的算例,用穷举方法完全可解,这不需要什么背景知识,第一门程序设计课应该学会的东西足够了。翻翻图书市场上众多趣味数学、智力训练之类的图书,这样“好玩又可解”的例子比比皆是。
对于确实需要一点特殊数据结构背景的问题,其实也很容易解决。我们可以尽早引入“库”的概念,对诸如队列、堆栈甚至更多的结构,只要让学生理解其解题意义就可以要求它们直接调用相应的函数用于解题,至于实现结构完全可以到后面的课程中再说。老师甚至可以根据布置的任务需要自行编制可供学生调用的函数,如果能引导学生在学习过程中自己通过增量方式积累自己的“库”,那就达到一个“新的高度”了。总之,要学生学会编程,总得让学生实实在在地“做点什么有趣的事”。
遗憾的是,这样的问题在第一门程序设计课的作业中很少出现。如果我们能做到每堂课都要求学生有足够量且需要一定思考的题目作为日常作业(完全谈不上“大”作业),课程效果会好很多。如果第一门程序设计课真能使学生“入门”,后续课程也都能有意识地加强程序实现方面的要求,可能就不会出现计算机类专业毕业生不会编程的怪事了(当然考试也得当真一点)。
我经常听到教程序设计课的老师说自己的课“不是教语言,而是教计算思维”。这件事情有些费解,“思维”其实是很难“教”的,只能通过让学生通过训练自己“悟”。如果课程中并未要求学生解足够多“稍微像样点”的题目,那么程序设计课程就只能是教语言而已。
现在有很多专业把程序设计课分开为两门,一门“程序设计”和一门“程序设计实践”。这件事情更令人百思不得其解:那门名称中没有“实践”两个字的课是要教给学生一些什么呢?坦率地说,如果只是讲语言成分与语法规则,半天时间足够。既然光靠讲课,学生不可能学会编程,那我们开设这门课的意义是什么呢?
《计算机教育》希望我谈谈自己的观点,其实我有很大的顾虑。我不希望程序设计课教师(数量巨大)误解我的意思。我在自己的计算机问题求解课程中,没有一个学时用在讲语言上,尽管这个课程作为计算机专业第一门专业基础课,程序设计是其重要组成部分(我们用C/C++),但我其实认为程序设计课非常重要,只是我认为对于这门课,“讲课”一点都不重要。
编程是一件很有趣的事,因为它能给我们带来“问题解决了!”的快感。我认为第一门程序设计课最重要的目标就是让学生体会到这样的快感,喜欢上编程。让学生喜欢上编程是第一门程序设计课能否让学生“学会”编程的“钥匙”。要让学生喜欢编程,首先得让学生觉得老师自己真喜欢编程,继而让学生觉得编程其实不复杂,却能给我们随时想到的某个问题带来答案。
我的计算机问题求解课程是这样“教“程序设计的:指定一本大部头的教材,让学生自己阅读或者作为手册查阅。课堂的重点就是通过问题引导学生考虑程序背后的“抽象思维”,通过有趣的问题让学生觉得“编程”真的“很好玩”。与编程直接相关的课时很少,但一定布置足够多的课后作业(没有什么“大”作业的概念,也不要冠上“实践”这样的词;就是每堂课后必须完成的解题作业)。
第一门程序设计课的目标当然不是要求学生编写很复杂的程序,但也绝不能只是知道程序设计语言是什么。我的目标是让学生习惯于随时针对特定问题实现一个算法,并且不觉得这是个什么“作业”或者“任务”。许多问题并不需要学过特别的数据结构和算法才能解答。
在笔记本中安装各种编程工具,存储大量的问题(让学生觉得“随手”可以拿出一个适合的问题),上课时和学生一起解题,让学生相信:如果我突然想知道“250 ~ 500 有哪些质数”,我可以随时打开笔记本写几行程序拿到结果;如果我看到某个智力测验问题,我也愿意试试能不能通过建模编程解决。总之,如果学过第一门程序设计课以后,学生会随时拿出笔记本解决一个突然想到的问题,正如学数学时随手拿出草稿纸画画图、写写公式那样。如果能让大多数同学都有这样的收获,那么我认为,这门课真正为同学打下了很好的编程基础。
引文格式:陈道蓄. 学生从第一门程序设计课中究竟该学会什么?[J].计算机教育,2021(1):优先出版.
(完)更多精彩:
46位,中国大陆计算机科学2020年全球高被引科学家名单!!!
北大李晓明教授:从趣味数学到趣味算法到趣味编程——非专业学习者体会计算思维的一条途径?
哈尔滨工业大学战德臣教授:一种确保高校教学质量的新模式——同步异步混合式教学
【校长专访】加快推进计算机科学教育 做数据科学教育的探路人——华东师范大学副校长周傲英教授专访