杂文笔记

    返回首页    发表留言
本文作者:李德强
          编程是一门艺术
 
 

        IT行业是一个又特殊又普通的行业。在这个多元化、信息化的时代,人们对电脑、互联网、智能家电等等名词越来越熟悉,越来越依赖。而这些名词背后有着一个神秘的行业——IT业。这个行业发展迅速,从早期的电脑、软件、互联网到现在的信息化、大数据、云计算、人工智能等等。随着这些热门词汇渐渐被人们所接受。行业内部的专业人士也越来越关注这方面的技术内容,但是对于编程的艺术却被逐渐的淡化。人们不再讨论编程的过程与实现,而是讨论更模块化的功能集成,把使用各大公司研发的框架、软件产品当做学习对象,而把编程简单的看作是“写代码”而已。

        在这个飞速发展的时代为了能够快速的研发软件,能够快速按时完成程序编写工作,只好使用那些所谓的“流行编程语言”,比如C++、Java、Python、C#、JavaScript等等。它们高效、方便移植、可扩展、可集成。大家通常更在乎代码所实现的功能,而忽略了编程代码的过程。往往编写几行代码,调用现成的类库或函数库就可以实现强大的功能。由于人们通常沉迷于结果而忽略了过程,因此越来越多的人不再注重代码的质量,认为只要能够实现目标功能的代码就是好代码。而编程本身也被人逐渐看成是“写代码”而已。

 

        实际上,编程是一门高深的艺术,并非是“写代码”那样的简单。计算机的专业课非常多,而编程语言的学习却很少,通常只有《C语言》和《C++语言》。然而除了编程语言的学习之外还要学习很多基础课程,例如:《计算机组成原理》、《计算机体系结构》、《数据结构》、《算法导论》等等。另外,基础数学方面的知识也是必学的:《高等数学》、《线性代数》、《概率统计》、《离散数学》等等。

        编程只是一个表象,在编程过程的背后需要大量的基础知识为其做支撑。同样在编写程序,程序的好与坏标志着程序员的能力。有两个程序员,实现具有相同功能的程序,两个人都完成了程序的编程工作。但是,一个人的程序代码冗长、复杂难懂、性能低下;另一个人的程序代码逻辑清晰、简单明了、性能还很可观。显然编写代码的好坏可以体现出编程人员的能力,而编程人员的能力高低会直接影响程序的好坏。

        优秀的程序一定要满足功能性、可靠性、易用性、高效性、可维护性、可移植性。这六个方面被称作为软件质量六要素:

        功能性:是一般软件程序的最低要求,即必须满足目标功能要求。

        可靠性:又称健壮性,程序可以稳定的运行、不崩溃、不异常。

        易用性:良好的用户界面与使用方式。        

        可移植性:从一种计算环境移植到另一个计算机环境下的容易程度。

        维护性:程序代码要有优秀的编码风格、良好的命名规范。想象一下,如果你今天写的一段代码和昨天写的代码风格迥异,命名杂乱无章。明天你回过头来看看自已写的代码说:“哦,这是谁写的?我不认识它们。”这是很不好的习惯,优秀程序的可维护性,也体现在代码的可读性上,庞大功能的软件代码可能具有几十万行代码,或几百万行代码,甚至更多。这些代码通常由不同的程序员来完成,如果每个人写的代码风格都不同,每个人写的代码在其他人看来都非常难懂,那这款软件就是一款非常失败的软件,没有很好的可维护性。所以我们经常见到一些年青人写了一些很难懂的代码然后自豪的说:“看,我写的代码你们谁都看不懂!”这样的人不是合格的程序编写者。优秀的事物都应该是简单的、易懂的、公开的、无秘密的。

        接下来我们谈谈高效性。高效性又称高性能要素。把这个要素放在六要素的最后来阐述是有原因的。我们在做程序设计和实现时,往往很容易把程序的性能忽略掉。人们通常认为功能是重要的,而性能是不必要的,这是一个非常错误的观点。性能是软件程序的最核心的要素。你可以想象当你打开一个软件让它为你做一件小事,而它几乎运行了十分钟才把你想要的照片显示出来,这时你的心情会是什么样?当然,你可能认为这个例子比较极端,但是假设我们要在全国十几亿人口中所有的一寸照中找到某一个指定人的照片时,十分钟就好像不是那么久了,但是如果让你来编写这个程序,你能让程序多久才能完成这个功能?所以说性能是衡量软件程序质量一个非常重要要素。

 

        数学——科学的女王,是科学界的母体。想要学好编程,同样要学好数学,这是没有争议的。而人们通常所说的“写代码”从严格意义上讲不能算做是编程,编程是一门很复杂的艺术。提到编程就要提及算法,因为算法是编程的灵魂,一个没有算法的程序是很初级的,是很苍白无力的。优秀的程序要以合理的数据结构为根基,加以高效的算法,用简单漂亮的代码实现目标功能。功能就像计算机领域里的“面包和水”,算法好比计算机领域里的“金钱”。我们为了维持生命,需要的是食物,需要吃面包和喝水,而现代社会中我们都不会直接追求食物,而是间接的追求“金钱”,然后再用“金钱”购买“面包和水”。当然,这个比喻并不十分恰当,但也说明了算法的重要性。

 

        我们再来谈谈编程语言。我不想用所谓的“高级语言”、“面向过程”、“面向对象”、“脚本语言”等等这样的词来阐述。在这里我只把这些编程语言分为两类:传统语言(汇编、C语言等)和流形语言(C++、Java、Python等)。目前编程语言非常多,它们通常都是多样化、模块化、功能化、抽象化的。我们来做一些比较:

        一、从性能上讲传统语言可以直接编译为CPU可识别的机器码,从而高效的运行。而流行语言通常是运行在一个通用的平台上的,例如Java虚拟机和.NET环境。

        二、从可移植上讲传统语言可以通过条件编译生成不同环境下能够运行的机器码,而流行语言大多不需要针对系统环境修改代码,但需要针对运行平台做开发。

        三、从可维护性上讲传统语言同样采用条件编译来实现不用的功能分支及扩展,无用的代码不会生成机器码,更不会执行。而流行语言中为了可扩展,常常采用很多的配置文件、配置脚本来实现功能扩展和功能切换,采用所谓低偶合的设计模式,用大量的代码来实现可扩展性,于是流行语言的代码通常臃肿不堪,运行缓慢,配置文件更是复杂难懂。这与优秀的程序设计理念背道而驰。

 

        我们再来引用Linux之父Linus在批评C++时说的话:

        “C++会导致非常非常糟糕的设计选择。总是用语言的‘漂亮的’库特性比如STL、Boost等等,这可能对程序有所‘帮助’。当这些库无法工作时,你会有无穷无尽的折磨,这是非常低效的抽象编程模型。也许在两年之后你才有可能注意到有些抽象效果其实并不怎么样。但是,所有代码已经依赖于围绕它设计的‘漂亮’对象模型了,如果不全部重新设计、修改程序代码,这些问题就无法改正。另外,我认为字符串处理是C++会找来大麻烦的地方之一。糟糕的程序员会这样写代码:

        a= b + "/share/" + c + serial_num;

        其中你肯定无法弄清到底分配了多少内存,因为有类型强制转换、重载的操作符,而当这种东西出现在内循环中,结果将是性能上的大灾难,而且原因还不明显!”

        引用以上内容并非断章取义,C++与其它流程语言一样,它们有丰富的类库和函数库,就像大树的每一个分支都长满了美丽的叶子,每一个方向都有成型类库和函数库。使得很多人形成“拿来主义”的思维定式。想要实现一个功能,就找到这个功能对应的库,调用一个函数或方法就可以立即实现这个功能,这很好,也正是目前流行语言之所以“流行”的原因。然而性能问题、安全问题等等全都是隐患。当然,也可以修改开源类库的源代码,但毕竟能够做的工作十分有限,而且是否能真正解决问题也不能保证。

        优秀的程序开发者要了解并掌控自己写下的每一行代码,明白它们的意义和功能,并能随时随地做任何功能上的调整。你绝不会这样说:“这个功能是底层库实现的,我不关心它是什么,更不关心它是怎么实现的。”当然,使用C语言编程也同样需要调用大量的标准C库函数。但优秀的程序员一定会明白这些函数内部是如何实现的,也可以自己重新编写一个函数来实现它。

        使用流行语言“写代码”就像我们常年使用计算器之后再也不会口算;每天用拼音打字之后却提笔忘字。实际上,任何领域都是一样的,高级的工具用的久了就会忽略这句重要话:“最原始的方法往往是最有效、最灵活的方法——老把式才是真把式。

        编程不是简单的“写代码”,想要编写出优秀的程序,自己时时刻刻都要思考:你需要使用什么样的数据结构,需要如何设计高效的算法。养成通过思考来解决问题的习惯,以不变应万变。

        编程是一门艺术。这门艺术不是看了一本编程语言书之后,就能做得出色的。会写毛笔字的人就一定是书法家吗?会素描的人就一定是画家吗?学会了围棋的规则的人就一定是围棋大师吗?不见得。在这里我没有讽刺和贬低任何人的意思。我只是说,编程与其它学科艺术一样,想要在任何一个领域里做的好,都需要多年的学习,实践,积累,总结。学了一门编程语言之后只能说是刚刚入门,要想做得好,还需要学习大量的知识,通过不断的努力,才能在编程方面有所成就。有很多人想法非常多,也非常好,很有想象力,但缺乏实践经验。在讨论问题时侃侃而谈,但从不喜欢手动去做,嘴上描述的天花乱坠,但从不脚踏实地的去写几行代码。想一千次,不如去做一次。一次华丽的跌倒胜过一千次无谓的徘徊。

 

        20世纪初,美国福特公司的一台电机出了毛病,为了减少损失,需要在不停机的情况下把毛病找出来。公司里的技术人员怎么也找不出毛病在哪儿,最后,只好到外面请来了流落到美国的原德国技术专家斯坦门茨。斯坦门茨在电机房躺了三天,听了三天,要了一架梯子,一会儿爬上去,一会儿爬下来,最后在马达的某一个部位用粉笔画了一道线,并说:“打开电机,在记号处把里面的线圈减少16圈。”人们照办后,毛病果然消除了。斯坦门茨的解决办法非常简单,但在这简单的背后却有他非常多的知识和经验做理论支撑。

        编程的过程也是一样,一些简单的表象背后有着很多的知识。请参见《技巧:四舍五入》《技巧:数组的下标》《技巧:递归》

        所以我们说,在编程的背后有着非常多的知识和经验做理论支撑。编程并不简单,在编程的深处有着许许多多需要我们学习的知识,有着太多太多需要印在心里的宝贵经验。

         最后,让我们用一种很有趣的方式来描述编程的艺术。

       金庸先生的武侠小说中有一位绝顶高手——剑魔独孤求败。他荡尽仇寇,败尽英雄,天下更无抗手,生平求一敌手而不可得,自述人生经过了四种境界:

        无名利剑:凌厉刚猛,无坚不摧。弱冠前以恃之与河朔群雄争锋。用流行语言,一行代码为你完成大量复杂的工作,简单的代码就可以实现庞大而漂亮的功能。

        紫薇软剑:三十岁前所用,误伤义士不祥,乃弃之深谷。当你沉迷于流形编程语言的类库丰富、功能强悍时,往往会出现性能问题、功能性问题,而且终究无法很好的解决,扔了它吧。

        玄铁重剑:重剑无锋、大巧不工,四十岁前恃之横行天下。学习C语言和使用C语言很有难度。想要用C来写一个有实用性的软件程序可能要消耗掉大量的时间和精力,但使用“重剑”的过程中,你的“内功”也在飞速的提升。当你用C写的程序从各个方面都能够与其它流形语言所开发的程序相比肩的时候,也就是你举重若轻的时候,此时你所编写的程序一定好得多。

        木剑:四十岁后,不滞于物,草木竹石均可为剑,自此精修,渐进于无剑胜有剑之境。编程语言只是我们使用的工具,当你的理论与实践真正达到一流高手的境界时,不再局限于任何的编程语言,也不再局限于为哪个领域做开发。用你的想象力和丰富的经验为根基,不再拘泥于任何的编程工具与软硬件环境!给你一台计算机,你能用它创造一个崭新的世界!

 

    返回首页    返回顶部
  看不清?点击刷新

 

  Copyright © 2015-2018 问渠网 辽ICP备15013245号