《程序设计实践》前言

你是否曾:

  浪费了许多时间去对一个错误算法做编码?
  使用了一个数据结构,实际上它是过于复杂了?
  测试一个程序而忽略了其中最简单的问题?
  化了一整天功夫查找一个错误,实际上你应该在5分钟里就找到它?
  需要让一个程序运行得快3倍而且只使用一半的存储?
  费劲地把一个工作站上的程序移到PC上,或者相反?
  试图对其他人写的某个程序做最简单的修改?
  重写一个程序,原因是你根本无法理解它?

这些事都很有趣吗?

  编程序的人每时每刻都遇到这些事情。但在处理时发生的情况却很不令人满意,通常都比实际上应该的情况更糟。产生这种状况的原因是,常规的计算机科学和程序设计课程都不大关注那些程序设计实践方面的论题,如测试、排错、可移植性、性能、设计可能性和选择、程序设计风格等等。许多程序员随着自己经验的增长慢慢地、毫无计划地学到了一些东西,也有些人始终都没有学好。
  在这个庞大的世界里,人们面临的是错综复杂、相互联系和处于不断变化中的工具、语言和系统,以及对任何东西都提出更多要求的无情压力。这种情况下,人们很容易忘掉那些最基本的原则:简单性、清晰性、普遍性。而正是这些东西,实际上是构成好软件的基石。人们也可能忽略工具和描述法的价值。实际上,利用它们可能机械性地构造出某些软件,从而让计算机为其本身的程序设计做一些事情。
  在这本书里,我们采用的方式是讨论一些基本的,互相关联的原则,它们可以用到计算的各个层次中。这些原则包括:简单性,它能使程序短而容易处理;清晰性,它保证程序容易理解,无论是对人还是对机器;普遍性,它意味着程序在很广泛的情形下都能工作得很好,也容易做修改以适应新出现的情况;自动化,借助计算机帮助我们做一些工作,使人能够摆脱许多平凡琐碎的事项。通过考察不同语言中的一些程序设计例子,从算法和数据结构,到设计、调试、排错和性能改进,我们能展示出许多具有普遍意义的工程概念,它们是独立于具体语言、操作系统和编程范型的。
  本书植根于我们多年来开发和维护大量的软件,多年讲授程序设计课程,多年与各种各样的程序人员共同工作中的经历。我们希望与人共享这些关于程序设计实践问题的经验和教训,从我们的经验中传达一些深层的认识,提出一些方法和建议,帮助各种水平的程序员变得更加熟练,工作更有效率。
  我们的书是为许多不同类型的读者写的。如果你是学生,已经上过一两门程序设计课程,希望成为一个更好的程序员,这本书将给你展开某些问题,而这些问题在你自己的课程里没有足够的时间讨论。如果你把写程序作为自己的一部分任务,目的是为了完成其他工作而不是做程序本身,这里的信息将帮助你更有效地编写程序。如果你是职业程序员,在学校期间没有学过这些内容,或者希望重新温习一下;或者你是个软件管理者,希望指导你的工作人员向正确方向发展,这里的材料都会非常有价值。
  我们希望这里提出的建议能帮助人们写出更好的程序。读这本书的惟一先决条件,是你已经做过一些程序设计,最好是用C、C++或者Java。当然,已有的经验越多,有关内容对你来说就越容易。不可能有任何东西能帮你在21天内从新手变成专家。对于这里的某些例子,Unix和Linux程序员可能比经常用Windows和Macintosh的程序员更熟悉一点。但是我们相信,无论你来自哪个环境,都一定能在这里发现一些东西,它们可能使你的生活变得更容易些。
  本书全部内容被组织为9章,每章集中讨论程序设计实践的一个重要方面。
  第1章讨论程序设计风格。好的风格对于好的程序设计是如此重要,所以我们选择在最前面讨论它。书写良好的程序比胡乱写出的程序好,它们包含的错误更少,更容易排错、容易修改。所以,最重要的就是从一开始就注意风格。在这章里还提出了好程序设计的一个重要论点:应该尽量采用对所用语言最合适的习惯用法。
  算法和数据结构是第2章的论题,这是计算机科学教育计划的核心,也是程序设计课程的重要组成部分。由于许多读者已经熟悉了这方面情况,本书中的处理方式就是对那些几乎出现在每个程序里的算法和数据结构做一个简单的总结。更复杂的算法和数据结构通常都是由这些基本东西建构起来的,因此需要掌握这些最基本的东西。
  第3章讨论一个小程序的设计,以便在实际工作中展示讨论与算法和数据结构有关的各种题。这个程序用5种不同语言实现,通过对各种不同实现的比较,说明了同样的数据结构如何在不同语言里处理,语言之间在表达能力和性能方面的变化情况等。
  用户和程序之间、程序不同部分之间的界面是程序设计的一个最基本问题。软件的成功很大程度上取决于这些界面设计和实现。第4章用一个小函数库作为例子,展示了界面的演化过程,这个库用于分析处理一种广泛使用的数据格式。虽然这个例子很小,但却显示出界面设计的许多重要问题:抽象、信息隐蔽、资源管理、错误处理等等。
  虽然我们总是希望第一次就能把程序写正确,但是,程序错误及相应排错过程实际上是无法避免的。第5章讨论了系统化地、有效地排除程序错误的各种策略和技术。有关论题中包括常见错误的标志、数值特性的重要性等等。程序输出中模式性的东西常常能告诉我们问题究竟出在哪里。
  测试的目的就是企图给出一种合理的保证,说明一个程序能正常工作,或者说明它经过改造之后仍然是正确的。第6章强调的是如何通过手工和机械的方式进行系统化的程序测试。边界条件测试针对潜在的薄弱点进行仔细检查,机械化和测试台测试使人可以比较容易地以合理代价完成昂贵的测试,应力测试提供与典型使用不同的另一类测试,它可能搜寻出另外一些种类的错误。
  计算机的速度已是风驰电掣,编译器已经做得如此之好,因此,许多程序在写出来之时就已经足够快了。但是,另有一些程序则实在是太慢,或者是使用了太多的存储,甚至同时存在这两方面的问题。第7章给出了一种有序方法处理这些问题,设法改造程序,使之能更有效地使用资源,并使它在提高效率的同时仍然是正确和有效的。
  第8章讨论可移植性问题。一个成功的程序可能在环境不断变化的情况下使用相当长时间,或者需要搬到新的系统、新的硬件、甚至新的国家去。可移植性的目标就是设法减少程序的维护,使程序在移植到新环境时要做的改动达到最小。
  计算是一个语言丰富的领域,在这里,不止有我们常用来做程序设计的通用语言,还有许多集中应用在较窄领域中的专门语言。第9章给出了一些例子,说明在计算领域里记法的重要性。这里还想说明怎样利用这方面的东西来简化程序,指导程序设计,或者帮助我们编写那种能够写程序的程序。

  由于要讨论的是程序设计,我们不得不给出许多代码。这里的大部分例子是为本书特别写出来的,也有些小例子取自其他来源。为把这些代码写好,我们已经做了很大努力,而且在半打的系统上的测试过这些代码,直接采用机器可读的形式。关于《程序设计实践》这本书的更多信息可以在下面网址找到:

 http://tpop.awl.com
  本书里的大部分程序是用C语言写的,也有一些用C++ 或Java写的程序例子,还有关于脚本语言的简短讨论。在最低的层次上,C和C++几乎完全一样,因此我们的C程序也是C++程序。C++和Java是C语言的直系后代,它们从C继承的远不止是一点语法,更多的是效率和表达能力,还有丰富的类型系统和函数库。我们在自己的工作中常规性地使用这三种语言,此外还使用一些其他语言。语言的选择依赖于问题本身:操作系统最好用某种高效的限制较少的语言来写,比如用C或者C++;快速原型用某个命令解释器或者脚本语言写常常是最容易的,比如用Awk或Perl;对于用户界面,Virsual Basic或Tcl/tk,还有Java,都是强有力的候选者。
  对于我们的例子,如何选择语言还有一个重要的教育学因素。正如没有任何语言能够同样好的解决所有问题一样,也没有一个语言对说明这里的所有问题都是最好的。更高级的语言实际上是预先确定了某些设计决策。如果用低级一些的语言,我们将能讨论对问题的各种解答,通过揭示其中的更多细节,有可能更好地处理它们。经验证明,即使是在使用高级的语言机制时,了解它们与低层次的关联关系也是很有价值的。如果没有这种洞察力,我们就很容易陷入性能或者其他奇怪的问题之中。所以我们在写例子时经常使用C语言,即使是在那些实际中可能会采用其他语言的地方。
  实际上,本书的大部分内容是独立于任何特定程序设计语言的。数据结构的实现受到所使用语言的影响,在有些语言里选择的可能性少些,有的语言可能支持更多的选择。但是话说回来,在这方面,做选择的方式都是一样的。在不同语言里,如何做测试、如何排除程序错误等也都会有许多不同,但其中的策略和技巧又是类似的。改进程序效率的大部分技术都可以应用于任何语言。
  无论用什么语言写程序,你作为程序员的工作都是尽可能地利用手头的工具,尽可能地把事情做好。优秀的程序员可以克服一种不良语言或者一个拙劣的操作系统带来的坏影响,但是,即使最伟大的程序设计环境也拯救不了一个糟糕的程序员。我们的希望是,无论你当前的经验和技术如何,这本书都能帮助你更好地编程并从中取得更多的乐趣。

  我们衷心地感谢所有那些朋友和同事,他们读过本书的草稿,给了我们许多很有帮助的建议。Jon Bentley,Russ Cox,John Lakos,John Linderman,Peter Memishian,Ian Lance Taylor,Howard Trickey,和Chris Van Wyk极其认真地通读过本书的手稿,有人还读过不止一遍。我们感谢Tom Cargill,Chris Cleeland,Steve Dewhurst,Eric Grosse,Andrew Herron,Gerard Holzmann,Doug McIlroy,Paul McNamee,Peter Nelson,Dennis Ritchie,Rich Stevens,Tom Szymanski,Kentaro Toyama,John Wait,Daniel C. Wang,Peter Weinberger,Margaret Wright和Cliff Young对手稿各个方面提出的极有价值的意见。我们也感谢Al Aho,Ken Arnold,Chuck Bigelow,Joshua Bloch,Bill Coughran,Bob Flandrena,Renée Frence,Mark Kernighan,Andy Koenig,Sape Mullender,Evi Nemeth,Marty Rabinowitz,Mark V. Shaney,Bjarne Stroustrup,Ken Thompson和Phil Wadler等的好建议和经过深思熟虑的提议。谢谢你们大家。

                            Brian W, Kernighan
                            Rob Pike