第10章 软件构架重构

 
 10.1介 绍
 
在本书中,我们始终把构架当作在很大程度上受您控制的亊物,并说明了如何制定构 架决策(第3部分将阐述如何分析这些决策进行),以实现待开发系统的目标和需求。但是,我们还需耍考虑另外一方面。假定个系统己经存在,但不知道其构架。也许最初 ;的开发人员从来没有编写过构架文档:也许曾编写过文档,但丢失了:还有可能是虽然编 写了文档.但对系统进行了系列更改,怛文档并没有及时更新。如何维护这样的系统? 如何管理其演变以维护其构架(无论它是哪种)为我们提供的质量属性?
 
本章使用构架重构讲述了回答这些问题的方法,其中,已实现系统的“已构建”的构架是从现有系统中获得的。这是通过使用支持工具对系统进行详细分析来完成的。这些工 具提取关于系统的信息,协助构建和聚合连续的抽象级别。如果工具很有效,最终就会得 到协助对系统进行分析的构架表示。在某些情况下,可能无法产生一个有用的表示。在遗 留系统没有可以恢复的内聚构架设计时便会出现这种情况(尽管从本质上说了解这一点是'有用的)。
 
构架重构是一种解释、交互和迭代的过程,涉及许多活动;它并不是自动进行的。它 需要反向工程专家和设计师具备相关技能并投入精力(或具备关于该构架的重要知识的某 个人),这在很大程度上是因为在源代码中并没有清楚地表示构架构件。对于层、连接器 或可以轻松地从源代码文件中挑选出来的其他构架元素,并没有编程语言构件-很少标记构架模式(如果使用的话)。相反,我们通过实现中的许多不同的机制实现构架构件,通 常是功能、类、文件、对象等的集合。最初开发系统时,其高层设计/构架元系被映射到实现元素上。因此,在重构这些元索时,就需要应用反向映射。随之而来的是要求能够对构架进行洞察。熟悉编译器构造技术和实用程序也很重耍.如grep. sed. awk. perl, python, lex/yacc。
 
可以用几种方法来使用构架重构的结果。如果构架没冇文档或已经过期.那么,可以 把恢复的构架表示作为重新编写构架文档的基础,第9章已经对此进行了讨论。还可以使用 该方法恢复 “as-built”构架,以根据“已设计的”构架检査符合性。这可以保证我们的维 护人员(或开发人员)遵循对其提出的构架规定。不损坏构架,分解抽象,桥接层,对信息隐藏进行折衷等。还可以使用重构作为分析构架的基础(参见第11章和第12章),或 作为对系统进行再工程以获得一个期望的新构架的起点。最后,可以使用表示确定用于重 用的元素,或建立基于构架的软件产品线(参见14章)。
 
构架重构己用在了各种项目中,从MRI扫描仪到公共电话交换机,从直升机导航系 统到分类的NASA系统。它已被用于:
 
•    为物理模拟系统重新编写构架文档
 
•    理解采矿机的嵌入式控制软件中的构架依赖关系
 
•    评价卫星地面系统的实现与其参考构架的符合性
 
•    理解汽车制造业中的不同系统
 
10.1.1工作台方法
 
构架重构需要工具的支持,但任何一个工具或工具集对进行构架重构都是不够的。首 先,工具往往是面向特定语言的.但在分析的制品中,我们会遇到很多种语言。例如,一个成熟的MRI扫描仪可能会包含用15种语言编写的软件。其次.数据提取工具是有缺点 的,它们经常返回不完整的结果或错误的证据,所以我们使用精心挑选的工具来进行补充, 并对彼此进行检查。最后,重构的目的是不同的,上面已对此进行了讨论。所恢复文档的 用途决定了需要提取什么信息,这反过来又会建议使用不同的工具。
 
合起来看,这些就形成了支持构架重构的工具集的特定的设计哲学,即我们所熟知的 “工作台”。工作台应该是开放的(易于根据要求集成新的工具),并提供一个轻量级的集 成框架,在这个框架中,向工具集中添加的工具不会不必要地影响现有的工具或数据。
 
工作台的一个例子是在SEI开发的Dali,我们将使用该工作台阐述本章的几个观点. 本章的结尾部分还描述了其他的工作台。
 
10.1.2重构活动
软件构架重构由以下活动组成,这些活动以迭代的方式进行
(1)信息提取.,该活动的目的是从各种源提取信息。
 
(2)数据库构造。数据库构造包括将该信息转换为标准的形式,如Rigi    Standard Form (一种基于元组的数据格式,形式是relationship<entityl><entity2>,以及用于创建数据库 的基于SQL的数据库格式。
 
(3)视图融合,视图融合将数据库中的信息组合在一起,以生成该构架的一个内聚 的视图。
 
(4)重构。在重构活动中,主要工作是构建数据抽象和各种表示以生成构架表示。
 
正如您町能已经预料到的,这些活动具有极高的迭代性。图10.1描述了构架重构活动 以及信息如何在这些活动中流动。
 
            图10.1构架重构活动(箭头展示了活动中的倌息流向)
 
重构过程需耍有一些人的参与。这些人包括一个进行重构工作的人(重构人员),以 及一个或多个熟悉所重构的系统的人(设计师和软件工程师)。
 
重构人员从系统中提取信息,然后以手工方式或使用工具从信息中提炼出构架。构架 由重构人员通过对系统做出-组假定来获得。这些假定反映了从源制品到设计的反向映射 (理想情况下就是设汁映射的反面)。通过生成反向映射并把它们应用到提取的信息中来 对结果进行验证,从而对假定进行测试。为了最有效地生成这些假定并对其进行验证。必 须让熟悉系统的人参与此项工作,包括参与系统开发的系统设计师或工程师(最初开发了该系统或现在正对其进行维护的人)。
 
在下面的各节中,将更详细地概述构架重构的各种活动,以及每个活动的指导方针。 大多数指导方针都不是专门适用于某个特定工作台的,即使手工进行构架重构,这些指导方针也是适用的。
 
10.2信息提取
信息提取涉及分析系统现有的设计和实现制品,以构造系统的模型。所得到的结果就 是放在数据库中的信息集合,在视图融合活动中.我们使用该信息集合来构造系统的视图》 信息提取就是理想与现实的混合。前者是您希望发现的关于构架的信息.这些信息将 帮助您实现重构工作的目标,后者是可用的工具实际能够提取和提供的信息。根据源制品 (例如代码、头文件、build文件)和其他制品(例如执行踪迹),您可以确定并捕获系统 中感兴趣的元素(例如文件、函数、变量)及其关系,以获得几个基本的系统视图。表10.1 给出了可以提取的元素以及它们之间的几个关系的典型列表。
                    表10.1所提取的典型元素和关系
 
元素之间的每个关系都提供了关于系统的不同信息。函数之间的calls关系能够帮助我 们构建•个调用阁。文件之间的includes关系为我们提供了系统文件之间的一组依赖.函 数和变量之间的access_read和access_write关系展示了使用数据的方式。某些函数可以编 写一组数据,其他函数可以读取这个数据集合。该信息用于确定数据在系统的各个部分之 间的传递方式。我们可以确定是否使用了全局变量存储,或者是否大部分信息都是通过函 数调用来传递的。
 
如果所分析的系统很大,那么,捕获源文件存储在目录结构中的方式对重构过程可能 很重要-可以将某些元素或子系统存储在特定的目录中,在以后试图确定元素时,捕获诸 如dir_contains_file和dir_contains_dir这样的关系是有用的„
 
所提取的元素集合和关系取决于所分析的系统的类型以及可用的提取支持工具。如果要重构的系统是面向对象的,那么,把类和方法添加到要提取的元素列表中,并提取和使 用•如 class is_subclass_of_class 和 class_contains_method 这样的关系。
 
可以把获得的信息按静态和动态进行分类..静态信息是仅通过观察系统制品来获得 的,而动态信息是通过观察系统的运行方式来获得的。我们的目的是把两者融合起来,以 创建更准确的系统视图(将在10.4节讨论视阁融合)。如果系统的构架在运行时发生了变 化(例如.系统在启动时读入了配置文件,其结果是载入了某些元素),那么,在进行重 构时.就应该捕获并使用该运行时配置。
 
为了提取信息,我们使用了各种工具,包括:
 
•    解析器(例如 Imagix, SniFF+. CIA, rigiparse)
 
•    抽象语法树(AST)分析器(例如Gen++, Refine)
 
•    语法分析器(例如LSME)
 
•    剖析器(例如gprof)
 
•    代码插装工具
 
•    流行工具(例如grep. perl)
 
解析器分析代码,并根据它生成内部表示(目的是生成机器代码)。然而在通常情况下,可以保存该内部表示以获得一个视图。AST分析人员进行了类似的工作,但他们建立 了所解析信息的显示树表示。我们可以构建遍历AST的分析工具,并以适当的格式输出 所选择的与构架相关的信息。
 
语法分析器对源制品进行分析,源制品纯粹是作为语法元素或环的字符串。语法分析 器的用户可以指定一组待匹配和输出的代码模式。与此类似,流行工具的集合(如grep 和perl〉可以执行模式匹配并在代码内搜索.以输出所需要的信息。所有这些工具——代 码生成解析器,基于AST的分析器,语法分析器和流行的模式匹配器——都用于输出静 态信息。
 
可以使用剖析和代码覆盖分析工具来输出关于所执行的代码的信息,通常并不涉及向 系统中添加新的代码。另--方面,在测试领域具有广泛适用性的代码插装涉及向系统中添 加代码,以在执行系统时输出特定信息。这些工具生成动态的系统视图。
 
还可以使用分析设计模型、build文件、makefiles和可执行文件的工具来根据需要提 取更多的信息。例如,build文件和makefiles包括存在于系统中的关于模块或文件依赖性 的信息,这些信息可能未反映在源代码中。
 
可以从源代码、编译时制品和设计制品中静态提取大量与构架相关的信息。然而,由 于后期绑定的原因,某些与构架相关的信息可能并不在源制品中。后期绑定的示例包括:
 
•多态性
 
•函数指针
 
• 运行时参数化
 
直到运行时才可以确定系统精确的拓扑。例如,多进程和多处理器系统使用诸如J2EE. Jini或.NET这样的中间件动态频繁地建立其拓扑,这取决于系统资源的可用性。此类系统 的拓扑并不存在于其源制品中,因此不能使用静态提取工具对其进行反向工程。
 
基于此原因,可能有必要使用能够生成关于系统的动态信息的工具(如分析工具)。 当然.这耍求能够在系统执行的平台上获得此类工具。此外,从代码插装中收集结果可能 是困难的。嵌入式系统通常无法输出此类信息。
 
指导方针
 
以下是在实际中应用该方法的这一步时应该考虑的一些事项:
 
• 用“最少的工作量”提取。考虑您需耍从源信息集合中提取什么信息?该信息在 本质上是不是属于语法方面的?它是否要求对复杂语法结构的理解?它是否要 求进行语义分析?在每种情况下,都可以成动地应用一种不同的工具。一般而言, 语法方法是最经济的方法,如果重构目标很简单.应该考虑采用这种方法。
 
•验证已经提取的信息。在开始融合或处理获得的各种视阁前,确保已经捕获了正 确的视图信息。确保用于分析源制品的工具在正确地工作是非常重要的-首先要 根据基础的源代码对元素和关系的子集进行分析和验证.以确定已捕获了正确的 信息。需要手工验证的信息的准确数量由您来决定。假定有一个统计样本,您可 以确定期望的置信度,并选择样本策略来实现它。
 
•在需要的地方提取动态信息,如有大景运行时或后期绑定,以及可动态配置构架 的地方。
 
10.3数据库构造
 
在数据库构造期间,将提取的信息转换为标准的格式以存储在数据挥中。有必要选择 -个数据庳模型。在选择数据库模型时,请考虑如下问题:
 
•它应是-个众所周知的模型,以用另.个相对简单的模型代替一个数据库实现
 
•它应允许进行高效的査询,考虑到该源模型可能会相当大,这一点显得非常重要,
 
•它应支持从分布在不同地理位置的一个或多个用户界面对数据库进行远程访问
 
•    它通过组合来自各个表的信息来支持视图融合。
 
•    它支持可以表示构架模式的查询语言。
 
•    实现应该支持检査点,这意味着可以保存中间结果。在迭代过程中,这一点非常
重耍,因为它总是能够使用户撤销所做的修改。
 
例如,Dali 工作台使用关系数据库模型。它将提取的视图(这些视图可能会以很多不 同的格式存在,这取决于提取视图所使用的工具)转换为Rigi Standard Form.然后,由 perl脚本读入该格式,并以一种包含必要的SQL代码的格式输出,以构建关系表,并在表 中填充所提取的信息。图10.2概述了这一过程„
                                    图10.2将提取的信息转换为SQL格式
构建并填充关系表的所生成的SQL代码的示例请看图10.3„
create table calls( caller text, callee text ); 
create table access( func text, variable text ); 
create table defines_var(file text, variable text );
...
insert into calls values( 'main','control ');
insert into calls values( 'main', 'clock');
...
insert into access  values( 'main'、 'stat');
        图10.3    用Dali生成的SQL代码的示例
 
当把数据输入数据库时,生成了两个额外的表:元素和关系。这两个表分别列出了所 提取的元素和关系..
 
在这里,工作台方法使得可以采用新工具和技术(除了当前可以获得的工具和技术) 将提取工具所使用的格式转换为其他格式。例如,如果要求使用某个工具來处理新的语言, .那么,就可以对其进行构建,并将其输出转换为工作台格式
 
在Dali工作台的当前版本中,POSTGRES关系数据库通过使用SQL和perl来提供生 成和处理构架视图的功能性(10.5节给出了示例)。可以轻松修改SQL脚木.以使它们与 其他SQL实现兼容。
 
指导方针
 
在构造数据库时,请考虑如下问题:
•    根据提取的关系构建数据库表,以使视图融合期间数据视阁的处理更加容易。例 如,构建一个存储特定查询结果的表,避免要再次运行查询。如果需要这些结果. 可以很容易地通过访问该表获得它们。
 
•    对于任何数据库构造,在开始构造前仔细分析数裾库设计。主(可能是辅)键是什么?任何数据库连接都需要扫描多个表吗?在重构中,表通常是相当简单的
(顺序是 dir_contains_dir 或 function_calls_function)主键是整行的一个函数。
•    使用像perl和awk这样的简单语法工具,将用任何工爲所提取的数据的格式变为 可以由工作台所使用的格式。
 
10.4视图融合
 
视图融合包括定义和处理所提取的信息(现在存储在数据库中),以协调、加强并建 立元素之间的连接。不同形式的提取应该提供互补的信息。下面儿节通过示例对融合进行 了说明。
 
10.4.1改进视图
 
考虑一下图10.4中所示的两个代码段,它们来自于从用C++实现的系统中提取的方法 集(每个方法前都给出了各自的类)。这些表包括面向对象代码段的静态和动态信息。例 如,我们可以从动态信息中看出调用了 List::getnth。然而,该方法并不包含在静态分析中, 因为静态的提取器工具遗漏了它。此外,对InputValue和List的构造器和析构器方法的调 用并不包含在静态信息中,需要添加到协调两个信息源的类/方法表中。
 
此外,该示例中的静态提取展示了 PrimitiveOp类有一个称为Compute的方法,动态 提取结果中没有此类,但它们确实展示了类,如ArithmeticOp. AttachOp和StringOp,其 中每个类都有一个Compute方法,实际上该方法是PrimitiveOp的-个子类。PrimitiveOp 纯粹是•个超类,因此实际上在执行程序中从来没有调用过。但是在扫描源代码时.静态 提取器肴到的是对PrimitiveOp的调用,因为对PrimitiveOp的一个子类的多态调用是在运 行时发生的。
 
为了获得构架的准确视图,我们需要协调PrimitiveOp的静态和动态信息。为了做到 这一点,我们使用SQL查询对提取的calls, actually_calls和has_subclass关系进行融合。 这样,我们可以看到对PrimitiveOp::Compute (从静态信息中获得)及其各种子类(从动 态信息中获得 的调用实际上是相同的。
            图10.4关于class_contains_method关系的静态和动态数据信息
 
图10.5中的列表展示了添加到融合视图中的项(除了静态和动态信息达成一致的方 法)以及从融合视图屮删除的项(尽管包含在静态或动态信息中)。
                    图10.5添加到总视图中的项和在总视图中省略的项
 
10.4.2消除函数调用的歧义
 
在多进程应用中.很可能会出现名字冲突。例如,几个进程可能都有一个称为main 的过程。标识冲突并消除所提取的视图中的歧义是很重要的。通过融合可以轻松地提取的 信息,我们可以消除这一潜在的模糊性。在这种情况下.我们需要把静态的calls表与“文 件/函数包含”表(用于确定在哪些源文件中定义哪些函数)和“建立依赖”表融合在一起 (用于确定对哪些文件进行编译来生成哪些可执行文件)。这些信息源的融合使得潜在模 糊的过程或方法名成为惟-的,因此可以在构架重构过程中明确地引用。如果没有视图融 合.这种模糊性将会持续到构架重构的过程中。
 
指导方针
 
下面是在应用该方法的这一步骤时.实际应该考虑的一些问題:
 
•    当单个提取出的表不能够提供所需要的信息时,对表进行融合。
 
•、当其中一个表具有模糊性,而且不可能使用单个表來消除歧义时,对表进行融合:
 
•    考虑采用不同的提取技术来提取不同的信息.例如,可以使用动态和静态提取: 或者如果您认为一个实例可能会提供错误的或不完整的信息,也可以使用相同技 术的不问实例,如用于相同语言的不同解析器。
 
10.5重 构
 
现在,我们已经提取、存储并求精或补充了视图信息,从而改进了其质量。重构对视 图进行操作.以揭示对构架概括性的、粗粒度的见解。重构由两个主要的活动组成:可视 化和交互以及模式定义和识别。下面分别对其进行讨论。
 
可视化和交互为用户提供了交互地可视化、探讨和操作视图的机制。在Dali中,视图 是使用Rigi工具作为元素和关系的层次上分解的图形提供给用户的。图10.6给出了构架 视阁的个例子.
                图10.6用Dali表示的构架视图
        
模式定义和识别为构架重构提供了工具:构架模式的代码表现的定义和识别。例如, Dali的重构工具能够使用户通过确定元素的聚合,根据较为详细的视图构造出软件系统较 为抽象的视阁。模式是使用我们称之为代码段的SQL和peri的组合,用Dali定义的。SQL查询用于确定来自Dali存储库的元素,这些元素将组成新的聚合:perl表达式用于转换名 字,执行杏询结果的其他操作。代码段被保留下来,用户可以有选择地应用和重用它们。
 
根据设计师期望在系统中发现的构架模式,重构人员可以建立各种杳询。这些查询会 导致展示了较低层元素(它们可能是源制品或抽象)的各种抽象或集群的新聚合。通过解 释这些视图并对其进行积极的分析,可以对査询和聚合进行求精.以产生几个可以解释、 进一步求精或否决的假定构架视图。该过程没有通用的完成标准;当构架表示足以支持分 析和文档时,该过程就完成了。
 
假定数据庳中包含阁10.7中所展示的元素和关系的子集。在这个示例中,变量a和b 是在函数f中定义的,也就是说,它们是f的局部变最。我们可以用图形的方式表示该信 息,如图10.8所示。
 
 
构架重构对局部变最不感兴趣.因为它们只提供了很少的关于系统构架的信息。因此, 我们可以把局部变量的实例聚合到出现它们的函数中。阁10.9给出了 SQL和perl代码完 成这一工作的示例。
 
            图10.9将局部变量聚合到定义它们的函数中的SQL和perl
 
第一个代码段通过在每个函数名后面添加一个“ + ”号更新了视觉表示。现在,函数与在函数中定义的局部变量聚合在了一起。SQL査询从元素表中选择函数,为每行查询结 果执行perl表示。用从查询中得到的字段自动填充$fields数组。在这个例子中,只从表中 选择了 •个字段(iName),因此,$fields[0]将为选择的每一个元组存储其值。该表达式所生成的行的形式为:
<function>+ <function> Function
这说明了应该把元素<function>聚合到<function>+中,它将有类型Function。
 
第二个代码段隐藏了局部变量,使其不可见。SQL查询通过选择defines_var表中的每 个元组为定义的每个函数确定了局部变量。因此在peri表达式中.$fie丨ds[0]与fimc字段对 应,$ficlds[丨]与local_variable字段对应。因此,输出的形式为:
 
<function>+ <variable> Function
 
也就是说,函数的每个局部变量都要添加到该函数的<function>+聚合中。因为应用这两个 査询得出的最终结果经过了排序,因此,这两个代码段的执行顺序并不重要。
 
图10.10用图形方式表示了应用代码段的结果。
 
处理所提取信息的主要机制是反向映射。示例包括:
 
•    确定类型
 
•    将局部变量聚合到函数中
 
•    将成员聚合到类中 
•    组合构架级的元素
 
阁10.11给出了确定构架元素的查询示例。该査询确定了 Logical_Interaction的构架元 素,并假定如果类名是Presentation, Bspline或Color,或者如果类是Presentation的子类, 那么,它就应归入Logical_Interaction元素。
 
用这种方式编写代码段的目的是对较低层信息进行抽象,以生成构架级的视图。重构 人员构建这些代码段來测忒关于系统的假定。如果某个代码段没有产生有用的结果,那么, 就可以将其废弃。重构人员通过这一过程进行迭代.直到获得有用的构架视图。
 
指导方针
 
下面是在应用该方法的这一步骤时.在实际中应该考虑的•些问题:
 
•    做好与设计师密切合作,并对所创建的构架抽象进行多次迭代的准备。当系统没 有清楚的、编成文档的构架时,尤其应该这样做(参见引文“査找构架”)。在这 种情况下,您可以把构架抽象作为假设,并通过创建视图,让设计师和其他涉众 査看这些视图来对这些假设进行测试。根据所发现的假阴性和假阳性,重构人员 可以决定创建新的抽象.从而产生要应用的新的Dali代码段(甚至可能是需要 完成的新的提取)。
 
•    在开发代码段时,试着构建简洁且不列出每个源元素的代码段..
图10.11给出了一个优秀代码段的示例,在这方面的糟糕的代码段的示例请看图10.12。在图10.12中,只列出了组成所关心的构架元素的源元素,这使得代码段很难使用、理解和重用
 
•如果命名规则在整个系统中的使用一致的的话,那么,代码段可以遵循命名规则。一个示例是属于Interface元素的所有函数、数据和文件都以i幵始。
 
•往文件和函数所在的位置,代码段可以基于目录结构,元素聚合可将这些目录作 为基础。
 
•构架重构就是只根据构架决策在实际制品(即实现它们的代码〉中的结果,萆新确定这些构架决策。随着重构工作的进行,必须添加信息,以重新引入构架决策, 在引入这些决策时,重构人员所假定的构架决策会与最初的构架决策产生偏差, 因此需要一个了解所重构构架的人参与此项工作。
 
10.8可进一步参阅的文献
 
现在已经幵发出了—些_工作台。软件工程研究所(SEI)已经开发出了 Dali
 
[Kazman 99a]» 興他本例包括 Sneed 的再工程工作台[Sneed 98],Verhoef and associates [Brand 97]的软件创新C厂,以及由Philips Research [Krikhaar 99]开发的笊新设计T.具蜜件。
 
[MiillerW]中讨论了 Rigi Standard Form,[Wong 94]中描述了 Rigi II具。
 
[Bowman 99]概述了 一种与Dali类似的方法,该方法用F从所实现系统的代码中提取 构架文档。在•个例子中,他们重新构造了 Linux系统的构架。首先他们使用cfx程序(c 代码事实提取器)对源代码进行了分析以从源代码中获得符号信息,并生成了符号之间的 一组关系-然后,他们人工创建了一个将Linux系统分解为了-系统的树型结构图,并为其 分配了源文件。接下来,他们使用grok事实操纵器工具确定了所识别的子系统之间的关系, 并使用Isedit可视化工具对所提取的系统结构进行了可视化。通过在子系统之间移动源文 件对所得到的结构进行了求精。
 
Harris and Associates使用组合的由底至上和自顶向下的方法[Harris 95]概述了构建重构的框架。该框架由3个部分组成:构架表示,源代码识别引擎和识别查询的支持库,以 及“鸟瞰”程序概述功能。由底至上的分析使用鸟瞰图来显示系统的文件结构和源元素, 并将信息重新组织到更有意义的集群中。自顶向下分析使用特定的构架模式来定义应该在 软件中发现的元素。然后,运行识别查询来确定是否存在所期望的允素。
 
[Guo 99]概述了称为ARM的半自动构架恢复方法,该方法所针对的是使用模式设计 和开发的系统。它由4个主要步骤组成:(1)开发具体的模式识别计划,(2)提取•个源 模型,(3)检测并评估模式实例,(4)重新构造并分析构架。所提供的案例分析展示了使 用ARM方法对系统的重构,并根据其已经编成文档的构架检査其一致性。
10.9讨论题
(1)假定您认为系统的构架已经分层,应该从源代码中提取什么信息来确定或否认该 假定?
 
(2)假定您认为系统的构架遵循•个共享的存储库样式,应该从源代码中提取什么信 息来确定或西认该假定?
 
(3)针对10.1节中所提及的每个重构的使用,指定应该重新构造的构架视图。
 
(4)第6萆描述了    •个代码模板,该模板用于提供一个在ISSS空中交通符制系统中 实现高可用性的一致方法。假定您想确认开发人员和维护人员在系统的生命期内一直忠实 于该模板。描述您将采用的重构过程。
 

猜你喜欢

转载自www.cnblogs.com/mongotea/p/11986004.html