演化架构与紧急设计:对设计进行重构

在 “测试驱动设计,第 1 部分” 和 “测试驱动设计,第 2 部分” 中,我 介绍了测试如何为新的项目实现更好的设计。在 “组合方法和 SLAP” 中,我讨 论了两种关键模式 — 组合方法(composed method)和单一抽象层原理 — 为您 的代码结构提供了整体目标。需要牢记这些模式。一旦拥有了一个现有软件项目 ,那么发现和利用设计元素的主要方法就是进行重构。在 Martin Fowler 的经典 著作 Refactoring 中,他将重构定义为 “一种严格的技术,可以重新构造现有 代码体,修改代码的内部结构,但是不会影响代码的外部行为”。重构是一种具 有某种目的的结构转换。对任何项目来说,值得称赞的一点就是拥有可以轻松进 行重构的代码库。在本文中,我将讨论如何使用重构技术来查找隐藏在代码库中 的未得到充分设计的代码。

关于本系列

本 系列 旨在从全新的视角来介绍经常讨论但是又难以理解的软件架构和设计 概念。通过具体示例,Neal Ford 将帮助您在演化架构 和紧急设计 的灵活实践 中打下坚实的基础。通过将重要的架构和设计决定推迟到最后关键时刻,您可以 防止不必要的复杂度降低软件项目的质量。

单元测试可以提供最重要的安全屏障,允许您按照自己的意愿重构代码库。如 果您的项目的代码覆盖率达到了 100%,那么可以安全地重构代码。如果尚未达到 这个程度的测试,那么草率地进行重构就会变得比较危险。本地化修改可以很容 易地应用并且可以立即看到修改效果,但是副作用产生的破坏也会使您非常苦恼 。软件会产生无法预料的耦合点,对代码的某一部分进行微小的修改会影响到整 个代码库,造成数百行代码发生错误。要安全地修改代码并找出大量错误,需要 进行广泛的单元测试。对于一个为期 2 年的 ThoughtWorks 项目,技术主管在运 行该项目的前一天对代码进行了 53 处不同的重构。他在进行重构时信心满满, 因为项目拥有广泛的代码覆盖率。

如何实现可以进行重大重构的代码库?一个办法就是不要编写任何代码,直到 您将测试添加到整个项目中。当您提出这个建议后,您将被解雇,然后您可以去 另一家重视单元测试的公司工作。这种方法可能不是很好。另一个好方法是让团 队的其他成员认识到测试的价值并开始缓慢地围绕代码的最关键部分添加测试。 做好规划并在近期内宣布一个日期:“从下周四启动,我们的代码覆盖率将不断 增长”。每次编写新代码时,添加一个测试,每次修复一个 bug 时,编写一个测 试。通过围绕最敏感的代码部分(新特性和容易出现 bug 的部分)逐步添加测试 ,那么测试就可以发挥最大的作用。

单元测试检验原子性行为。但是,如果您的代码库没有坚持组合方法的思想, 该怎么办?换句话说,如果您的所有方法都具有几十或几百行代码,并且每个方 法执行大量的任务,那么应该怎么做?您可以使用单元测试框架来围绕这些方法 编写粗粒度功能测试,主要关注方法的输入和输出状态的转换。这种方法不如单 元测试,因为不能对行为进行彻底的检验,但是总比不采取任何措施要好。对于 代码中真正关键的部分,可能需要在进行重构之前添加一些功能测试作为一种安 全保障。

重构机制非常简单,并且所有主要 IDE 目前都提供了出色的重构支持。比较 困难的地方在于确定对哪些内容 进行重构。这就是本文其余部分要解决的问题。

与基础设施耦合

Java 世界的所有开发人员都使用框架来启动开发并提供最好的关键基础设施 (不需要您编写的基础设施)。但是框架(包括商业的和开源的)所隐含的一个 危险就是:它们总是试图让您与其进行紧密耦合,这使得发现代码中隐藏的设计 变得更加困难。

框架和应用服务器都提供了 helper 类,诱使您实施一种更加简单的开发:如 果您仅仅是导入和使用它们的某些类,那么完成特定的任务将变得非常容易。一 个典型的例子就是 Struts,这是一种非常流行的开源 Web 框架。Struts 包括了 一组 helper 类来帮助您处理常见问题。例如,如果允许您的域类扩展 Struts ActionForm 类,那么 Struts 将自动从请求中填充表单字段,处理验证和生命周 期事件,并执行其他比较简单的行为。换而言之,Struts 提供了某种权衡:使用 我们的类将使您的开发工作变得非常轻松。它鼓励您创建一种类似于图 1 所示的 结构:

图 1. 使用 Struts ActionForm 类

时间: 2024-11-01 07:25:53

演化架构与紧急设计:对设计进行重构的相关文章

演化架构和紧急设计: 利用可重用代码,第2部分

简介:在使用 演化架构和紧急设计 前几期描述的技术发现 代码中的紧急设计之后,下一步您需要一 种获取和利用这些设计元素的方法.本文介绍了两种用于获取惯用模式的方法:将模式作为 APIs 进行捕 捉:使用元程序设计方法. 本 系列 的前几期主要关注紧急设计中显而易见的第一步:发现 惯用模式.发现惯用模式之后,您要 用它做什么?该问题的答案就是本期重点,本文属于由多个部分组成的系列文章的第二部分.第 1 部分 -代码与设计的关系探讨- 介绍了一种观点的理论基础,这种观点就是软件中的设计真正是指解决方

演化架构和紧急设计:利用可重用代码,第1部分

简介:识别出代码中的惯用模式后,下一步是积累和使用它们.理解设计与代码之间的关系有利于发 现可重用的代码.本期的 演化架构与紧急设计 探索代码与设计的关系,使用表达性强的语言的重要性, 以及重新考虑抽象风格的潜在价值. 通过本 系列 的前几期,您已经知道,我的观点是软件的每个部分都包括可重用的代码块.例如,公 司处理安全性的方式在整个应用程序甚至多个应用程序中可能都是一致的.这就是我所说的 惯用模式 的 实例.这些模式代表对构建软件特定部分时遇到的问题的常用解决方案.惯用模式有两种类型: 技术模

演化架构和紧急设计: 演化架构

简介: 这一期的 演化架构和紧急设计 将会解决演化架构相关的各种主题,包括设计和架构之间的重 要区别(以及如何区分两者),您在创建企业级架构时遇到的某些问题,以及面向服务的架构中静态类型 和动态类型的区别. 在 本系列的第一期 中,我推荐了软件世界中的一些架构定义.无论如何,如果您已经阅读过本系列 ,您会注意到我花费了大部分时间在设计上.我之所以这么做是基于以下几个原因:首先,在当前紧急设 计尚未被广泛关注时,软件世界里存在很多架构定义(良莠不齐):其次,在设计方面很多问题都有具体 的.不受环境

演化架构与紧急设计: 积累惯用模式

简介: 本期将之前的 演化架构与紧急设计 文章中的紧急设计概念与一个案例研究相结合,展示如何 发现.积累和利用代码中意料之外的设计元素.一旦理解了如何识别设计元素,便可以使用该知识改进代 码的设计.紧急设计使您可以发现代码中意料之外但是已成为代码库重要部分的那些方面. 在本系列第一期 "研究架构和设计" 中,我曾断言每个较大的项目都包括超出所有人意料的设计元 素.详细考虑一个问题时,常常会发现有些本以为困难的事情实际上却更容易,有些本以为容易的事情实 际上却更困难.随后的几期则演示了发

演化架构与紧急设计: 通过指标进行紧急设计

简介: 软件指标可以帮助您寻找代码中隐藏的设计元素,让它们能够成为惯用模式. 演化架构与紧急设计 的这一期讲解如何使用指标和可视化发现被复杂性掩盖的重要代码元素. 紧急设计的难题之一是寻找隐藏在代码中的惯用模式和其他设计元素.指标和可视化有助于识别代码的重要部分,从而提取出一些设计元素.本文主要讨论两个指标,圈复杂度(cyclomatic complexity) 和传入耦合(afferent coupling).圈复杂度度量方法的相对复杂度.传入耦合表示有多少个其他类使用当前类.本文要介绍显示和

演化架构与紧急设计:研究架构和设计

演化架构(evolutionary architecture)和紧急设计(emergent design)都是将 重要的决策推迟到最后责任时刻(Last Responsible Moment)的敏捷技术.在本 系列的第一期文章中,系列作者 Neal Ford 将定义架构和设计,然后指明了一些 关于整个系列的基本概念. 软件架构和设计一直都没有一个明确的定义,因为软件开发作为一门学科,尚 未完全理解其中的复杂度和内涵.但是要发表关于这些主题的论述,您必须从某 个位置开始.本系列涉及演化架构和紧急设

演化架构和紧急设计: 使用 DSL

简介:至今, 演化构架和紧急设计 主要关注技术模式的紧急设计,本期将介绍使用特定领域语言 (DSL)捕获 领域惯用模式.系列作者 Neal Ford 用一个例子说明了该方法,显示了这种获取惯用模式 的抽象样式的优势. 惯用模式可以是 技术也可以是 领域.技术模式为常用的技术软件问题指出解决方案,例如在应用程 序(或应用程序套件)中怎样处理验证.安全和事务数据.前几期主要关注获取技术惯用模式所用的技术 ,例如元程序设计.域模式关注的是如何抽象常见业务问题.而技术模式几乎出现在所有的软件中,域模 式

演化架构与紧急设计: 语言、表达性与设计

简介:发现和积累惯用模式的能力对于紧急设计至关重要.对于设计而言同样十分重要的是代码的表 达性.在本系列文章的第 2 部分中,Neal Ford 将继续讨论表达性和模式的交集,通过惯用模式和正式 设计模式阐释这些概念.他用动态语言为 JVM 重构了一些经典的四人组(Gang of Four)模式,以说明 表达性更好的语言如何使您看到被透明度不佳的语言遮挡的设计元素. 本文是本系列文章的第 2 部分,旨在演示计算机语言的表达性(允许您专注于本质,而不是形式)对 于紧急设计的重要作用.意图(inte

演化架构与紧急设计: 组合方法和 SLAP

简介:如何在陈旧的代码库中找出隐藏的设计?本文讨论两种对于代码结构很重要的模式:组合方法 和单一抽象层.对代码应用这些原则有助于找到以前隐藏的可重用资产,有助于把现有的代码抽象为成熟的框架. 在这个 系列 的前两期中,我讨论了如何使用测试驱动开发 (TDD) 帮助您逐步发现设计.如果从头开始一个新项目,这种方法的效果非常 好.但是,更常见的情况是您手中已经有许多并不完善的代码,在这种情况下应该怎么办呢?如何在陈旧的代码库中找出可重用的资产和隐藏 的设计? 本文讨论两个很成熟的模式,它们可以帮助您