编写干净的代码

文档选项

将此页作为电子邮件发送


拓展 Tomcat 应用

下载 IBM 开源 J2EE 应用服务器 WAS CE 新版本 V1.1



本文来自于 Rational Edge:看看软件开发人员在代码编写工作中为什么需要学习代码的优雅性,结构以及效率方面的内容。

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

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

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

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

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

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

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

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

列表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对整体进行一个简短的回顾。

4 http://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 的信息。



参考资料

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时