跳转到主要内容
Chinese, Simplified

您在A Vision中了解到敏捷数据方法,敏捷方法(如极限编程(XP)和纪律敏捷交付(DAD))采用迭代和增量方法进行软件开发。 XP和DSDM项目的应用程序开发人员通常放弃大型设计(BDUF)方法,转而采用紧急方法,系统设计在整个项目生命周期中不断发展。在敏捷开发项目中,在应用程序准备好发布之前,通常不知道最终设计。对于许多有经验的IT专业人员来说,这是一种非常不同的工作方
这意味着,预先创建(几乎)完整的逻辑和物理数据模型集的传统方法不会起作用。传统方法的主要优点是它使数据库管理员(DBA)的工作变得更加容易 - 数据模式很早就实现了,而这正是人们使用的。然而,有几个缺点。首先,它要求设计人员尽早完成,迫使您在项目早期确定大多数要求,从而迫使您的项目团队采用连续的方法进行开发。其次,它不容易支持变化。随着项目的进展,您的项目利益相关者了解他们的需求将会发展,从而激励他们发展自己的需求。在您的项目中,业务环境也会发生变化,再次激励您的利益相关者发展他们的需求。简而言之,传统的工作方式在敏捷环境中不能很好地工作。如果敏捷DBA将继续工作并支持遵循敏捷方法的项目团队,那么他们需要找到支持迭代和增量工作的技术。我的经验是,一种关键技术是数据库重构。


目录

  • 重构
  • 数据库重构
  • 为什么数据库重构?
  • 保留语义
  • 什么数据库重构不是
  • 为什么数据库重构很难
  • 如何重构数据库
  • 第1步:从您的开发沙箱开始
  • 第2步:在集成沙箱中实施
  • 第3步:安装到生产中
  • 在您的组织内采用数据库重构
  • 数据库重构最佳实践
  • 现实世界中的数据库重构
  • 数据库重构目录(发布为另一页)

 

1.重构


Martin Fowler(1999)描述了一种称为重构的编程技术,这是一种重构代码的规范方法。基本思想是您对代码进行少量更改以改进设计,使其更易于理解和修改。重构使您可以随着时间的推移缓慢地发展代码,采用迭代和增量方法进行编程。 Martin的重构网站www.refactoring.com是一个很好的在线资源
重构的一个关键方面是它保留了代码的行为语义,至少从黑盒的角度来看。例如,有一个名为Rename Method的非常简单的重构,可能是从getPersons()到getPeople()。虽然表面上的这种更改看起来很简单,但您需要做的不仅仅是进行单一更改,还必须在所有应用程序代码中更改此操作的每次调用以调用新名称。一旦你做了这些改变,你可以说你已经真正重构了你的代码,因为它仍然可以像以前一样再次运行。
重要的是要了解在重构时不添加功能。当您重构改进现有代码时,在添加功能时,您将添加新代码。是的,您可能需要重构现有代码才能添加新功能。是的,稍后您可能会发现需要重构刚刚添加的新代码。要点是重构和添加新功能是两个不同但互补的任务。


2.数据库重构


在2002年2月的软件开发期间,我描述了一种我称之为数据重构的技术。本文描述了我的初步经验,应该更恰当地称之为事后数据库重构。因此新名称。从这一点开始,我将使用术语代码重构来引用Fowler所描述的传统重构,以区别于数据库重构。
让我们从一些定义开始。数据库重构是对数据库模式的简单更改,可以改进其设计,同时保留其行为和信息语义。为了便于讨论,数据库模式包括结构方面(如表和视图定义)以及功能方面(如存储过程和触发器)。有趣的是,数据库重构在概念上比代码重构更难。代码重构只需要维护行为语义,而数据库重构也必须维护信息语义。
有一个名为Split Column的数据库重构,它是A Database of Database Refactorings中描述的众多数据库之一,您可以用两个或多个其他列替换单个表列。例如,您正在处理数据库中的Person表,并发现FirstDate列用于两个不同的目的 - 当该人是客户时,此列存储他们的出生日期,当该人员是雇员时,它存储他们的雇用日期。您的应用程序现在需要支持既可以成为客户又可以成为员工的人,这样您就会遇到问题。在实现此新要求之前,您需要通过将BirthDate列替换为BirthDate和HireDate列来修复数据库模式。要维护数据库模式的行为语义,您需要更新访问FirstDate列的所有源代码,以便现在使用这两个新列。要维护信息语义,您需要编写一个遍历表的迁移脚本,确定类型,然后将现有日期复制到相应的列中。虽然这听起来很简单,有时也是如此,但我的经验是,在考虑文化问题时,数据库重构在实践中是非常困难的(稍后将详细介绍)。

 

2.1为什么要重构数据库?


您应该对数据库重构感兴趣的原因有两个:

  • 安全地修复现有的旧数据库。底线是遗留数据库不会自行修复,从技术角度来看,数据库重构是一种安全,简单的方法,可以随着时间的推移改善数据和数据库的质量。多年来,我对数据质量的各种调查一直表明,组织遭受数据质量问题,但在许多情况下,没有一个现实的战略来解决这些问题。
  • 支持进化发展。现代软件开发过程,如DAD,XP和Scrum,都以渐进的方式工作。数据专业人员需要采用包括这一技术在内的技术,使他们能够以这种方式工作。
  • 调整数据库。部分调优工作可能包括模式的(反)规范化。

2.2保留语义


信息语义是指从该信息的用户的角度来看数据库内的信息的含义。保留信息语义意味着当您更改存储在列中的数据的值时,该信息的客户端不应受到改进的影响。类似地,关于行为语义,目标是使黑盒功能保持相同 - 必须重新设计与数据库模式的已更改方面一起使用的任何源代码,以实现与以前相同的功能。


2.3什么数据库重构不是什么


对模式进行小规模转换以扩展它,例如添加新列或表,不是数据库重构,因为更改扩展了您的设计。同时应用于数据库模式的大量小更改(例如重命名十列)不会被视为数据库重构,因为这不是一个小的更改。数据库重构是对数据库模式的微小更改,可以在保留行为和信息语义的同时改进其设计。而已。我毫不怀疑你可以对你的模式进行那些更改,你甚至可以遵循类似的过程,但它们不是数据库重构。


3.为什么数据库重构很难


耦合。正如您在关系数据库101中所了解到的那样,耦合度是两个项目之间依赖程度的度量 - 两个事物之间的耦合程度越高,一个变化需要另一个变化的可能性就越大。在进行数据库重构时,耦合是“万恶之源”,数据库模式与重构更加困难的事情就越多。不幸的是,您在关系数据库101中了解到关系数据库模式可能与各种各样的事物耦合:

  • 您的应用程序源代码
  • 其他应用程序源代码
  • 数据加载源代码
  • 数据提取源代码
  • 持久性框架/层
  • 您的数据库架构(通过模型或脚本捕获)
  • 数据迁移脚本
  • 测试代码
  • 模型和/或文档

图1描述了数据库重构的最佳情况 - 只有您的应用程序代码与数据库模式相关联。图2描绘了数据库重构工作的最坏情况,其中各种各样的软件系统与您的数据库模式耦合,这种情况在现有生产数据库中很常见。
图1.最佳情况。

Data refactoring best-case scenario

Data refactoring worst case scenario

 

如您所见,在数据库重构方面,耦合是一个严重的问题。为简单起见,在本文的其余部分中,术语“应用程序”将指代与数据库耦合的所有外部系统,数据库,应用程序,程序,测试套件。

4.如何重构数据库


在我描述重构数据库的步骤之前,我需要解决一个关键问题 - 图1所示的简单情况是否意味着你会做出与图2中高度耦合的情况不同的事情?是的,不是。基本过程本身保持不变,尽管随着数据库耦合的增加,实现单个数据库重构的难度也会大大增加。如果您发现自己处于简单的情况,那么您将不需要执行下面描述的过渡期工作,您可以简单地并行重构数据库模式和应用程序代码并同时部署它们。发现自己处于更复杂局面的人没有这种奢侈品。

本节的编写假设您的技术和文化环境是有组织的,以支持数据库重构。虽然这听起来像是一个很大的假设,但是,我会描述你需要做些什么才能达到这些环境实际到位的程度。少一点是不合适的。

我喜欢将数据库重构视为一个三步过程:

  1. 从您的开发沙箱开始
  2. 在集成沙箱中实现
  3. 安装到生产中

4.1第1步:在您的开发沙箱中开始


您的开发沙箱是一个技术环境,您的软件(包括应用程序代码和数据库模式)是开发和单元测试的。重构数据库模式的需求通常由尝试实现新需求或正在修复缺陷的应用程序开发人员识别。例如,开发人员可能需要扩展其应用程序以接受除美国地址之外的加拿大邮寄地址。主要区别在于加拿大地址有邮政编码,如R2D 2C3而不是邮政编码,如90210-1234。不幸的是,SurfaceAddress表的ZipCode列是数字的,因此目前不支持加拿大邮政编码。应用程序开发人员描述了对其项目中的一个Agile DBA所需的更改以及数据库重构工作的开始。
如图3所示,Agile DBA和应用程序开发人员通常会通过以下部分或全部步骤来实现重构:

  • 验证是否需要重构数据库
  • 选择最合适的数据库重构
  • 弃用原始架构
  • 写单元测试
  • 修改数据库架构
  • 迁移源数据
  • 更新外部访问程序
  • 更新数据迁移脚本
  • 运行回归测试
  • 宣布重构
  • 版本控制你的工作

图3.数据库重构的过程。

4.1.1验证是否需要数据库重构


敏捷DBA所做的第一件事是他们将尝试确定数据库重构是否需要发生以及是否是正确的重构。敏捷DBA所做的第二件事是在内部评估实际需要变更的可能性。这通常是基于Agile DBA之前与应用程序开发人员的经验的“直接调用”。 Agile DBA接下来要做的就是评估重构的整体影响。在图1的瘦腿情况下,这是相当简单的,因为敏捷DBA应该了解应用程序如何耦合到数据库的这一部分。如果不是这种情况,他们需要与应用程序开发人员合作。在图2的复杂情况下,Agile DBA需要了解组织内的整体技术基础架构以及其他应用程序如何与数据库耦合。这是他们需要通过与企业架构师,企业管理员,应用程序开发人员甚至其他敏捷DBA合作来建立的知识。当敏捷DBA不确定其影响时,他们要么需要决定当时做出决定并且有他们的直觉,或者决定建议应用程序开发人员在他们与合适的人交谈时等待。这项工作的目标是确保您尝试进行无法完成的数据库重构 - 如果您需要更新,测试和重新部署其他20个应用程序以进行此重构,那么你可能继续下去是不可行的。


4.1.2选择最合适的数据库重构


敏捷DBA需要的一项重要技能是理解您通常有多种选择来在数据库中实现新的数据结构和新逻辑。


4.1.3编写单元测试


与代码重构一样,数据库重构由于存在全面的测试套件而启用 - 您知道如果您可以轻松验证数据库在更改后仍然有效,则可以安全地更改数据库模式。这是我的建议:

您的主要目标是确保测试存在。
您应该尝试在应用程序级别或数据库级别执行一次每个测试,但不能同时执行两者。
一些单元测试将在应用程序级别,一些在数据库级别,这没关系。
寻求最低的共同点 - 如果数据库被多个应用程序访问,那么任何与数据相关的测试都应该出现在您的数据库测试套件中,这有助于确保它们经过一次测试。
如果您有选择,请在具有最佳测试工具的级别(通常在应用程序级别)实施测试。测试工具在工具文章中讨论。
文章数据库回归测试详细描述了数据库测试。


4.1.4弃用原始架构


Pramod Sadalage和Peter Schuh(2002)推广的一种有效技术是弃用期,尽管过渡期是一个更好的术语,对于你正在改变的模式的原始部分。他们发现您不能简单地立即对数据库模式进行更改,而是需要并行处理旧模式和新模式一段时间,以便为其他应用程序团队提供重构和重新部署系统的时间。图4显示了当我们将替换列数据库重构应用于ZipCode时,这个想法是如何工作的(这个例子是在2003年创建的,因此在2007年是一个删除日期 - 稍后将详细介绍)。请注意过渡期间原始模式和模式之间的更改。 PostCode已添加为列,正如您所期望的那样。 ZipCode列已被标记为已弃用 - 您知道这一点,因为已使用UML命名变量为其分配了删除日期。还引入了一个触发器来保持两列中包含的值同步,假设新的应用程序代码将与PostCode一起使用,但不应期望ZipCode保持最新,并且旧的应用程序代码尚未重构为使用新架构将不知道如何使PostCode保持最新。此触发器是数据库脚手架代码的示例,是保持数据库“粘合在一起”所需的简单和通用代码。此代码已分配与ZipCode相同的删除日期。

图4.重构Address表。

关于图4的一个有趣的事情是将Country列添加到Address。等一下,目录中没有添加列数据库重构。我们发现了一种新型的数据库重构吗?不。数据库重构是对数据库模式的小改动,它们改进了他们的设计,而不仅仅是改变设计。添加新列是对模式的转换,但不是对它的设计改进。虽然这显然是一个非常小的细微差别我相信它是一个重要的。
要了解如何实现数据库重构的代码,请阅读重命名列数据库重构。

图5描绘了数据库重构的生命周期。首先在项目范围内实现它,如果成功,最终将其部署到生产环境中。在过渡期间,原始模式和新模式都存在,具有足够的脚手架代码以确保正确支持任何更新。在过渡期间,一些应用程序将与PostCode和其他具有ZipCode的应用程序一起使用,但不能同时使用。无论它们使用哪个列,应用程序都应该正常运行。弃用期限到期后,将删除原始架构和任何脚手架代码,并重新测试数据库。在这个时间点,假设所有应用程序都使用PostCode。

图5.数据库重构的生命周期。

在图5的顶部,我们将来自Disciplined Agile(DA)的3C模式应用于生命周期。这是一个三步模式:

坐标。实施重构,与组织级别的适当人员(可能是您的数据管理组)协调,以确保它进入整个变更流程。
合作。整个组织中的团队共同努力改变与数据库相关的任何变化(参见图2)。
得出结论。删除原始模式和脚手架代码,有效地完成重构。

4.1.5修改数据库模式


应用程序开发人员和Agile DBA一起在开发沙箱中进行更改。策略是简单地开始每个重构,首先通过在开发沙箱中执行重构,您实际上将自己置于图1中描述的情况中。
为此,您需要更新两个日志(假设您没有自动执行此操作的数据库重构工具):

  • 数据库更改日志。这是在整个项目过程中应用它们的顺序实现所有数据库模式更改的源代码。在实施数据库重构时,只包括此日志中的即时更改。在应用替换列数据库重构时,我们将包括用于添加PostCode列的DDL和用于实现触发器的数据定义语言(DDL),以在过渡期间维护PostCode和ZipCode列之间的值。
  • 更新日志。此日志包含将在数据库重构的过渡期之后运行的数据库模式的未来更改的源代码。在我们的示例中,这将是删除ZipCode列和我们引入的触发器所需的源代码。


4.1.6迁移数据


许多重构要求您将旧版本的架构迁移或复制数据到新架构。您的数据迁移日志包含数据操作语言(DML),用于在整个项目过程中重新格式化或清理源数据。在我们的示例中,这将包括任何用于提高ZipCode列中值的质量的代码。

4.1.7更新外部程序


访问要重构的数据库模式部分的程序必须更新才能使用新版本的数据库模式。所有这些程序都必须重构,然后在过渡期到期之前部署到生产中,如图5所示。

4.1.8运行回归测试


一旦对应用程序代码和数据库模式进行了更改,您就需要运行回归测试套件。因为成功的测试会发现问题,所以在你做对之前需要重做工作。数据库重构的一个重要优点是,如果您的测试确实打破了,那么您可以很好地了解问题所在 - 在您刚刚更改的应用程序代码和数据库架构中。您的更改越大,追踪问题就越困难,因此您的开发工作就越慢,效率也就越低。你会发现,在小的渐进步骤中进行开发在实践中非常有效。

4.1.9宣布您所做的更改


因为您的数据库是一个共享资源,所以如果不是由多个应用程序团队在应用程序开发团队中共享它,那么Agile DBA需要传达已经发生的更改。如果您还没有这样做,则应更新数据库的物理数据模型(PDM)。我个人倾向于在PDM工具(如ERWin)中对新模式进行建模,然后生成初始DDL,然后我将修改并包含在我的数据库更改脚本中。


4.1.10版本控制你的工作


敏捷开发人员的一项关键技能是将所有工作都置于配置管理(CM)控制之下,通过将其检入版本控制工具。在数据库重构的情况下,这包括您创建的任何DDL,更改脚本,数据迁移脚本,测试数据,测试用例,测试数据生成代码,文档和模型。这是您通常会修改的面向应用程序的工件的补充 - 对待面向数据库的工件与处理其他开发工件的方式完全相同,您应该没问题。

4.2第2步:在集成沙箱中实施


几天过后,您将准备好在项目集成沙箱中实现数据库重构。您需要等待的原因是为了让您的队友有时间重构自己的代码以使用新架构。

选择通过使用持久性框架封装对数据库的访问权限的团队将发现更容易对数据库模式更改做出反应,因此可能会发现他们可以加强在开发沙箱和项目中实现数据库重构之间的时间间隔集成沙箱。这是因为数据库模式在元数据中表示,因此许多数据库模式更改只需要更新元数据而不需要更新实际的源代码。

要部署到每个沙箱中,您需要构建应用程序并运行数据库管理脚本(Autopatch等工具可以提供帮助)。下一步是重新运行回归测试以确保您的系统仍然有效 - 如果不是,您将需要在开发环境中进行修复,重新部署和重新测试。项目集成沙箱中的目标是验证团队中每个人的工作在组合时的功能,而您在Test / QA沙箱中的目标是验证您的系统是否适用于组织内的其他系统。

通信是将数据库重构部署到Test / QA沙箱中的关键部分,我现在使用复数,因为您通常会在此环境中同时引入多个数据库更改(重构)。在更改数据库模式之前,您需要与访问数据库的所有其他应用程序的所有者进行通信并协商更改。您的企业管理员将参与此次谈判,他们甚至可以促进工作,以确保满足您组织的整体需求。幸运的是,您在开发沙箱中遵循的过程使数据库重构的这一方面变得更加容易:

  • Agile DBA只允许实际实现的数据库重构 - 如果另一个应用程序团队无法重新编写代码来访问新模式,那么就无法进行更改。
  • Agile DBA编写的文档,即使只是每个更改的简要描述,也很重要,因为它提供了即将部署的更改的概述。
  • 随着数据库重构的实施而更新的新版本物理数据模型(PDM)成为与其他团队进行谈判的焦点。敏捷建模(AM)会认为PDM是您的团队与其他应用团队之间的“合同模型”,他们可以指望这些模型是准确的,并且他们可以指望积极参与协商变更。


4.3第3步:安装到生产中


安装到生产环境是数据库重构中最难的部分,特别是在图2的复杂情况下。您通常不会自己部署数据库重构,而是将它们部署为一个或多个系统的整体部署的一部分。当您有一个应用程序和一个要更新的数据库时,部署是最简单的,并且这种情况确实在实践中发生,但实际上我们需要考虑您一次部署多个系统和多个数据源的情况。图6概述了将重构部署到生产环境中的步骤。


图6.部署数据库重构的步骤。

图7描述了如何安排应用程序预定义部署窗口的部署,如绿色所示。 部署窗口(通常称为发布窗口)是允许将系统部署到生产中的特定时间点。 您的操作人员很可能对应用程序团队何时部署系统有严格的规定。 图7显示了两个项目团队如何安排将更改(包括数据库重构)部署到可用的部署窗口中。 有时没有什么可以部署,有时一个团队有变化,有时两个团队都有架构变化要部署。


图7.将重构调度到部署窗口中。

您自然需要与在同一部署窗口中部署的任何其他团队进行协调。这种协调将在您部署之前很久发生,坦率地说,您的预生产测试环境存在的主要原因是提供一个沙箱,您可以在其中解决多系统问题。无论将多少数据库重构应用于您的生产数据库,或者这些重构是由多少团队开发的,它们都将首先在您的预生产测试环境中进行测试,然后再应用于生产。

5.在您的组织内采用数据库重构


虽然采用有效的工具是实现数据库重构的重要部分,但它只是冰山一角 - 数据库重构需要在组织内进行重大的文化变革。由于数据库重构是敏捷数据方法的一种支持技术,因此采用数据库重构的许多文化问题与采用敏捷数据方法时面临的问题相同。这些文化问题包括许多数据专业人员的一系列思维方式,对变革的抵制以及政治惰性。以下方法可以帮助您克服这些挑战:

  1. 从简单开始。在新应用程序访问新数据库的绿地环境中,数据库重构最容易,下一个最简单的情况是单个应用程序访问旧数据库时。这两种情况都以图1为代表。通过简单的开始,您可以为自己提供一个可以学习基础知识的环境,一旦您了解了基础知识,您就可以更好地解决图2所示的情况。
  2. 接受迭代和增量开发是常态。现代软件开发方法采用迭代和增量方法进行软件开发。尽管串行开发通常是许多数据专业人员的首选方法,但遗憾的是它并未反映应用程序开发人员当前的工作方式。是时候改变了。
  3. 接受没有神奇的解决方案让你摆脱现有的混乱局面。您的数据质量问题并没有自行创建,也无法自行修复。人们创造了问题,人们需要解决问题。数据库重构是您可以从数据技术债务中挖掘出来的最安全,最直接的策略。
  4. 采用100%数据库回归测试策略。要使数据库重构工作,并且通常要使迭代和增量开发工作,您需要在回归测试中有效。要在数据库重构方面取得成功,您不仅需要对数据库本身进行回归测试,还需要对与数据库耦合的任何应用程序进行回归测试。这意味着您需要为每个应用程序提供回归测试套件,这是您很可能没有的。所以开始写它们。
  5. 探索技术。首先在简单的情况下尝试数据库重构,以学习技术并获得一些经验。然后开始重构更复杂的事情。所以,开始简单吧。

数据库重构在实践中起作用,它不仅仅是另一种学术理论。对于绝大多数组织而言,这是一种新的“前沿”技术。

6.数据库重构最佳实践


Fowler(1999)提出了一系列代码重构的最佳实践,我在下面重新构建了数据库重构的实践:

  1. 重构以简化模式的添加。
  2. 确保测试套件到位。
  3. 迈出小步。
  4. 人民计划。
  5. 不要过早发布数据模型。
  6. 对文件的需求反映了重构的必要性。
  7. 经常测试。


7.现实世界中的数据库重构


数据库重构支持数据库模式演变的渐进方法,这是三个基本策略之一(您可以放弃,采取“大爆炸”方法,采取增量方法)。每种策略都有其独特的优点和缺点。我怀疑许多组织,或许是因为一种连续的思维方式,要么尝试过大爆炸的方法,要么已经太害怕了,现在已经放弃了。它不一定是这样的。是的,您的组织可能需要花费大量精力来制定文化和技术来支持整个企业的数据库重构,但从长远来看,这可能比您的其他选择更加可口。
请参阅数据库重构目录(http://www.agiledata.org/essays/databaseRefactoringCatalog.html)。
无论您的策略如何,数据库的演变都很难,当您的数据库与其他事物高度耦合时,尤其如此。数据库重构不是一个可以神奇地解决所有数据库问题的灵丹妙药。本文介绍了如何在简单的瘦腿环境中成功实现数据库重构。

 

原文:http://agiledata.org/essays/databaseRefactoring.html

本文:https://pub.intelligentx.net/agiledata-process-database-refactoring-strategies-improving-database-quality

讨论:请加入知识星球或者小红圈【首席架构师圈】

Article
知识星球
 
微信公众号
 
视频号