前言
人们为电子计算机编写程序已有 80 多年,但令人惊讶的是,对于如何设计程序、好的程序应该是什么样,讨论却一直很少。相比之下,软件开发过程(如敏捷开发)和开发工具(如调试器、版本控制系统、测试覆盖工具)已经得到了广泛讨论。面向对象编程、函数式编程等编程技术,以及设计模式和算法,也已有大量分析。这些讨论都很有价值,但软件设计的核心问题仍很少被触及。David Parnas 的经典论文“关于将系统分解成模块的标准”发表于 1971 年,此后 45 年间,软件设计的水平并未在这篇论文的基础上取得多少进展。
计算机科学中最基本的问题是 问题分解:如何将一个复杂的问题分解为可以独立解决的部分。问题分解是程序员每天都要面对的首要设计任务,但是,除了这本书里描述的工作之外,我还没有在任何一所大学里找到一门以问题分解为中心的课程。我们讲授 for 循环和面向对象的程序设计,而不是软件设计。
此外,程序员之间的代码质量和开发效率差异很大,但我们很少探究最优秀的程序员为何如此出色,也很少在课堂上传授相应技能。我曾与几位自己认为很优秀的程序员交谈,但其中大多数人也难以说清,究竟是哪些具体方法让他们占据优势。许多人认为软件设计是一种无法教授的天赋。然而,大量科学证据表明,在许多领域,相比先天能力,杰出表现与高质量练习的关系更密切(例如,参阅 Geoff Colvin 的《哪来的天才?练习中的平凡与伟大》)。
多年来,这些问题一直让我困惑和沮丧。我想知道软件设计能否通过教学传授,也猜想设计能力正是优秀程序员与普通程序员的区别所在。最终,我认定,回答这些问题的唯一办法,就是尝试亲自开设一门软件设计课,斯坦福大学的 CS 190 课程由此诞生。我在课上提出一套软件设计原则,让学生通过一系列项目理解并实践这些原则。授课方式类似传统英语写作课:学生先写草稿,获得反馈,再修改完善,反复迭代。在 CS 190 中,学生从零开始开发一个具有相当规模的软件,随后我们通过大量代码审查找出设计问题,再由学生修改项目、解决问题。这样,学生就能看到如何运用设计原则改进代码。
我已经讲授过几轮这门课程,本书正是根据教学过程中形成的设计原则写成的。这些原则较为抽象,近乎哲学概念(例如“通过定义来规避错误”),学生很难仅凭抽象论述理解它们。最有效的学习方式是亲自编写代码、犯错,再观察错误及其修正与这些原则之间的关系。
读到这里,你也许会问:我凭什么认为自己知道软件设计的所有答案?坦白说,我并不知道。我学习编程时,没有软件设计课程,也从未有导师向我传授设计原则,代码审查几乎还不存在。我对软件设计的认识,来自亲自编写和阅读代码的经验。在职业生涯中,我用多种语言编写了约 25 万行代码。我参与的团队曾从零构建三个操作系统、多个文件系统和存储系统、调试器、构建系统及图形界面工具包等基础架构工具、一种脚本语言,以及用于文本、图形、演示文稿和集成电路的交互式编辑器。在此过程中,我亲身经历了大型系统的问题,也尝试了各种设计技术。我还阅读了大量他人编写的代码,接触过各种好的和坏的做法。
我试着从这些经验中找出共同之处,归纳出应当避免的错误和值得采用的方法。本书正是这些经验的总结:书中描述的每个问题我都亲身经历过,推荐的每种技术也都在自己的编程实践中成功使用过。
我并不期望本书成为软件设计的定论。我肯定遗漏了一些有价值的技术,长远来看,其中某些建议也可能被证明并不好。但我希望本书能开启关于软件设计的讨论。请结合自己的经验,判断书中的方法是否真的能降低软件复杂性。本书表达的是我的个人观点,有些读者自然不会赞同所有建议。如果你不同意,请试着想清楚原因。我很想了解哪些方法对你有效、哪些无效,以及你对软件设计的其他想法。希望这些讨论能加深我们对软件设计的共同理解;我也会将从中学到的东西纳入本书的未来版本。
与我交流这本书的最好方法是将电子邮件发送到以下地址:
software-design-book@googlegroups.com
我欢迎关于本书的具体反馈,例如错误或改进建议,也希望听到大家对软件设计的看法和经验。我尤其希望收到可用于本书未来版本的有说服力的示例。最好的示例既能说明一项重要设计原则,又足够简单,用一两个段落就能讲清楚。如果想阅读他人发到上述邮箱的内容并参与讨论,可以加入 Google Group software-design-book。
如果 Google Group software-design-book 将来因故消失,请在互联网上搜索我的主页,那里会提供最新的本书交流方式。请不要将与图书相关的电子邮件发送到我的个人电子邮件地址。
我建议你不要盲从本书的建议。总体目标是降低复杂性,这比书中任何一条具体原则或想法都重要。如果尝试某种方法后发现它并未降低复杂性,就不必勉强继续使用(不过,请告诉我你的经历;无论方法是否有效,我都希望得到反馈)。
许多人提出了批评或建议,以提高本书的质量。以下人员对本书的各种草稿提供了有用的意见:Abutalib Aghayev,Jeff Dean,Will Duquette,Sanjay Ghemawat,John Hartman,Brian Kernighan,James Koppel,Amy Ousterhout,Kay Ousterhout,Rob Pike,Partha Ranganathan,Daniel Rey,Keith Schwartz 和 Alex Snaps。Christos Kozyrakis 为类和接口建议了术语“深”和“浅”,代替了之前有点模糊的术语“厚”和“薄”。我很感激 CS 190 中的学生,阅读他们的代码并与他们讨论的过程有助于明确我对设计的想法。