一旦你冻结了设计,它就开始变得过时。 --Fred Brooks
重构是以一种训练有素的方式,以一些较小的步骤来调整代码的结构。它是采用演进 (迭代和增量) 的方式进行编程,关键是它保持了行为语义,既没有增加功能,也没有减少功能。
图2.1应用了“方法下移”重构,将calculateTotal( )操作从Offering类移动到它的子类Invoice中。还需要改变调用这个操作的代码,让它们改为访问Invoice对象。这样就完成了一次重构。
图2.1 方法下移到子类
数据库重构是对数据库schema的一个简单变更,在保持其行为语义和信息语义的同时改进了它的设计。换言之,既没有增加新功能,也没有破坏原有的功能,既没有增加新的数据,也没有改变原有数据的含义。
数据库schema既包括结构的方面,如表和视图的定义,也包括功能的方面,如存储过程和触发器。
由于数据库架构所导致的耦合度,数据库重构可能变得更加复杂,如图2.2所示。耦合度是两项之间的依赖关系的一种测量指标;耦合度越高,则改动其中一项就越可能要求改动另外一项。
图2.2 数据库架构的两种类型
单应用数据库架构最简单,可以将应用与数据库并行地重构并同时部署,通常称为独立的应用或“火炉烟囱”
式系统。第二种架构要复杂的多,因为有多个应用与数据库交互,不能假定所有的外部程序都会同时部署,因此必须支持一个转换期(过渡期),在这一时期同时支持旧的schema和新的s
c
hema。
看一个例子,如图2.3所示,将Balance列作为Customer表的一部分真的有意义吗?
图2.3 Customer和Account的初始数据库schema
以下例子描述单应用数据库环境下将一个列从一个表移动到另一个表。这是最简单的情况,可以同时重构数据库和应用源代码。
这种情况下,建议两个人一起结对编程;重构先在开发者沙盒中进行。
首先,这对程序员运行了所有的测试并看到测试通过。接着,他们编写了一个测试,可能是访问Account.Balance列中的一个值。在运行所有的测试并看到测试失败后,引入了 Account.Balance列,如图2.4所示。
图2.4 Customer和Account的最终数据库schema
他们再次运行测试并看到测试通过了。
接下来他们对原有的测试进行重构,例如存款功能测试,它最初是访问Customer.Balance,因此会失败。对存款功能进行重构,使它去访问Account.Balance列。他们对测试套件和应用中的其他代码进行了类似的变更,诸如取款逻辑。
当应用再次运行起来后,出去安全考虑,对 Customer.Balance中的数据进行了备份,然后将数据从 Customer.Balance拷贝到 Account.Balance中。再次运行所有测试,确保数据迁移安全地完成了。最后是删除 Customer .Balance列并再次运行测试,需要的话对缺陷进行修复。图2.4是最终的模式。完成这些工作后,再将变更提交到项目集成环境中去。
这种情况更困难,因为每个应用都会在不同的时间部署新的发布版本。你需要完成与单应用数据库环境相同的工作,但不是立即删除 Customer.Balance列,至少在“转换期”中同时保持这两个列。
图2.5展示了转换期中的部分数据库shcema,请注意两个触发器SynchronizeCustomerBalanceSynchronizeAccountBalance,在转换期中它们在生产环境中运行,确保两个列的数据同步。
图2.5 转换期中的数据库schema
在转换期之后,你会删除原来的列和触发器,得到图2.4中的最终数据库schema。只有在足够的测试可以确保安全时,才能删除。
当你重构数据库shcema时,需要同时保持信息语义和行为语义。
信息语义是指从信息使用者的视角来看,数据库中信息的意义。在行为语义方面,目标是要保持黑盒功能性不变--所有与数据库schema变更部分相关的源代码都必须改造,从而实现与原来同样的功能。
表2.1 数据库重构分类
与“代码味道”类似,有一些常见的数据库味道,表明可能需要进行重构,包括:
重要的一点是要理解,仅仅因为存在某种味道,并不表明它坏了--limburger干酪即使在最好的状态下也有味道。但是,如果牛奶闻起来味道不对,你就知道它坏了。如果存在某种味道,就观察它,思考它,如果重构有意义就进行重构。
数据专家可以采用类似开发者使用的现代演进式技术,并从中受益,而数据库重构就是数据专家需要的重要技能之一。
图2.6提供了一些关键开发活动的高层视图。所有的箭头都是双向的,你需要在这些活动之间来回迭代。
图2.6 演进式项目开发中的一些可能的开发活动
耦合越厉害,就越难重构。
如图2.7所示的多应用数据库架构中,你的数据库可能与应用源代码、持久框架和对象-关系映射(ORM)工具、其他数据库(通过复制、数据抽取/加载等)、数据文件schema、测试代码,甚至它自己耦合在一起。
图2.7 数据库与外部程序是高度耦合的
减少涉及数据库的耦合的一种有效方式是 封装对数据库的访问。
让外部程序通过持久层来访问数据库,你可以实现对数据库访问的封装,如图2.8所示。
持久层有多种实现方式:通过数据访问对象(DAO),它实现了所需的SQL代码;通过框架;通过存储过程;甚至通过WEB服务器。永远也不能把耦合降到0,但肯定可以把它降到能管理的程度。
图2.8 通过封装访问来减少耦合
代码重构是一种训练有素的方式,以一些较小的、演进式的步骤来调整代码的结构,从而改进代码的设计。代码重构保持了代码的行为语义;它既没有增加功能,也没有减少功能。
类似地,数据库重构是对数据库schema的一个简单变更,在保持其行为语义和信息语义的同时改进了它的设计。数据库重构是一种核心技术,使数据专家能以一种演进的方式进行数据库开发。
数据库所涉及的耦合越厉害,就越难对它进行重构。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/24945919/viewspace-741370/ ,如需转载,请注明出处,否则将追究法律责任。