作为极限编程实践的重构 是一项强大的技术,用于通过一种严谨的方法重构源代码使软件熵最小化。重构使源代码更易于理解和维护,并使其运行得到简化,从而可以确保系统的功能保持不变。通过使用自动化的重构工具,程序员可以最大限度地减少烦琐的记录活动,并将精力集中于“实际”的编程,从而提高了工作效率和代码的可靠性。
开发复杂的软件应用程序是一项物流工作,它必须根据严格的日程安排对有限的资源进行分配,以满足资源密集型活动的需要。重构和开发都是以这种方式操作代码的方法,但两者存在一个根本的差别:代码设计旨在增添功能,而重构是通过重新设计现有代码的内部结构来简化现有代码。根据热力学定律,软件系统或工程的熵将随时间的推移而增加,因此如果不对软件进行重新设计以维护其性能,那么软件的性能将会降低。因此,设计意味着添加新功能,而重构则通过维护现有功能的体系结构操作来抵御软件熵。重构用于克服不必要的复杂性、更改要求、体系结构限制、性能较差/性能降低的代码以及对复杂系统的片面理解。
自动重构是一个强大的工具,使开发人员能够实时地重新构造/简化源代码,以便程序员能够安全的重新设计代码,同时保持功能不变。因此,重构通过严谨的防错方法学改进已编写代码的设计。该方法对于软件设计、开发和维护具有深远的意义,这是因为源代码:
- 可能是在数分钟或数年前在某个地方编写的。开发和维护具有前瞻性,以前编写的旧代码可以回收到当前项目中。
- 可以随时优化和安全更改。设计和维护可以相互转换,且度量“受攻击代码”是生成高效行业代码的可行基础。
重构的好处
在集成到强健开发环境中的重构工具(例如,Oracle JDeveloper 10g 现在可以使用重构插件,不久该产品自身将支持重构)的支持下,可以考虑并切实地进行代码转换和开发,而在不具备重构工具的情况下,转换和开发代码比较费力或消耗过多的资源。通过执行重构操作(确保系统的行为保持一致,并使设计得到巩固),即便是对于大型代码库也可以迅速地进行一致的更改。
将重构和开发工具组合到一个平台中的优点将通过鼓励开发过程中的重构在整个开发生命周期内辅助开发人员。尽管这显得有些微不足道,但正如小溪可以侵蚀高山一样,不断进行小型重构可以简化代码和改进设计,同时确保功能一致,从而可以显著改善您的环境。将重构与开发结合在一起可以使项目得到不断地改进,这是因为通过实时地修改功能和结构设计可以实现增强。
重构还提供了极限编程的优点,具体体现在:
- 使用结构良好的代码增强了系统的可管理性,从而降低了成本并使有限的开发资源得到有效地利用
- 通过允许不引入错误的代码“演练”提高了程序员的理解能力,从而增强了评估外部代码和执行更改的信心
- 快速简化代码以优化性能,以及在要求发生变化时重新设计体系结构
- 回收已测试的高质量代码,从而使开发人员能够将精力集中于新的编程而不是进行重复的工作
- 使开发人员可以团队方式工作,并在不同的学习、测试、开发和质量保证平台中负责相应的代码部分。
因此,当开发软件项目时,重构有助于回答以下基本问题:
- 该项目存在的原因是什么?哪些人担心(或更希望)它不存在?
- 该项目预计产生什么商业结果?对此有多大把握?
- 实现这些结果的关键是什么?为确保按预期的方式实现这些结果,需要投入多大精力?
从本质上讲,将 Oracle JDeveloper 10g 与重构工具结合在一起(参见图 1)使得只需进行最低限度的维护便可以将已测试的代码回收到工程中,并将概念验证(受攻击的)代码转换为合理的行业级版本。
图 1:RefactorIT 和 Oracle JDeveloper 10g |
重构源代码的关键在于通过灵活的操作,而不是硬性地遵守可能错误和不完善的体系结构来完成设计。因此,重构维护了系统功能并允许实时地改进代码,从而避免了开发人员盲目地因循先前的设计、维护不适当的代码以及不得不拒绝原始体系结构以外的改进。重构在各个阶段都会给软件项目带来影响:
构建阶段:
| 操作阶段:
|
维护阶段:
| 回收阶段:
|
程序员将重构用作完整的生命周期平台工具,以学习、评估、测量、建议、测试、识别、描述和交流与源代码有关的元数据信息。因此,程序员不断重复以下任务:
发现问题
是否存在问题?存在什么问题?
如果能够测量它,那么便可以管理它;但通常情况下,识别要在软件开发和维护过程中重构的“腐化”代码与其说是一门科学,不如说是一门艺术。与构筑桥梁不同,构建软件应用程序时如果缺少物理基础架构将防碍定义和检测。例如,您可以解决客观和主观的质量测度,如:
- 年龄、身高、建筑面积、结构、位置和环境(用于评估建筑物)
- 速度、功率、底盘、颜色、转矩、汽油公里数和款式(用于评估汽车)
- 功能、接收、布局、颜色、声音清晰度和样式(用于评估移动电话)。
软件审计和度量的用途只有一个:封装足够的用于预测外部质量的信息(用于识别高风险代码);度量只是从数量方面描述了系统。然而,当评估软件时,诸如代码行数、函数点、方法数和圈复杂度等测度对于评估正在运行的软件应用程序的质量或复杂性并不充分。对于评估代码时应测度哪些内容并不存在共识,这是因为质量,正如 Walker 和 Kitchenham 在 1989 年的 Software Engineering Journal 文章中所描述的那样,“很难定义、无法测度但易于识别”。因此,要识别应重构的代码,需要将一组度量、审计和高级工程经验与相应的技术(如由马里兰州大学的 V. Basili 和 H.D. Rombach 开发的目标/问题/度量 (GQM) 范型)结合在一起。
收集度量的目的不是为用户指定一组正确的度量或武断地确定一个方法;度量、审计和模式实际上是通过各种标准或测度来评估软件的手段。因此,组织应选择适合其系统的方法和度量以满足其要求,并在使用评估代码时遵守以下原则:
- 评估软件时任何单一的度量或审计都不能解决问题,而度量过多则可能导致信息过载。精心选择一个由 4 到 10 个测度组成的子集有利于评估应用程序的状态。
- 应经常进行测量并记录结果,以便生成一个用于跟踪系统演变的时间序列图。
- 有时,应记录和分析一个完整的度量(30 到 40 个不同的测度)快照,以便可以比较可提交的里程碑以及识别有效的度量。使用时间-日期命名结构保存这些快照,以用于参考和日后分析。
- 您可以随意更改所用的测度,以评估质量、复杂性或项目状态。不同的阶段需要不同的测度,因此完整的度量集分析应表明哪些度量与特定项目的实际情况相关。
- 软件是一个物理系统,因此变化普遍存在。所有度量都会存在误差。
- 因此,度量不是万能的,只能将其用作导向。如果管理过于依赖报告数字而不是生成代码,则程序风格可能(并将要)改变,从而促生 Hawthorne 和 Heisenberg 效应。
问题定性
为什么必须更改代码?好处是什么?是否存在风险?与检测类似,问题定性涉及确定错误所在并将该问题转化为一种可以更正的模式,以便结果不会比当前状态更糟。当决定是否应重构某个代码片段时,应确定这样做是否劳有所得。使用集成的自动重构工具,重构可以顺利进行,并可以随时取消。
设计解决方案
代码的“目标状态”是什么?哪个(哪些)代码转换将使代码达到所需的状态?分析源代码时,您应记住项目的“大致”状态,以便当某个代码部分腐化时,可以清楚地确定所需的清理级别。有关解决方案设计的示例,请参考 refactoring.be/thumbnails.html 中由 Sven Gorts 和 Philipe T'Seyen 的作品。
修改代码
当发现一个已腐化的代码片段并找到一个替换代码时,便可以执行、测试和分析更正此代码的转换,以测量改进。
测试代码
为确保代码仍按照预期的方式运行,必须在每次进行主要更改后运行测试。如果您的项目中尚未使用单元测试,则 Oracle JDeveloper 10g 可以自动生成大部分单元测试代码。
实例
为演示这些步骤,我们将使用 JDeveloper 和 RefactorIT 逐步完成这些步骤以重构一个示例应用程序。
我们设计了一个具有三个类(Customer、Order 和 Register)的应用程序。可以在此处下载这些类的源代码。
有问题的代码部分位于 Register.java 中。
客户的全名创建代码根本不应出现在此处,但遗憾的是,许多开发人员为求快速完成工作而将类似的错误代码拼凑在此处。
现在,为解决问题,我们必须将所有内容各就各位。我们首先将客户的全名创建代码移动到 Customer 类中。
我们提取以下方法:
图 2:提取方法 |
然后,将新方法移动到 Customer 类:
图 3:将新方法移动到 Customer 类 |
在仅仅执行了几次单击操作后,我们便拥有了一个更具可维护性的代码。但我们不能百分之百确定该程序仍像以前那样运行。
这就是单元测试的用途所在。在重构前,我们使用了 JDeveloper 的 JUnit 支持,它是免费的 JDeveloper 扩展。测试用例检查是否正确创建了客户全名。(参见图 4)。
运行测试套件。
图 4:使用 Oracle JDeveloper 的 Junit 支持测试重构操作 |
图 5:检查以确保代码的外部行为未被更改 |
使用工具支持的重构操作和自动化单元测试,不出一分钟便可以执行和验证更改。在包含数十个、上百个或上千个类的实际项目中,这在时间的节省和质量保证的改进方面非常明显。
以上示例使用了两个重构技术“提取方法”和“移动方法/域”。以下是更多的重构操作示例。
重构操作
参考refactoring.com/catalog/index.html 以获取 90 多个不同重构操作的列表;参考 refactoring.be/thumbnails.html 以获取 UML 图表;参考 refactorit.com/index.php?id=1370 以获取描述列表。
重构 | 描述/优点 |
重命名 | 重命名功能用于重命名任何程序包、类、方法或变量,并自动查找/更正对它的所有引用。对于任何已重命名的项,您可以在方便的树结构中预览所有引用、选择要重构的使用/引用并在 JavaDoc 注释、xml 和其他文本文件中搜索所有名称的出现位置以使其保持最新状态。可以从任何视图(如 Project、Source、Commander 和 Structure)中调用重命名重构。 |
移动类 | 移动类功能使您能够通过将类或接口移动到其他程序包中来管理项目结构。RefactorIT 自动更新所有引用,从而节省了您的时间和精力。 |
移动方法/域 | 移动功能使您能够将类中声明的方法或域移动到其他类或接口以便管理程序。同样,RefactorIT 自动更新所有引用,从而最大限度地减少了维护和错误。 |
在层次结构中向上移动/向下移动 | 要重新安排项目的层次结构,可以将域和方法“上移”到超类,以及将代码下移到子类。此功能使您能够精简项目以获得最佳性能。 |
提取方法 | 此提取功能分析选定的代码,并将其传输到独立的方法中。这有助于程序的模块化,从而可以将代码分解为可管理和可理解的多个部分。 |
提取超类/接口 | 您可以选择现有方法和域,并将其提取到一个新的超类或接口中。同样,这可以帮助程序员维护程序员友好和高效的面向对象的代码。 |
引入解释性变量 | 此功能使您可以将表达式的结果或表达式的某些部分赋予一个其名称能说明其用途的临时变量。该功能可以帮助将长表达式分解为可管理的小片段。 |
添加代理方法 | 使用此功能可以为给定域创建代理方法,从而增强模块化,为程序员创建友好的应用程序。 |
覆盖/实现方法 | 此重构使您能够为超类添加实现方法。当通过覆盖继承方法或子类的实现添加功能来增强方法时,此重构很有用。 |
内联变量 | 此功能使用声明表达式替换变量的所有引用,然后删除比较旧的变量文本。这节省了您在重新整理代码时的时间和精力,并将引用错误减到最少。 |
更改方法签名 | 这个新重构功能组合了几个不同的修改,这些修改构成了方法签名。此方法使您能够添加、删除、重新排序和重命名给定方法的参数。 |
封装域 | 此功能使您能够选择一个类,并使用相应的读/写访问器方法替换直接使用的域。因此,您可以轻松地更改域的可见性以及访问它们的方式。 |
最小化访问权限 | 此功能确定不同类域和方法的最小访问修改量。RefactorIT 将自动更改用户的选定修改量。 |
在可能的情况下使用 Super 类型 | 使用此功能,用户可以使用超类代码替换子类。RefactorIT 识别在哪个位置可以进行替换并使用它的某个超类型替换出现的某个类型。 |
http://www.oracle.com/technology/global/cn/pub/articles/pefferly_refactor.html
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/1384/viewspace-432928/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/1384/viewspace-432928/