内容


Rational Edge

编写干净的代码

系列内容:

此内容是该系列 # 部分中的第 # 部分: Rational Edge

敬请期待该系列的后续内容。

此内容是该系列的一部分:Rational Edge

敬请期待该系列的后续内容。

illustration今年夏天我在明尼苏达州明尼阿波利斯参加了Agile 2006会议,并在那里度过了美好的时光。当我与Ron Jefferies谈论我在软件开发教学中采用的方法的时候,从事Agile Toolkit 相关工作的Bob Payne问我是否愿意对这个话题创建一个博客。1 一年前我已经在这个专栏描述了我的教学方法2 所以我不想再次谈论这个话题。但是我将关注一个我在记录这个播客时所遇到的一个问题:不能够编写干净简洁的代码,这也是程序员们遇到的一个相当普遍的问题。

这个话题是怎样产生的呢?一个倾听我们记录的播客的人简单地问了这样一个问题:为什么当今大学毕业生不能够编写出干净的代码(也就是,易读的、结构合理的、优雅的代码)呢?“难道这些学生们都没有意识到在现实的社会中编写不干净的代码是要受到惩罚的吗?”他十分惊奇地问到。“您们这些教授有什么地方做得不对,而导致这些学生并不认为编写优雅的代码和解决方案是很有必要的?”

在这篇文章中,我将谈论到一些劣质代码的问题和因果关系,并提出一些可行性的解决方案。

究竟什么是“干净的”代码?

在一定程度上,干净的代码——像漂亮一样——就是在旁观者眼中所留下的印象。有经验的程序员能够一眼看出程序的源代码并断定它是否是一个易读的代码。他们还能够很快地提出关于这个代码是否是高效,结构是否合理以及是否简单明了的意见。所有的这些特征都很难定义,但是当您把代码呈现给这些程序员时,您通常会很赞同他们对代码是否干净的判断。

决定干净代码的因素很多。有些是普遍性的,适用于任何类型的编程语言或者您所开发软件的问题领域。有些是干净代码的属性取决于特定的编程语言。

让我们快速浏览一下这两个能运行出相同结果的代码。这个代码是一个网球运动的记分规则。3 它们都有一个记录比赛中赢家分数的算法,和一个返回包含这个分数消息的算法。假设所有的输入都是有效的,并且没有对无效状态的核查。他们都是用契约式设计的方法编写的,因此所有正确使用这个类的担子都落在这个客户机程序上。您认为哪一个“更优秀”呢,列表1还是列表2?

code listing 1

code listing 1

列表1:第一个网球规则记分范例

code listing 2

code listing 2

列表2:第二个网球规则记分范例

列表1编写的风格非常简单,一个编程的初学者可能会这样用,看起来像是在重复它本身。这种复杂性完全没有必要,但是对我来说似乎很混乱而且效率非常低。列表2有很多复杂的条件,但是如果您了解Java就会知道它很容易理解。唯一可以让您有疑问的是在最后一个else if中条件的开始部分。结果证明当您获得这样的一个子句时,就有一个选手会赢。

这两个程序运行都没有错误。事实上,它们都很小,跟一个玩具例子差不多,因此除了用您的偏好来判断哪个代码更优秀外,这些列表还不足以用来说明干净代码的重要性。

有很多讨论干净代码的文章、网站和书籍。每个人对什么是干净代码都有自己的看法。因为我已经看过他们其中的一些代码——在我的教学和研究中我已经阅读过非常多的代码——我认为您可以遵守一些通用的原则。我将在这篇文章的后面部分为您提供这些原则。

我们为什么会编写出一些不干净的代码呢?

我认为有以下几个造成我们编写不干净或者冗长代码的原因:

  1. 时间压力
  2. 缺少训练
  3. 动机

让我们分别看看这些原因。

时间压力

软件项目偏离轨道。如果您采用的是一个瀑布式的过程,它们将会比您采用迭代的方法偏离得更厉害,但是无论您采取什么样的生命周期模型,绝大多数项目都会有所偏离。使用迭代递增的生命周期,这种偏离将会是功能性方面的,而不会在交付日期上发生。

当一个项目开始偏离轨道时,开发人员——以及整个团队——都要采取捷径,这是人的本性。有一个谚语:“当您的脖子即将进入鳄鱼的口中,您很难记得您是处于将要陷于沼泽的状况。”当受到时间的压迫时,有些东西就应该放弃,我们通常会忽略那些不能直接减轻压力的事情——我们只知道要攻击鳄鱼。我注意到,过程是这种忽略中典型的牺牲品。这个过程可能会采取特殊的行为或者产生某些工件,但是如果我们能够忽略它就应该忽略掉。当紧迫的时间稍微缓和之后,我们应该有很好的目的和计划返回来检查,但是我们却很少这样做。

当我们不得不丢掉一些东西的时候,干净的代码也属于这个范畴的过程被我们丢弃。为了简单和节约宝贵的时间,我们用“np”来代替“netPay”变量的名称。我们不再提供有意义的注释或者描述这些算法。最终的期限已经迫近,我们只是想着要使我们的代码能够运行。

为了在最终期限完成任务,我们用这样方法来编写代码是目光短浅的做法,我们最终将受到惩罚。

缺乏培训

无论您是在高中,大学还是其它途径学习的编程,问题是您实际上并没有学习如何编写干净的代码。部分原因是由于教育机构的时间都相当紧迫。在有限的学时中也只能教授有限的知识,编码的设计、易读性以及其它干净代码的典型特性在教育过程中都被省略掉,就像一个项目在最终期限时间的压迫下丢弃一些过程一样。

如果您看看各个不同教育机构的程序设计课程的教学大纲,就会发现会有一些教学大纲把程序的设计列为课程或者教学目标。我见过的大多数大纲中都很深入地说明了这一点,看来教师们很少实现这个目标。分配和标准分级没有谈到任何惩罚或者对干净的、易读的、有条理的代码的奖励。商业程序设计课程比在学校提供更少的知识。他们通常上课的时间更少,并只关注于向您提供一些必需的知识让您自己回到办公室用当天的语言开始从事生产性的工作。

动机

在大学计算机科学的课程中,绝大多数的课程都没有任何对程序设计的介绍。更准确地说,他们都假设这些学生对其中的某种语言已经有足够的基础,因此一堂系统或者网络的操作课程很少有时间来训练编码的设计或者易读性。学生们会因为在某个周期顺利地解决难题而得到奖励,而并没有因为编码的设计而奖励的。

不要让我受到错误思想的影响,计算机科学家们都很赏识优雅的代码。我不认为软件工程的教授们都特别欣赏代码的简洁。但是这种欣赏并不是一定要求代码易读或者简洁。我们通常认为优雅的算法或者技术的优雅比代码的易读性和结构具有更高的价值。

人们已经认识到,重视编写正确的代码而不是让代码变得更漂亮一些的想法不仅仅只是在大学才存在的。在行业中也存在,更让我惊慌的是在编程竞赛中也能看到这种现象。看一下在 ACM International Collegiate Programming Contest 世界决赛的的评分摘录:

"小组的成绩根据解决问题的多少来决定。排列在前十二位的小组解决了相同数量问题的,再根据使用总时间最少来决定第一名,如果需要,还可根据最早提交最后公认运行的时间来决定。"4

没有任何关于干净代码的奖励。我意识到“判断”代码的优雅性和易读性并不是一件很容易的事,事实上是非常主观的看法。即使您争辩说编写优雅的代码可能会让您更快地解决问题,但是我想现在还没有研究这个问题的学科。我的观点是,作为重要的编程比赛,干净的代码是经常被忽略的一个因素。

提高我们编码质量

因此,很多人会责备我们为什么会编写如此多不干净的代码。我们应该怎样做呢?我建议有以下三点:

  1. 把编写干净代码作为您个人过程的一部分。
  2. 讲授如何编写干净代码。
  3. 重视干净代码。

现在我将对这些稍做解释。

把编写干净代码作为您个人过程的一部分

Agile 社区会挑选出保持干净代码的价值来作为他们原理的一部分,其中原则之一是:

持续关注技术上的卓越的和良好的设计可以增强敏捷性。 5

比如在极限编程(XP)不断的重构实践中这个原理就会十分明显。人们通常认为从事XP小组的程序员在每次工作的时候都会花一定的时间尽可能地使代码保持干净。不允许走捷径,当然干净也不会被重视和得到奖励。当然,这是在假设这个小组确实遵循了XP的实践的情况下进行的,即使最终期限已经迫近。但是这不能保证当时间已经迫近时,这个组织的文化不会反过来与美洲鳄鱼进行搏斗。

如果您能使重构与编写很好的注解作为您个人过程的一部分,您会发现您不可能用任何其它方法来编写代码。您应该考虑整理代码和插入注解的时间,从而保证您的评估正确而合理。6

讲授如何编写干净代码

编写代码就像从事其它工作一样。它需要练习、批评和更多的练习。Richard Gabriel 在Writers' Workshops & the Work of Making Things: Patterns, Poetry...中提到。7 这本书里讨论了很多写散文、写诗和软件代码的相似之处.在教室里把各种形式的写作看作一种艺术,并坚持用协作的技术来练习是一件很困难的事,但是无论怎样教师能够将软件编码训练提升到一个艺术的水平还是一件很值得做的事情。

为了写得更好,我们必须能够更好地理解。在精通一门语言之前,我们必须了解如何阅读一种特定语言的标准的和习惯用法。阅读和编写代码没什么不同。我们必须学习这种语言并且了解如何很好地使用。那么如果我们要想成为很好的代码编写者,首先就必须成为很好的读者。我从没花费足够的时间来要求我的学生去阅读代码,并且对它的质量和优雅性进行反思和讨论。曾经与我一起工作而且我引以为荣的一位软件开发者是一个广泛阅读代码的人。他通过阅读各种项目的代码来学习如何更好地编程,然后思考自己如何来提高自己的编程水平。

有些学校——非常少——开设一些课程并设立类似于 软件工作室这样名称的研究会。在这些课程中,学生们像艺术家和作家一样汇聚在一起相互分享他们的工作和经验。他们自由地交流,并学习如何提出和接受一些建设性的批评和建议。我见到在我们行业中这中课程对于那些典型的自负的学生来说是一堂很艰难的课程,但是它却可以提供很好的学习经验。

今年我们在WPI举行了一次编码 dojo (dojo:是日本为文科学生提供的一个正式的训练大厅)。这个编码 dojo 与我今年夏天参加的一个 Agile 2006 会议有点像。8 我前面我引用的列表2的代码就是在最近一次的会议上选取的。编码 dojo 代码会议的唯一问题就是时间太短。但是 dojo 确实是一种很好的让人们在他们的工作中对干净代码编写技术进行思考与合并的方法。它可以在任何地方举行,并且可以是公司里的一个极好的午餐时间的活动。

许多大学对此课程的分配都比较少,也正如我前面所说的,代码的优雅性和易读性事实上并没有受到很高的重视。但是作为教育者,我们要找到提高学生代码编写基础的方法。比如,我们要使他们维持现有代码的基础并对其进行扩展。当他们编写完代码之后,能够感觉得到那些编写有缺陷的代码带来的痛苦,并知道这些代码的生产力如何。在去年,这种情况我的学生们曾经遇到过,所以今年我意识到项目的代码质量有必要加强的问题。

当我给我的软件工程学生一些基本代码并且他们也使用了,这些代码是由我的面向对象分析和设计的学生所编写的,不到一个星期,他们就能够有效地使用了。结果很令人满意。这是去年从没发生过的情况。对 OOAD 项目评分的一部分——每周给一次分——就是以他们的注解和代码风格为基础的。

重视干净代码

如果您是一位管理人员,您必须确保您的下属能够理解您的价值观念。保证您的开发人员了解代码的质量和优雅性对您是至关重要的。当最终期限迫近时,要支持团队并为范围管理而努力,不要仅仅为了在期限内完成工作而交付差劲的代码(通常是武断地作出判断)。

寻找几种好的方式来宣扬因为编写优质的代码而奖励的行为。奖励并不难执行。您的团队不久就会意识到什么才是您所重视的,他们也将全力以赴并根据这些价值观来编写代码。尽管有很多大的公司并不支持那些价值观,但是从长远来看您的团队将会一直坚持这种观念,因为简洁的代码将会长久地支持他们的工作。

结论

我希望这篇文章已经让您开始考虑干净代码对您系统的重要性。我也认识到我们应该寻找测量干净代码价值的方法。我将在以后的专栏中讲述测量标准。

注释

1 查看http://www.podcastdirectory.com/podcasts/2918从这个会议中找到这个以及其它的网络广播。

2 查看 Rational Edge 中文版 2006年2月刊的“教学软件开发与软件工程”;以及 Rational Edge 中文版 2006年3月刊的“软件开发 101”。

3 如果您打网球,记分大概就是您理解的那么回事,但是当我们开发代码时,发现在比赛、规则以及比赛记分中有一些相当复杂的情形。查看 http://en.wikipedia.org/wiki/Tennis#Scoring对整体进行一个简短的回顾。

4http://icpc.baylor.edu/icpc/finals/About.htm,可以从 ACM-ICPC 的主页上找到。http://icpc.baylor.edu/icpc/finals/default.htm

5 参见http://www.agilemanifesto.org/principles.html

6 参见2004年8月个人过程的专栏: http://www.ibm.com/developerworks/rational/library/content/RationalEdge/aug04/5585.html

7 Pearson Education,2002年出版,ISBN 020172183X。

8 查看 http://wiki.agilefinland.com/?CodingDojo 找到一些关于编码 dojos 的信息。


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=188328
ArticleTitle=Rational Edge: 编写干净的代码
publish-date=01152007