养成好的编程习惯(转载)
版权申明
本文可以被自由转载,但是必须遵循如下版权约定:
1、保留本约定,并保留在文章的开头部分。
2、不能任意修改文章内容,或者删节,增加。如果认为本文内容有不当之处需要修改,请
与作者联系。
3、不能摘抄本文的内容,必须全文发表或者引用。
4、必须保留作者署名、注明文章出处。(本文授权给www.linuxaid.com.cn)
5、如不遵守本规定,则无权转载本文。
作者
ariesram
电子邮件地址
ariesram@linuxaid.com.cn, 或 ariesram@may10.ca
本文及本人所有文章均收集在bambi.may10.ca/~ariesram/articles/中。
本文授权给www.linuxaid.com.cn。
正文:
假设有一种编程的方法,能够克服所有的困难和改正所有的错误,而且能够避免重写代码,我相信我们都会使用这种方法。因为没有一种完美的编程方法, 我们能做的事情就只能是看我们周围的程序员是如何做的,哪些是正确的,哪些是错误的。有一些编程的方法是我从实际工作中总结而来的,也确实感到它们能够帮助我养成良好的编程习惯。其中最重要的一件事情就是记住,当你看到这些经验的时候,不要认为他们太简单和基础,觉得一种方法是不值得学习的。很多程序员认为检查错误和写程序注释是浪费时间。而我认为,这些经验能够帮助我们节省时间和精力。在实践过程中,我了解到,我能够更快的编写代码,代码也更加的有效率。
做最坏的打算
假设你是一个超级程序员,你的代码永远都不会有错误。但是,如果你的完美的代码没有得到完美的数据,事情将会如何?你的代码假设一个指针是合法的,或者它会把一个声音文件当作一个图片来处理?基本上来说,一段代码不能假设任何事情。C语言又一个标准的函数 assert, 它能够用来捕获错误。每次你的代码接收到用户数据,请注意要先确认数据是你所预想的。如果不是,使用assert并且打印消息来解释出现了什么错误。这是很重要的,这样你就能够让任何阅读你的程序的人了解到,什么是正确的数据,什么是错误的。百分之九十的错误都是一些简单的错误。所以,不要让这种错误影响你的程序浪费调试人员的时间,而只需要简单的在那些地方给出一个assert, 就能够避免。百分之九十的时候它能够容易的被改正。而另外百分之十的时候,它能够在变成一个大的错误之前被调试人员注意到并且改正。不论你采用哪种编程语言,你编写的第一个程序一般都是打印一条消息。把这个打印消息的功能作为你的程序中一个基本的函数,能够简单的打印任何错误。这样,程序就能分辨不明显的错误,你也能在任何错误可能出现的地方使用这个打印错误消息的函数。这样,就能够节省寻找错误的时间,从而让改正错误的时间减短。
注释
不要企图记住你的代码是用来做什么的。在你编写完一段程序几个月之后,你不会记得在编写程序的时候的想法,也不会记得什么代码是用来干什么的。所以,写注释是一个好的方法,特别是当你需要别人来阅读你的代码,或者是为了你半年之后还能记起来这段代码的目的。如果有一个同事告诉你,你的代码有一个错误,你将不得不重新检查并且改正它。如果你能够通过注释来回忆起什么代码用来做什么,你就能快一点找到并且改正错误。这个方法也是比较简单的,只需要注明你的那一段代码是做什么的,这就够了。而如果你不这么做,其他的阅读你的程序的人将看不懂它的意思,不知道变量是用来做什么的,哪些复杂的计算又是用来做什么的。如果你说明了它们的意义,就简单多了。比如,看这样的代码if "(frmp>10)", "(plist[i].bdown & x03)", "(plist[i].y > pond.y)"就比看注释要复杂的多。当你写注释的时候,你会得到两种好处。任何人都能明白你希望一段代码去做什么,而且,如果这段代码有错误,阅读代码的人就能发现,它没有执行你在注释中希望它去做的事情,那样就能尽快的发现错误和改正它。注释是程序员最重要的工具之一。而且所有的语言都支持注释。所以,记住,要写注释。
文档
当我在写一个文档的时候,我记得我花了很多篇幅来写一段关于系统和模块的文档。这个文档是正确的,但是却是没有用的。因为,没有人读过它。很多人都忘记了还有这篇文档,而是在需要的时候来问我,让我来解释给他们。这种方法也不错,它比查阅整个文档快多了。很少有机会有人会花上一大段时间来通读整个文档。所以说,我当时写文档的时间是浪费了。而且,如果这个系统和模块要做什么改动的话,我还必须相应的修改文档。也就是说,这文档让我的劳动加倍了。但是,这并不是说文档是不重要的。相反,如果用源代码和说明来记录文档,就简单多了。在每一个函数的开头,都用一段注释来解释函数的功能,如何使用,需要注意的问题等等。如果是一段比较复杂的代码,需要解释你所采用的方法。没有必要采用另外一个文件来记录文档,而只用在源代码中间来写文档。这样你就能够在你需要文档的时候随时找到它们。其他的程序员也会很方便的使用你的代码。而且,不象一个专门的独立的文档那样,其他的程序员将会无意识的阅读你的文档,而不会置之不理。如果有人来问你关于某一段代码的意思的时候,你就会明白,那一段代码缺少明白的注释。所以,你可以尽快的补上它,而不会有另外一个程序员来问你同样的问题。
采用工具
在编程的工作中,你也许会常常遇到这样一些繁重的体力劳动,比如,编译一个程序,然后就是等待。或者你使用了别人写的API函数,而记住这些函数的名称和参数是一个很累的活儿。这些工作并没有什么技术可言,比如说编译程序,每天晚上都会有人把新增加的程序放到库里,然后第二天上班以后你需要来重新编译它们,往往都是一些重复的工作,但是由于程序很大,编译的过程很漫长,而你就要陷入等待状态。那么,为什么不采用工具呢?或者写一些这样的工具?我就这样做过。我写过一个程序,让它每天早上3点开始,重新编译程序,到了早上8点左右,差不多就编译完成了。然后捕获错误,如果有的话,就发电子邮件给相关的人。这样,到了上班的时间,每个人都能得到一个最新的,编译好的程序。如果代码中有错误,还能最快的得到错误报告。再比如,我需要使用别人写的API函数,当然,我不能指望每个人写的函数都采用同样的命名方法和参数定义方法,也不可能每次需要使用的时候都去查看文档,那样太浪费时间而且效率太低。我写了一个工具,让它来检查我的函数调用是否正确,参数是否正确。如果有错误,则从文档中找到可能的函数,并在错误日志中给予提示。然后我就能很快的编写代码,而不用担心函数拼写,参数调用的类型和顺序了。你也可以这么做,当下次有人来问你某个函数的名称,参数类型,参数顺序的时候,你就能够告诉他,该怎么做,用什么工具了。
可复用的代码
有一个好的比方,用来描述一个引擎。有一个不是程序员的朋友问过我一个问题,什么是程序引擎?有什么作用?为什么要用引擎?我尽量的用通俗的语言回答它,一个程序引擎就像一个汽车的引擎。没有它,汽车不能启动,但是,同时,一个没有轮胎的引擎,也是没有用处的。
我想,这是一个好的例子。这个朋友说,当你的引擎不能用的时候,你可以换一个。如果传动带坏了,你
可以换一个新的,同时把引擎的性能调整到最好。同样,一个引擎有相同的部分,比如,传动装置,等等。它们对于一个引擎是重要的,如果某一个部分坏了,你不能不拆开引擎来更换它。
然后我的朋友总结道:如果你从头来写一个程序引擎,你就不得不从头来写所有的传动带,所有的零件。如果你能用一些以前用过的部分,你就能简单的把它们拼装到一起而不用重新写了。
没错。他并不懂得如何去写程序,但是他道出了编程的真谛。这也是一个普通的程序员和一个高级程序员的区别。采用可复用的代码,让工作变得简单。
写通用的代码的关键是,不要让你的子程序变长,不要超过一屏。关键要把你要做的事情分解开,变成小巧的,可以复用的函数,要么完成一个功能,要么调用另外的函数来完成一个完整的功能。
比如,VectorAdd()可能包含了一段代码把两个vectors的元素合并到一起,而SceneDisplay可能包含了调用PrepRender(), Render2dObjects(), RenderHud()的代码。每一个函数可能都只有几行。
当你把代码分解成小的部分的时候,你将能够集中注意力到一些在其他地方可以复用的功能上。在前一个例子中,RenderHud()和RenderDebugText()可能共享了同样的一段函数调用,因为它们都是在屏幕上描画一些对象。
有很多人认为,在你做一个通用的代码的时候必须有一个好的设计。当你编写模块和系统的时候,设计是重要的步骤,但是,仅做这些还是不够的。我要说的是,要养成一个习惯,把你要写的每一段代码都变成一个通用的,可以复用的代码。这样,当你设计一个新系统和模块的时候,你将有大量的可以复用的功能模块,你只需要调用其中的一些功能,而不用从头写所有的代码。
做一个好木匠
木匠用一些原材料,根据学来的经验和自己的想象来打造木器。在他们工作的早期,可能他们用一些简单的工具,比如锤子,钉子,刨子等等来打造木器。但他们积累了一定的经验后,他们可以做一些更高级的事情,比如给一个房子加上一扇门。当一个木匠取得了更多的经验,他就能有机会建造一整套房子,也能够带领一个小组的人来干活,告诉他们,什么人干什么活,比如,有人专门刨木头,有人专门钉钉子,等等。
这些高级的木匠是有价值的,并不是因为他们懂得用很多的工具,而是因为他们懂得如何和什么时候去用他们。当你给一个木匠一个锤子,让他把一扇门装在门框上,他会问你要一个螺丝刀和螺丝。如果给一个普通人一把锤子,他可能会认为门是用钉子钉上去的。而如果你给一个小孩一把锤子,他就会拿这把锤子来敲所有的东西,好像所有的东西都变成了钉子。
要有好的判断能力,当你解决一个问题的时候,不要总是尝试用最新的技术或者你最熟悉的技术去解决问题,因为它可能并不是和。重要的是,总是采取在特定的范围内最适合的工具去解决问题。
承认你不懂的东西
我们都是人,人无完人,没有人能够懂得所有的东西,所以我们也不是什么都懂。当你被领导要求去完成一个你不熟悉的任务的时候,该怎么去做?如果你回答,"我不会,对不起,我不懂如何去做"。我相信没有人会愿意这样去回答。因为这将让你在领导面前很没有面子,同时,也失去了你的一部分价值。在上面的例子中,很多人都认为最好什么都不说,免得别人认为你不懂得你正在做的事情。然后,他们会闭上嘴巴,超时工作,读更多的书籍和网上的文章,按时完成任务。
但是往往,你闭上嘴巴,超时工作,读任何你能找到的书籍和文章,但是你还是不能按时完成任务,或者超过了一个月的时间你才完成任务。你完成了任务,但是,你花了多大的代价?
如果你不懂得要完成的任务,也没有足够的了解和知识,最好的方法是承认它。而不要试图隐瞒或者撒谎。如果你说你对它不熟悉或者不懂得怎么去解决这个问题,你可以这么说,"我不懂得这个问题,它对我来说是新问题,有没有什么你可以告诉我该往哪个方向去做,或者有没有类似的例子可以给我做参考?".当然你不能这么说,"我不会做。我没有用处。炒了我吧。"你要表达的是,"我可能不懂,但是没关系,我愿意去学习。我愿意学习并且按时完成工作"。 有很多别的程序员可能会很高兴与你分享他们所懂得的知识和获取的经验。这样,你就能够更快的学会你要学的东西并且按时完成任务。