3.3 初学者不能回避——《逆袭大学》连载

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxhelijian/article/details/86221726

返回到【全文目录

目录

3.3 初学者不能回避

不要绕过英语

用好调试工具 

写规范的程序,不仅是好看一点 


3.3 初学者不能回避

开始学编程,一大堆的问题扑面而来。人类的认知非常厉害,当问题多时,常能够避虚就实,优先将事情做下去。这也是学习中的一种非常宝贵的品质。在教学和咨询中,我却发现了一些本不该忽略的“虚”,却使得需要的进步“实”不起来。有些困难对大学生而言,只是表面的东西,它们只是一只纸老虎,只要突破心理上的畏惧和轻视,在编程进步过程中会走得更快和更好。

不要绕过英语

在日常的工作、学习中,我们用到很多的软件都是英文界面。在学习中,我们需要很多用英文写成的文档、资料。IT行业发展速度最快,对外开放的程度最高,与外界的交流最深入,学习英语,对计算机类专业的学生而言是当然的事。IT界最前沿的进展信息都是用英语公布的,很多的软件没有汉化版,绝大多数的优秀资料是不会翻译成中文的(由于IT技术发展非常快速,即使有译文,由于时间关系其时效性也不高了),中文译本往往并不能很好地表达出原文的意思的,对有声志于成为高级技术人才的学子,学好英语是必须的选择。

有些同学知道英语对于编程学习的重要性,却怀着所谓强烈的“民族自尊心”对英语心怀抵触。用中文软件,看中文书也就罢了,在实践过程中直接需要用到英语了,却主动绕道而行。最典型的一种表现,也是一种非常糟糕的做法是,调试程序中遇到错误编译或连接错误、警告,直接忽略给出的提示,甚至于错误发生在哪一行都不管,一头扎到源代码中瞪大眼睛,试图找到问题所在。在我的教学中,我的大一学生在调程序遇到编译错误时,总是直接忽略相关的提示信息,抱怨着为什么没有中文提示,直接用眼睛在程序中寻找问题所在。这在程序设计的学习中,是一种直接废了大半武功的做法!对于刚学程序设计的学生,盯着程序看再长的时间,哪有看一句“undeclared identifier”管用?当问及为何不看错误提示时,一句“看不懂”着实让人心痛,他们在说出这三个字时无奈眼神更让人心疼——这是学习了近十年英语的大学生!

有编程经验的人都知道,有的提示信息能直接告诉我们问题所在,有的不一定准确,但这是发现问题最重要的参考之一。可以根据提示发现出错的线索,然而却有众多的初学者在不断“碰运气”中完成实践,带来了更多的受挫感,哪里能够收获成就感?

于是,我在辅导上机时常和同学一起试着去读一读。个别的词没把握,在线词典中一查,立马解决。进而发现这句话原来很好懂,程序中犯的错误很低级。说“看不懂”的原因很简单,只是因为没有看。在错误提示刚一出现就暗示自己:我是看不懂英文提示的,对应的行为就是不看这些提示。再多问一句,“嘿嘿”之后,很自然地就是“英语不好”。

让考试束缚了的学习啊,何时才能释放出该有的力量!在选择、填空、完型、改错题中,封上了英语听说读写能力提高的道路。话说养兵千日,用兵一时,然而在学了十多年的英语之后,到真正要用英语了,却先给自己扣了个“英语不好”的大帽子,悄悄地溜了墙根。这是个舒适无比的温柔的理由,从此不必再犯难改变英语的学习,不必再看那些洋文。一方面选择从事了在全球化中站在最前沿的行业,另一方面却在拒绝通向世界的这张通行证。

学编程序中遇到了英语,这正是在用中学英语的大好时机!去上英语课,采用通用的教学材料进行的学习,是我们惯常的学习,而在编程中遇到了应用中的英语,是一箭双雕的学习。不回避标准化考试中受到的伤害,确实需要主动去挑战一下那个所谓的心理障碍,沉下心来去读一读遇到的用英语表达的错误提示了。不这样做,将永远处在慌乱之中,严重影响编程学习的进度,编程中应该有的好感受中也总缺着一块。沉浸在学英语就是做选择题的圈子里,不结合专业学习英语,不在用中去学英语,这就是一种自挖墙脚的做法,一副老态龙钟,死气沉沉的样子。可能有的同学还在指望着还有一门叫做专业英语的课程,那又何必呢?这门课程需要修读,但随时都在使用着英语,这是学英语的最好机会。其实,束缚住自己的,永远是自己。令人恐惧的,往往不是我们要面对的事物,而是自己的内心。内心封住了,英语学习就不敢往外走一步,不敢去执行“用中学”。

学生在编程中遇到的不认识的词,不少是专业术语。用词典查,常需要从诸多词义中选择一个,这往往并不是一件很容易的事。对于初学者,一些术语正在学习、理解当中,这个障碍自然不能忽略。不少技术类的中文书籍,在术语第一次出现的地方总是在括号中写出对应的英语词汇,然而同学们在看书时,括号里的英语单词是要直接忽略的。注意到这又是一个非常坏的习惯。上机实践中不看英语提示,看书时再忽略专业术语的英语描述,在学习中诸多有血肉联系的内容,就这样被生生地割裂开来了。

将编程的实践与英语学习结合起来,用好编程环境中给出的英语提示,这是在初学编程时必须要正视的一个方面。很多事情,亲自做了,不会有想象中的那样难。遇到不会的词,猜一下,或用在线词典,或在课本上查一下,明白了,再做下去。看懂英文提示的过程,也是一个学习提高的过程,少舍弃一个本该面对的环节,得到的是双倍的收获。

我想将这个话题往编程之外稍稍扩展一下。大学生在用英语中,要有更多一些信心,也要安排机会,让自己找到这种信心。学英语,一直是为着考试去的,而到用的时候却逃了,在英语学习中曾经的投入真就是完全浪费了,你也将成为传播“英语没有用”观点的最佳人选。凭着十来年学习英语的经历,无论高考得了多少分,任何一个同学完全有能力去读懂那些错误提示,只要去做,就能会。要让自己进步更快,选一段时间,沉下心来,读一读经典的英文原著,进步会更快。如果想让自己起步读英语著作时的感受更好一些,不妨找你已经不存在知识障碍的原著起步。比如,在用中文教材学了C++语言后,读一读C++之父Bjarne Stroustrup著的《C++ Programming Language》。初时可能需要一点点强制,但只要让自己完整地读到了100页,你会发现自己真的能读下去,再看不少译著真别扭。越是经典的书,其中的英语的表达越简单,越易读。我们所缺少的,只是起步去做。

不要用一句“看不懂”让自己避开,不要用一句“英语不好”封上自己通往更广阔空间的路。英语学习贵在积累,在编程中遇到错误提示,这是避不开的事情,编程的能力就是在不断纠错中锻炼出来的。如果将遭遇错误也看作是失败的话,这种从失败中的学习,永远是最有效率的。

用好调试工具 

在编写程序中,通过编译的程序,只是说明其中已经没有语法错误了。而在此时,我们将关注比语法错误更隐蔽、更危险的运行错误和逻辑错误。我们称程序中错误为bug,而检测并修正这些错误的方法就是debug。编程人员的日常工作,有大部分的时间花在debug上。在冗长的代码中,找出这些错误并不总是一件容易的事,但真正的程序员会把与bug战斗当成自己的神圣使命,用各种技术手段写出尽可能少bug的程序,也会用同样丰富的方法去debug,找出隐身的bug——那些产品中最凶险的敌人。

敏锐、机警、犀利的福尔摩斯能够用他那一双敏锐的眼睛加上两只灵敏的耳朵,觉察到别人忽略的东西,抓住一些细微的线索,利用精密的思想将一个个断掉的连环重新接起,推理出事情发生的起因经过。程序员在debug的过程中,做的也是同样的事情。这是一个能让人倍受鼓舞的事,却常让悲观主义者纠结:我哪有人家福尔摩斯的本事?上大学来,在程序设计的实践中,就是来获得这些本事的。不要将自己看成一个长成的葫芦,再不能塞进上苍馈赠的宝物。经历与bug的斗争,可以学得福尔摩斯的本领。

程序员靠什么发现bug出没的蛛丝马迹?除了大脑中的思维,观察是必需的环节。看英文的编译错误提示,是一种观察,用于对付语法错误常常奏效。对付运行错误和逻辑错误,需要观察程序的运行结果。运行结果不只是初学者做题目时常关注的最后运行结果,找bug要更关注程序运行过程里中间结果的可疑之处。

一种简单的方法就是在程序中,加入一些输出语句,输出值得怀疑的变量或表达式的值,再与自己的预期进行比较。例如,程序中执行了x=a/b,即将a除以b的运算结果赋值给x,但之后x参与的运算结果总是出错,这时就可以在x=a/b之前加入一条语句,输出a和b的值。为此,不同语言中需要加入不一样的语句,见表3–1。

表3–1 各种语言输出变量值的方法

语言

为了观察加入的输出a和b的值的语句

C

printf("a和b的值:%d,%d\n", a, b);

C++

cout<<"a和b的值:"<<a<<b<<endl;

Java

System.out.println("a和b的值:"+a+","+b);

在运行程序中,会看到输出的a和b的值。如果a和b的值是错误的,问题在之前;否则,安心在后面找bug。通过这样一种观察,不仅可以定位问题出现在什么位置上,而且会启发我们判断出究竟是什么错误。这是一种简便的方法,也几乎是万能的办法,很适合初学者。在实践中,当没有其他合适的工具供使用时,常常这样做。但是,这种方法也增加了写代码的工作量,调试结束后,可能还得费事删去各处不必要的输出语句。有些程序员舍不得去掉这些“功臣”,给不必要的输出加上注释,或者用条件编译等手段处理,却使本来清晰的源代码,看起来像乞丐的百衲衣。

神话故事中,神通广大的人物,手中都是有些宝贝的,孙悟空有金箍棒,九尾狐手中有捆仙索。程序员调试程序的宝物,就是调试程序——一种用于帮助程序员调试程序的程序。目前大多数的集成开发环境中,都提供了调试程序。

教会读者使用调试程序已经超出本书范围,但初窥这一宝物中的门道,还是有些必要的。读者在实践中正在用哪一个编程环境实践,找到合适的手册,或者找一个会用的人帮助带一下,用一个程序体验下来就能学会,这并不是一件太难的事。调试程序是一种非常实用的工具,一朝学会,终身受益;早学会,早受益;花少许时间磨刀,砍柴又多又省力。这其中的道理,并不难理解。

图3–2是在VC++6.0和CodeBlocks 10.05中调试C/C++程序时,通过菜单能够观察到的调试功能,以此为例概述调试(debug)过程中常用到的手段。

单步执行程序。读程序时,我们常按计算机的“思维”在人脑中“执行”程序。在调试程序时,常遇到的让人郁闷的情况是,明明知道程序应该执行这个分支,但感觉计算机偏偏走了另外一个分支;明明知道循环需要执行n多次,却1次也不进去。这时我们可以“单步执行”,让计算机不是按照它的脾气一股脑地执行下去,而是在你的控制下,一步一步地往下执行,走哪条分支,循环、函数如何进入,如何退出,一目了然。单步执行的具体功能包括:

  • Step Into:单步执行程序,遇到函数调用时,进入函数内部逐步执行(想着Into,进入到)。
  • Step Over:单步执行程序,遇到函数调用时,并不进入函数内部,而是将其调用当作一个整体执行(想着over,跨过去)。
  • Step Out:调试程序时,结束某个正在执行的函数,返回到调用它的上一级函数,常用于知道当前执行的函数中不存在错误时返回(想着out,出去了)。

再看图9–2中的菜单,找到单步执行对应的几个选项,再看选项前的图标,是否已经给出了非常清晰的提示?你可以找一个尽可能简单的程序,开始单步执行这个程序,这是一个经过体验就可以做下去的事情,而不是仅盯着资料去看就能明白的。看到菜单中每一个选项后面的快捷键了吗?选菜单是个麻烦的过程,日常的操作几乎都是通过快捷键高效完成的。这些功能还可以在窗口中找到工具栏,上面也有对应的图标,可以用鼠标去点击。

在一个醒目的箭头指示下,程序快活地在你的手中执行,一步,下一步,何去何从,一目了然。但,你是来找bug的,不是来看热闹的。在程序执行过程中,我们关心涉及到的数据是如何变化的。这是福尔摩斯断案中需要发现的信息,也是我们找到bug的依据。在单步执行过程中,为了找出问题所在,我们需要观察变量和表达式的值的变化,并和事先的预期进行对比。

观察变量和表达式值的变化。还是到图9–2的菜单上,我们分别看到了“QuickWatch...”和“Edit watches...”两个选项,点击之后,将你关心的变量的名字输入到后续的界面中去,在单步执行中,就会看到“观察窗口”中变量值的变化。哪一个变量的值在执行中发生了变化,在执行的过程中,都能一览无遗。这是一个很热闹的场景,展示的就是这个程序中的门道。观察窗口中不仅可以展示即时的值,而且还可以观察表达式的值,在单执行过程中,可以随时添加。要是福尔摩斯再世,他也一定会羡慕我们的宝物了,将观察窗口中展示的结果,和你头脑中的预期相对照,bug就此无处藏身。

利用断点。单步执行很给力,美中不足的是,要一步一步地执行,显得效率低下。明明已经知道这一段循环没有问题,但循环需要执行几百次,点几百次Step Over,这该让人如何面对?

调试程序中提供了“断点”(BreakPoint)的功能。断点是程序执行需要中断的地方,由程序员自己设置。程序在执行过程中,会自动在断点的位置停止下来,让程序员观察、分析。观察完一个可疑点之后,可以让程序自动执行到下一个断点再进行观察。成块地跟踪,理性地分析,这是一件很过瘾的事情。

现在需要了解的功能就是:如何设置断点(Toggle breakpoint或Insert breakpoint)、取消断点(Remove breakpoint),如何执行到下一个断点。你用的编程环境不同,方法会有些许差别,亲自试一试吧。

运行到光标处。设置断点需要费些心机,考虑好哪里可疑,逐个标记好断点,按部就班地进行处置。调试程序还提供了“运行到光标”(Run to cursor)的功能,光标在哪里,就运行到哪里,所需要的,是VC++ 6.0中的Ctrl+F10或者是CodeBlocks中的F4,或者是别的键的组合,配合观察窗口,好犀利。

工欲善其事,必先利其器。程序设计和软件工程中,为了方便工作,有无数帮助专业人员提高工作效率和质量,降低工作强度的工具软件。初学者中,不知道调试工具的人不少,似乎现有的教材并不热衷于介绍这些,而有些人知道却称“不习惯”而不用。如果不去用,是不会习惯的,也不会感受到其强大的功能,也不能享受找出bug带来的快意。

写规范的程序,不仅是好看一点 

大学毕业生进了企业,编码没有规矩。——IT行业资深开发人员

实际上,编码规范是一个老生常谈的问题,几乎在每家公司,都会采用一定的编码规范要求开发团队。例如C++程序设计中的规范,通过搜索引擎,很容易找到谷歌、中兴等中外公司的企业要求。有些人不喜欢编码规范,因为这意味着可能不得不改变自己的编程习惯,有些人还认为编码规范会破坏创造性和程序质量。在大学里,教学的要求相对产品开发的要求宽松得多,老师会讲到基本规范,但有些人拒不执行。无论怎么讲,按照编码规范要求,写出一手好程序,是一个应该从初学起就养成的好习惯。

编码规范是提高程序可读性、保证程序质量的重要指标。程序转换为目标代码后是要由计算机执行的,但其质量需要人去保证,前提是能够让人容易地读懂。有人不无夸张地说:“任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码的程序员,才是优秀的程序员。

编码规范,帮助我们写出人类容易理解的代码,例如标识符的命名,适当的注释,代码的缩进等,听起来简单,用上了价值非凡。不止一次,我在辅导学生上机时,学生面对莫名的问题折磨得就要崩溃了,用IDE中的“整理代码格式”的功能重新排版式,问题马上一目了然,就是花括号不匹配而已。现在学编程的同学是幸福的,因为流行的IDE,整理代码格式的功能已经成为标配。有人放着宝物不去用,偏要生活在垃圾堆一般的代码里。实际上,在IDE中录入代码时,会很自然地写出缩进有序的程序。只要习惯了,真的会觉得不规范的代码就是一堆垃圾。

编码规范还有助于知识传递,提高程序员和学习者的个人能力。规范的代码由于其良好的可读性,能让人更迅速,更容易地理解,即使是陌生的代码,也能达到快速理解的目标。无论程序员,还是正在学习编程的大学生,没有理由去抵制相关规则的存在,都应该养成良好的编码习惯。在很多时候,一些风格良好的代码在默默地影响着技术风格的形成。这也要求学习者能从代码本身能看出功能之外的很多东西。在此也想谴责部分教科书,应该是想省点纸张的原因,将代码在排版时挤做一团:一边在强调代码规范的重要性,一边就在身先垂范着不规范的丑陋,以至于影响了初学者的编码风格。

在实际的工作中,编码规范能够统一全局,促进团队协作,实际也能起到节约成本的目标。开发软件是一个团队活动,编码规范要求团队成员遵守统一的要求,包括在标识符命名上的统一、注释的方法,以及规范的开发流程,降低了出现缺陷的机会,减少了在维护阶段的工作量,成员之间可以轻松地阅读对方的代码,集中精力关注要完成的业务逻辑,这体现的都是效率和成本。

关于规范说了一堆,具体的规范还有待结合编程的实践去落实。初学编程需要关注规范,但在有些人看来,似乎是一个可以暂时忽略的话题。然而一放再放只能使问题延后暴露,无形当中,是坏习惯与好习惯之间的博弈,是高效率或低效率、高产出或低产出的斗争。对初学者而言,适当的注释、缩进排版、一句一行、规范的命名,这些是可以马上做好的事。

返回到【全文目录

猜你喜欢

转载自blog.csdn.net/sxhelijian/article/details/86221726
3.3