内容


设计债经济学:描述软件维护性问题的原因,成本以及改善的词汇

Comments

在许多的应用软件开发团队中,团队成员连续的选择,操作,以及实践可以对代码的维护性造成负面影响,进而影响到总体的代码质量。在这些问题得到识别和重视之前,解决它们将会变得越来越困难,执行更改以及开发员资源消耗变得越来越大。而且,就算代码维护性得到了解决,缺陷复发的风险也得到了增加,因为不适当维护后的代码变得更加的脆弱。

本文强调了代码维护性对于程序所有者以及开发团队的重要性,描述了忽略代码维护性问题会出现的结果的问题,试着在问题出现的地方引入一种适度的危机感,并呈现可行的解决方案。

设计债以及代码可维护性

在代码维护性问题存在的地方,很有可能使用者和旁观者在很长的时间内并没有察觉到问题的存在,因为维护性问题是程序内部的问题。必须承认,当组成程序的代码的内部结构不适应更改,或者很难追踪时,在外部系统可能还会很好的履行它的职责。

在本文中,我使用了一个金融比喻,设计债(Design Debt),以显示代码维护性的极端重要性。这个比喻强调不具维护性的代码成本较高,特别是在执行的更改远不是表面上那么简单时, 以及需要训练新员工担任程序的维护和开发工作时,成本会更高。设计债从广义上来说,是指程序代码由于包含了大量重复而出现的问题到了什么程度,理解什么时候出现的问题过于复杂,或者极端的困难。设计债的比喻超过了描述不具维护性代码的能力(例如,付息)。它还强调产生不具维护性代码(取款),以及那些改善代码可维护性的操作(还款)。

当开发团队对代码质量操作不在行,不负责或者不关注时,设计债问题就会产生。如果团队由于时间限制因素或者其他不能改变的影响,不能够创建或者坚持代码质量最佳操作时,问题也会产生。一般来说,在项目已经开始了一段时间而不是刚开始时,代码质量最佳操作会变得更难维护。

解决方案

如果想要设计债问题得到解决,可以采用一个三步的方法。

首先,设计债问题必须得到承认,列举和监控。

接下来,因为设计债问题可以停止,所以开发团队必须获取书写更具维护性的代码的能力。为了达到这一点,必须在团队中培养质量文化,使得每一个成员都拥有技巧,并对确保高质量,可维护的产品的最佳操作负责。应该更加关注内部设计以及程序的结构,而不仅仅是功能性需求的外部实现。客户和团队的领导层应该意识到并参入其中,团队支持,有权并承担责任已建立重视质量的文化氛围。

第三,已存在的设计债问题必须得到减少。程序必须与高维护性的代码离得更近,要么通过改善软件的可维护性,要么通过用更具维护性的代码来替换它。虽然后一种方法听起来需要更大的工作量,但是事实并不是总是这样。当设计债十分严重时,重写代码的出问题部分,要比试着修复它更快,风险性更小。如果使用其他方法,虽然程序的内部可能得到了改善,但是外部的功能性却没有变化。

执行一些方案的推荐策略

上面描述的代码维护性的推荐解决方案,是旨在建立一个软件质量独特文化技术活力战略。这项战略会在文章的剩余部分中进行讨论。

面对设计债问题

设计债从广义上来说,是指程序代码由于包含了大量重复而出现的问题到了什么程度,理解什么时候出现的问题过于复杂,或者极端的困难。设计债这个比喻最早是由 Ward Cunningham 在他的 OOPSLA 1992 经验报告1中使用的,他在文中使用一个临时过失来描述普通操作以加速开发。Martin Fowler 在Refactoring2中对其做了引用。 Joshua Kerievsky 在 Refactoring to Patterns 3,4中对设计债做了详细介绍。

不管何时我们在处理代码时,人们大多对程序的维护性不怎么感兴趣,这就会导致设计债问题的出现。以上每一项都会加大我们正在处理的项目与高维护性代码之间的距离。

设计债拥有它的位置

设计债实际上拥有它的位置。知道产生过失是正确的事情,做一笔小的取款可以帮助缓解短期的时间和/或资源压力。不管何时我们意识到过失问题的发生时,我们都应该获取取款以及日程安排的记录。追踪工具例如 IBM®Rational®Team Concert ,使得创建,分类以及重新安排设计债工作项变得更加容易。

未管理的设计项

更加具有关注性,可悲的是更常见的,是没有承认和没有管理的设计债。就像设计债是金融比喻一样,服务设计债的成本由于代码维护性的影响也在不断增加。每一次我们必须更改或者添加功能性时,或者每一次我们必须适应开发团队新加入的新人时,我们对设计债的兴趣会更大。

虽然这只是一种比喻,但是设计债的实际底线成本也不能被忽略。作者和软件咨询员 Joshua Kerievsky 帮助解释了设计债的字面真意。这种引用时在不同兴趣的混合中进行的:

由于无知或者对“只要还能用就不要去管它”原则的坚持,许多程序员和团队在设计债问题上花费了很少的时间。

在金融领域中,如果你不去偿还一项过失,那么你就得缴纳滞纳金。如果你不去缴纳滞纳金,那么你就得交更高的滞纳金。你不还的款项越多,你的金融状况就会变得越糟。复利随着时间而增加,于是摆脱过失成为不可能完成的任务,这就是所谓的设计债。5

根据我的经验,以及其他的行业轶事,最常见的未管理设计债原因包括:

  • 时间压力
  • 缺乏技巧,无知,或者缺乏热情
  • 隔绝或者失去联系的团队/缺乏质量回馈
  • 缺乏标准
  • 程序员和管理层对改进代码持怀疑态度,因为害怕会引入新的问题:“如果它还没彻底坏掉,就不要管它”。

在没有管理时,就算是很少的一部分过失也会很快的累积,并产生更大更广泛的问题。当一个开发团队不去关心代码质量问题并为此承担责任时,一旦有大笔款项取出,那么团队就很有可能,陷入无法控制的设计缺陷问题之中。

怎样面对设计债

如上所述,处理设计债需要三步的方法:

  1. 列举并追踪过失
  2. 停止外泄(停止取款)
  3. 处理(减少/消除过失)

追踪设计债

一旦设计债的问题得到了承认,那么过失就应该得到记录,不管它是担负的还是识别的。积压的问题应该得到监控,项目和过失的偿付应该得到处理,就像功能性缺陷的处理是在计划之中的。

像 Rational Team Concert 这样的追踪工具,是追踪设计债的最有效方式,因为它们向设计债积压提供报告和可视性,而且它们支持分配过失项目和执行付款所需的工作流程。Rational Team Concert 也为过失项和它们的处理提供了合作:这可以对所有参入的开发员都变得十分有用且具有教育意义。

追踪设计债所需的缺陷追踪器应该可以很快且很容易的使用,而且适应快速的获取。如果使用的追踪器很难使用,太过严格,或者它“延后”,那么不管碰到它设计债都不会被获取。如果适应这种设计债的快速获取,那么使用来自客户和测试员的单独缺陷追踪器可能也是合理的。

设计债可以通过标记“设计债”,或者使用不同的工作项类型,来进行分开处理。如果客户和测试机构不希望对设计债活动有稳定的可视性,这就可以变得十分有用了。因为设计债在本质上是技术性而不是功能性的,这些活动对于非开发员来说可以是非常“烦人的”。理想条件下,这样做的意图并不是对客户隐藏设计债,我会在稍后的文章中对它进行讨论。在任何的情况下,如果设计债要被管理和追踪,那么开放团队必须不带任意性质的恐惧,犹豫或者抵抗,去获取设计债记录。

停止外泄(停止取款)

当任意的团队开始意识到,继续取款会招致更大的设计债,那么他们需要做的第一件事情,就是控制取款。团队必须拥有书写更具维护性代码的能力和义务。

培养软件质量的文化氛围

为了做到这一点,软件质量的氛围必须在深入和围绕所有团队开发活动进行培养。这种氛围必须在设计债存款很明显的地方得到创建,而不是接受为规范。必须更多的关注代码的内部质量问题,而且交付优良性的定义必须得到扩展,这样它就包括了维护性,而不仅仅是对功能性需求的交付。

今天,这样一种文化通常是由这些活动6(或者更多)进行标记的:

  • 测试驱动的开发(TDD)
  • 持续的重构(一般通过 TDD 进行)
  • 持续的集成
  • 坚持代码标准
  • 设计模式
  • 领域驱动设计
  • 同行评审
  • 思考以及学到的经验

为了阻止团队进行未受控制的取款,需要授权选择最佳操作,并使其他项目也可以访问它们。

初步测试好的起始点,是决定团队采取哪一种操作(更规范的说,是重新采用),然后决定角色,责任,方法以及工具支持7。这里有很多程序,特别是合法的程序,在同一时间去处理它们可能是不现实的。有一些操作很难应用到没有使用操作书写代码的实体中。因此,在组件到组件基础上合适使用操作应该得到我们的考虑。

整体分析的技巧

我们不应该把技术技巧当做程序框架, Java™Database Connectivity (JDBC),以及 Servlets,作为开发员的关键技巧。我们必须进一步鼓励,支持,并需要“软技术技巧”的发展,因为该技巧支持质量和高维护性代码的文化氛围。在这些技巧中,重要的是写出可读的代码,敏感的代码嗅觉8,评价设计模式,除了以上提到的,还有 Test Driven Development。

团队应该分类对成功很重要的技巧,并通过进化,监控,学习的过程支持这些技巧的发展。团队成员一般包括业务培训和技巧培训方面的技巧。

敏捷方法学和操作

建立质量文化氛围的最有效方式,是通过采取规范的敏捷方法学进行的,像 OpenUp, RUP@Scale, Scrum, Extreme Programming (XP)或者 Eclipse Way。客户和管理的全面参入和支持,对于这种采用是十分关键的。投资的技巧也是必要的,但是值得尝试。一些像 Rational Team Concert9这样的工具,应该很好的考虑。今天,以教育,会议,团队,文章,咨询员,教练或者更多的格式,可以来支持敏捷实践。

采取的规范操作是不可能的,从开发团队一部分的被选择敏捷实践中获益仍然是值得的。提高的质量,以及对质量的热情就是必然的结果了。有很多以技术第一开发员开始的敏捷实践的许多轶事,这些开发员开始以这种方式执行选择的敏捷实践。

程序框架的角色

有很多种可用的程序开发框架,它们大多数是开发员,这对避免重复,保持层状结构,以及促进可测试性都可以变得十分有用。它们对采取有用的程序技术也很有帮助,这些技术包括 Aspect Oriented Programming (AOP)和异步 JavaScript™ 还有 XML (AJAX)。这些框架的范例包括 :

  • Spring10和 Google Guice (Dependency Injection)
  • Spring-AOP 和 AspectJ (Aspect Oriented Programming)
  • Hibernate 和 iBatis(对象/关系映射,数据库抽象)
  • JavaServer Faces (JSF)执行,以及像 MyFaces, Ajax4JSF, RichFaces,和 Facelets 这样的插件。

使用像这样的框架,可以极大的提高长期程序的可维护性和质量11

治理

一旦操作和工具得到解决,它们应该 变成批准的决定;应该创建一个负责任的框架,包括报告和监控。任何接触代码或者监管代码的人,必须负责以确保根据公司规定来执行工作。根据 Jeanne W. Ross 和 Peter Weill:

管理是对决定权和责任框架的分配,以鼓励 Information Technology12中预期的行为。

应该考虑管理的角色,以确保软件质量文化氛围的长期稳定坚持。通过使用团队规定来使团队成员负责,团队是在一定的范围内运作的,以确定他们认为什么对他们的程序是正确的,什么 对他们的客户是最好的,什么进行软件质量操作。如果存在一种文件结构,或者高层次结构的技术性领导实体,他们应该参入以确认团队的权利,并恳求他们的支持。涉及或者激发这样的技术性领导,可以获得本地团队之外的责任,以确保团队的文化得到持续,就算人员发生变动也是这样。

管理也是一种机理,通过这个机理,软件质量的文化氛围可以并且应该得到拓展。同事的项目可能会有机会从本地经验中获益。技术性领导可以加速这种共享,并且可以开始观察设计债,以及怎样处理不同的项目。通过共享轶事,论文,技巧获取方法以及文本,可以意识到合并。

引入管理和客户

质量文化氛围的普遍性应该扩展至客户。客户应该接受关于设计债经济学的概念的教育,而开放直接的对话应该受到鼓励。如果客户理解设计债,那么理解需求就变得更加容易,而且公司可以更好的避免短期时间压力造成的过失问题。

Kerievsky 使用设计债类比来与管理员进行交流:

使用设计债的金融比喻的技术问题,被证明是管理的一种有效形式。我通常都是拿出一张信用卡,并在谈到设计债时向管理员展示它的。我问他们:“你欠付你的过失已经有几个月了?”有一些几乎在每一个月都有欠账,但是几乎所有的管理员都不会让帐拖的太久。像这样的讨论可以帮助管理员们意识到,按时还清设计债的智慧所在。一旦管理层接受了不断控制设计债这种理念,那么公司构建软件的所有方式都会发生改变。一夜之间,从执行层到 管理层再到程序员的每一个人,都承认走的太快可以伤害到每一个人。现在程序员已经得到了管理层的授权去重构。重构的修补性操作使得扩展和维护变得越来越容易。当这成为一种现实之后,每一个人都从中获益,包括制作人,管理员以及软件的最终用户。13

当处理设计债开始需要更大的努力时(见上),该词汇在验证对客户和利益相关方的需要时也很有用,特别是当他们有一定的基础时更是这样。

当然,这样的对话并不需要意味着对客户交过了一个糟糕的工作。在世界上并不存在一个完全不与设计债打交道的开发团队(有时候它自己并没有意识到这一点)。再一次,设计债是由糟糕的代码维护性,以及程序的内部结构体现的,但是外部公告可能会是一种较好满足客户需求的程序。但是,我们可以通过更好的保护并指导他们的投资,来提升客户代码资源的可用性。

处理(消除过失)

设计债最明显的解决方式是“偿还”。

重构...不要停

一旦设计债得到识别和标记,通过重构进行偿付应该放在优先的位置。重构是在不变外部行为的基础上,提升代码内部结构的行为14

重构可按照下面这些方式进行,以改进代码:

  • 改善的阅读性,做出代码自我记录15,不管在什么地方都可以。
  • 建立更好的分层并有效的应用企业结构模式
  • 建立更高的测试性和更高的测试覆盖面
  • ...以及更多

持续的重构应该作为一种连续的活动进行,处理每一个开发团队不定期所做的小的故意和非故意的取款。没有连续的重构,设计债就会再一次的累积。

追踪大型合理代码基底:分割和克服

提高大型代码基底的维护性可以是十分困难的,特别是在没有分层或者可识别结构时更是这样。有效重构的一个战略,是向程序引入一个依赖注射16容器,例如 Spring 或者 Google Guice。然后,程序功能就会渐渐的抽象为服务,它是通过依赖注射来管理的,并位于合适的服务层中。通过执行这些重构,可以达到更好的分层,更宽松的耦合,以及更大的测试性。

在每一次重构之后,程序的外部功能仍然没有得到更改。因此,这种改善越来越多的在不同的版本之间可以进行执行。在重构时间不能更改时,改善结构只有一种方法。

这种方法可能与建立代码中的堡垒类似,你可以只执行重构的一小部分,以分割并克服维护性问题。每一次小的胜利都让随后的战争变得少血腥一点。

破产

提升并没有以维护性写成的代码库的维护性总是十分困难的。这是一个阻遏性的 Catch-22:代码需要变得具有维护性(只要有足够的测试覆盖范围),以安全的应用全范围的更改,但是我们不能在没有对其重构(更改)的条件下,提升它的可维护性。这就是为什么许多设计成提升程序质量的项目,没有做到这一点的原因 。

所以,当一个团队发现它有大量的设计债时,那么是时间该作出一些决定了。应该考虑一下,改进程序中已存在的代码的成本,确实要比重写它的成本高 17。在设计债的词汇表中,这样的重写可能会被比作“宣告破产” ,但是具有讽刺意义的是,这可能会是最负责任的行为,因此我们和我们的客户确实拥有过失。

重写一个程序模型并不一定要从头开始。团队对当前的执行和业务可能有大量的经验。另外,他们可能学会书写高质量,高维护性的程序,在处理这些程序时会有更好的框架和工具。

注意程序重写员通常都是不受欢迎的。设置底线就是为了避免这一点,设计债必须尽可能早的意识到并得到尊重,这样就可以不受破产的风险了。理想条件下,设计债不应该在开发项目开始的时候才进行管理。

大泥球 (BBoM)

下面就是怎样识别程序是否位于破产边缘的方法:小的改进和表面的更改都是可行的,但是大型的更改是非常困难的,通常需要 spaghetti 代码的弯曲路径的昂贵恢复。Brian Foote 和 Joseph Yoder 写了一篇关于这种状态非常著名的文章,叫做“大泥球”。 Wikipedia 将“大泥球”描述成一种反模式18:“一个没有可识别结构的系统”。下面是 Foote 和 Yoder 的定义:

所谓的大泥球就是一个偶然结构的,伸展的,邋遢的, spaghetti 代码的混合。这些系统显示了无规则发展,重复式临时修复的符号。信息在系统的各个元素之间得到很好的共享,几乎到了所有重要信息都变成全球化或者被复制了。系统的总体结构可能从来没有被定义过。如果它被定义了,它也可能被模糊到不能识别的地步。拥有结构性嗅觉的程序员避开了这片沼泽。只有那些不关心结构,还可能对日常繁琐的打补丁工作很满意的人,才会对在这样的系统上工作满意。19

Wikipedia 关于大泥球的条目,还对其做了很好的描述,并提出了有建设性的意见:

控制大泥球的程序员得到鼓励去学习它,并去理解它是怎么工作的,以及使用它作为新的优良结构的系统的规范系列的需求,提供了一个宽松的基础,开发的新的优良结构是为了替换以前的结构。技术变更(客户服务器到基于网络,基于文件再到基于数据库,等等),为从头开始提供了一个好的原因。20

总结

长期以来对代码维护性问题的冷漠、无知、无为,造成了巨大的损失。在弄清长期代码质量问题的成本,原因以及处理,甚至与管理层,客户和同事之间的坦率对话,也有很大的帮助。

为了解决代码质量问题,通过全面的技巧战略,软件质量操作,以及使用被证明能够促进软件质量和维护性的框架,培养软件质量的文化氛围是十分必要的。

有时,当代码维护性问题不能得到解决时,就必须作出快速的决定了。团队越快开始管理设计债,它们避免支付不喜欢付的利息的可能性就越大。Thomas J. Watson,从 1949 到 1956 年的 IBM 公司主席,以完美的简洁性描述了这个真理:“好的设计就是好的业务” 。

作者的笔记:

我写这篇文章的原因,是因为我总是发现自己试着表达节省短期花费所做的长期花费决定,我想要对这些讨论引入一些有意思的论证,并支持软件开发操作更具前瞻性的内容。在做这一点时,我也试着提供软件质量操作最集中的团队文化的概图。

The Rational Edge 上文章公布后不久,我拷贝了 Clean Code; A Handbook of Agile Software Craftsmanship21, Robert C 所做的新书。(“Uncle Bob”) Object Mentor, Inc 的 Martin 和其他的作者。

Clean Code 的开始处, Uncle Bob 处理了 “The Total Cost of Owning a Mess”,它所做的讨论与本文中的设计债比喻完全相匹配。从这里开始,他和其他的合作作者将会继续提供代码质量问题的具体,复杂的讨论 。

我强烈推荐完全阅读Clean Code。如果你在一个开发团队中,并在很多地方赞成本文中的观点,那么你可以寻找更具体实际的建议。如果Clean Code属于你的阅读列表的顶部附近,那么你可以从这里开始继续阅读。

注意

  1. http://c2.com/doc/oopsla92.html
  2. Martin Fowler,Refactoring,Addison-Wesley Longman Inc., 1999,p. 66。
  3. Joshua Kerievsky,Refactoring to Patterns, Pearson Education Inc., 2005, pp. 15-16。
  4. Kerievsky (2005)的范例章节,包括设计债以及人类可读代码的章节,网址为 http://www.informit.com/articles/article.aspx?p=360842
  5. Kerievsky p. 16。
  6. 许多这样的操作在 Open Source 和 Agile communities 中得到开发和证明。有时它们会被引用到“方法”,但是意识到操作可以是更广泛敏捷方法学的一部分 。换句话说,每一个敏捷方法 (例如,OpenUp, RUP@Scale, Scrum, Eclipse Way, XP),描述了操作的选择,还有特定的过程指导。不论如何,操作都可以提供高质量高回报的软件,不管是否采用它们自己的方式,或者作为更广泛,更规范方法的一部分。
  7. 执行静态代码分析的工具,像 IBM Rational Software Architect 和 IBM Rational Software Analyzer,可以识别代码中的共同问题,并在很多种情况中,可以通过提供应用简单命令菜单的“快速修复”,来得到快速的解决 。
  8. 代码感觉是代码中可维护性问题的指示符:http://c2.com/xp/CodeSmell.html。在网上的代码感觉中有很多参考,在 Fowler1999 pp 75-88, Kerievsky2005 pp 37-45,以及 Martin2009 pp 285-315 中也有很多。
  9. 使用 Rational Team Concert 的敏捷团队,可以从包含的过程模板中的指导获益匪浅。Scrum, Eclipse Way, OpenUP可以得到支持。
  10. JSF 和 Spring 都是“轴心”技术的范例,每一项技术都采用了可以轻易访问子框架的插件结构。例如,通过编码到 这些技术的 Spring 的抽象,AOP以及宣布性交易管理还有其他部分变得更容易采用。在隐藏执行复杂性时,Spring 的抽象层也变得可以交换。
  11. 除了软件质量操作,我的经验就是你发现这些框架的地方,会频繁发现高维护性的代码,这是由对程序以及过程质量拥有技巧和热情的开发员写成的。与之相反的是,在最近的时期内,我会检索所有代码,而这些地方框架是完全不存在的。
  12. http://papers.ssrn.com/sol3/papers.cfm?abstract_id=664612 查看 Ross 和 Weill 关于 IT 管理的论文。
  13. Kerievsky (2005), p. 16。
  14. http://www.refactoring.com 处查看 Martin Fowler 的重构网址,以及 Fowler (1999)。
  15. 自我记录的代码并不是拥有大量在线评论的代码。这是一个普遍的误解,而且这确实是一个错误:伪造的评论代码是文件ed,但是是由开发员 写成,而不是代码本身。与之相反的是,自我记录的代码是观察的开发员可以阅读并轻易理解的运行代码;这样它的意图,目的以及技术是清晰且不需要额外评论的。评论是有价值而且通常是需要的,但是自我记录的代码会更好因为它保证了剩余的当前:评论可以变得僵硬而且误导,但是运行的代码不会。
  16. 依赖注入是通过使用像 Spring 这样的框架来执行的软件模式。它适应并产生了程序组件的松散组合,这就导致了更好的维护性,测试性以及总体的质量。见于 http://www.martinfowler.com/articles/injection.htmlhttp://en.wikipedia.org/wiki/Dependency_injection
  17. 我相信有三种因素证实了糟糕保存的过失驱动代码:1)预期更改的低积压和低容量,2)开发和维护很少需要开发员,以及 3)低的员工利用率。如果所有这些项目继续保持非常低的状态,那么对过失所付的利息也变得很低。
  18. 另一个反模式,是普通重现或者对一个问题糟糕的解决方案。见于 http://en.wikipedia.org/wiki/Anti-pattern(这里列有 BBoM )。
  19. Foote 和 Yoder 所写的 Big Ball of Mud 论文可以在网上通过以下网址访问:http://www.laputan.org/mud/
  20. http://en.wikipedia.org/wiki/Big_ball_of_mud
  21. Robert C. Martin,Clean Code: A Handbook of Agile Software Craftsmanship, Pearson Education Inc., 2009。

相关主题

  • IBM Rational 敏捷开发工具包:本工具包将帮助您了解 IBM Rational 为敏捷开发所提供的技术和解决方案,以及最佳实践。帮助您更好地运用 IBM Rational 软件实施敏捷开发,将敏捷开发的实践落到实处。
  • 查看 Rational Edge 电子期刊 其他精彩文章,获得了解高效软件开发背后的概念。
  • 访问 developerWorks 上的 Rational 软件专区,了解有关 Rational 软件交付平台产品的技术资源和最佳实践。
  • 了解 IBM Rational 软件交付平台,包括适用于并行开发和地域分布式团队的协作工具,以及用于架构管理、资产管理、变更和发布管理,集成需求管理、过程和组合管理,和质量管理。
  • 订阅 IBM developerWorks 时事通讯,获得有关最佳的 developerWorks 教程、文章、下载、社区活动、网络广播和事件的每周更新。
  • 浏览 技术书店,获得有关这些和其它技术主题的书籍。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=413624
ArticleTitle=设计债经济学:描述软件维护性问题的原因,成本以及改善的词汇
publish-date=07152009