面向方面建模中管理可变性复杂性
在面向方面建模(AOM)中,管理可变性的复杂性是一个关键问题。手动定义约束不仅耗时,还可能导致约束过度或不足,影响方面族的一致性和可靠性。为了解决这些问题,我们提出了一套系统的方法来分析和评估具有可变性的方面模型的一致性。
1. 方面族一致性检查
我们提出的方法旨在生成、分析和测试方面族的所有可能变体。虽然管理产品线的所有成员在实际的软件产品线(SPL)中可能既耗时又耗资源,但方面模型可被视为专注于特定关注点的微型软件产品线,其可能的变体数量是合理的。
该过程从一个可变方面开始,包括以下三个顺序步骤,这些步骤将对可变方面的所有可能变体执行:
1.
生成方面族的变体
:此步骤通过从可变方面定义的选项和变体中选择一个配置,生成一个无变体的方面模型,作为分析的测试用例。生成的方面模型的组合协议和接口模型仅包含所选变体和选项定义或使用的元素。例如,在我们的示例中,这一步相当于构建一个对应于图中某一单元格的方面模型。
2.
对生成的方面进行静态分析
:该步骤以生成的方面模型为输入,对方面的各个部分(嫁接模型、接口模型、组合协议)进行静态分析,检查其一致性属性。如果检测到方面不一致,过程将停止,不再执行后续步骤。
3.
测试方面组合
:在这一步中,将生成的方面应用于生成的基础模型,通过其组合协议进行验证。基础模型根据接口模型的内容自动构建,以确保基础模型元素遵守其所有结构约束。计算方面模型的绑定,使每个接口模型元素与相应的基础模型元素匹配。如果组合过程中出现错误,则该变体不一致。
过程结束时,会生成一份报告,指定所有已测试的变体配置。对于失败的配置,报告将提供关于哪个检查步骤(步骤2或3)失败的解释和详细诊断信息。这有助于方面设计者识别和理解问题,并通过更改或扩展方面模型的部分内容来修复问题。更改后,可以重新运行该过程,再次测试方面模型的效果,直到可变方面模型的测试无错误为止。
下面是该过程的mermaid流程图:
graph LR
A[可变方面] --> B[生成方面族的变体]
B --> C{方面是否一致?}
C -- 是 --> D[测试方面组合]
C -- 否 --> E[结束并报告问题]
D --> F[生成报告]
F --> G{是否有错误?}
G -- 是 --> H[修复方面模型]
H --> B
G -- 否 --> I[结束]
2. 方面模型静态分析
方面模型的静态分析主要关注两个方面:模型的一致性和组合协议的一致性。
2.1 方面模型的格式良好规则
SmartAdapters首先检查方面模型的各个元素在语法上是否正确,并遵守格式良好规则。
-
嫁接模型和接口模型
:这两个模型使用与MOF非常相似的领域元模型概念设计(实际上使用的是专门用于类图设计的EMF/ECore)。与基础模型不同,嫁接和接口模型仅表示模型片段。我们会静态检查模型元素的类型是否正确,例如所有关联端是否正确类型化,以及一个对象是否不会被两个模型元素包含。
-
适配
:组合语言的一些特性旨在防止设计者表达不安全的组合。例如,SmartAdapters中的关联基于两个类中的两个引用(ECore元模型中的Ereference)的链接。当设计者指定要设置其中一个引用时,SmartAdapters会自动修改相关的关联端,减轻设计者设置关联另一端引用的负担,从而减少转换规范的大小。此外,SmartAdapters模型要求每个模型元素通过组合关系(即EMF中的包含属性)最多链接到一个模型元素。当设计者更改模型元素的容器时,组合协议会自动移除容器中包含属性的元素,以强制执行此约束。
2.2 适配器规范语言语义
为了进行静态分析,我们提议使用一种具有明确操作语义的低级组合语言来表达方面模型。我们区分两种类型的模型组合:基本原语和合并。
-
用于操作模型的动作语言
:基本组合原语是对模型元素的简单操作,可以使用诸如Kermeta之类的动作语言轻松实现。该语言提供了对模型元素(创建、更新、删除)和属性(获取、设置、添加、移除)的基本操作符,支持关联,并提供循环和条件语句。图展示了使用这种动作语言定义的任务调度方面的嫁接模型的摘录。所有SmartAdapters提供的基本适配(例如添加超类、在操作中添加参数)都可以使用这些低级原语表达。例如,将超类A添加到类B的适配可以用我们的动作语言表示为:
ADD REFeSuperTypes,A,B,其中A是要添加为父类的类,B是要添加父类的类。 - 高级模型组合操作符 :模型元素的组合也可以通过合并操作符进行,这是一个对称的一对一组合操作符(涉及两个输入模型)。它将表示同一概念不同视图的两个模型元素合并为一个新的或更新版本的模型元素。SmartAdapters模型(SAM)的组合涉及合并SAM中的公共元素。两个SAM的组合基于一个具有参数化语义的合并操作符。该操作符在要合并的SAM之间没有冲突时提供默认的合并行为,例如“具有相同标识符的两个类的成员应统一为一个具有该标识符的复合类”。冲突检测基于以下机制:首先检测具有相同标识符的两个元素,然后比较这些元素的签名,以检查它们是否严格等价。如果签名不相等,则检测到冲突。设计者可以通过注册插件(冲突修复器)来扩展合并语义,以自定义合并行为。
2.3 组合协议分析
我们使用前面提到的语言来描述模型元素的创建和适配的清晰语义。在将方面织入任何模型之前,我们会先对每个组合协议进行先验分析。为了便于分析,我们考虑规范组合协议。
- 规范组合协议 :规范组合协议由所有实际有效果的适配组成,不包含对抗性适配(例如添加/删除同一元素)或中性适配(例如在集合中多次添加同一元素)。非规范协议将被视为错误,并会生成一份报告,指定哪些适配是对抗性的,以帮助设计者重构其方面。
-
影响
:规范组合协议对对象obj的属性p的影响是一个值
∆p,obj ∈Z,计算方式为:∆p,obj = #ADD *p,anyInstance,obj – #DEL *p,anyInstance,obj,它量化了属性大小的增加或减少。
基于上述定义,我们可以独立于可能应用该组合协议的任何基础模型,对其进行静态分析,并定义和形式化了一组规则:
1.
∃CREATEanyMeta,instance ∧∃ADD REFanyPrty,instance,anyTarget ⇒∃ADD CONTAINanyPrty,instance,anyTarget
:此规则检测引用结果模型中不存在元素的悬空引用。
2.
∀obj : Object, p : Property ∈obj,∆p,obj ≤p.upper - p.lower
:该规则检测方面的组合是否遵守元模型中定义的基数。
3.
∃DEL CONTAINp,obj,any ⇒¬∃obj’,p’ | obj ∈obj’.p’
:此规则会发出警告,指出一个模型元素从结果模型中移除,可能导致一些悬空引用。
这些规则允许在将方面实际织入特定基础模型之前检测一些不一致性。我们还可以利用基础模型提供的知识,定义一些特定于模型的规则,在织入之前进行检查。
3. 通过测试验证方面模型
虽然静态分析步骤可以检测到一些错误,但由于接口模型中信息的缺乏,有些错误无法通过静态分析检测到。因此,我们的过程的最后一步是测试方法。
3.1 概述
我们将具有可变性的方面模型视为一个待检查的系统,每个派生的方面模型都可以看作是该系统的一个测试用例。测试的预言机由两种断言组成:
1.
能否执行组合
:如果组合在结束前出现错误,则该方面模型不一致,通常意味着缺少一些约束来正确处理方面模型的变化点。
2.
结果模型是否符合其元模型并遵守其格式良好规则
:
测试过程的最后一步是获取测试数据。我们从接口模型生成一组基础模型,将派生的方面模型应用于每个生成的基础模型。对于每种错误类型,SmartAdapters框架会提供诊断信息,解释测试用例失败的原因。设计者可以根据这些信息,精确分析生成的变体和基础模型,以理解问题所在。
3.2 生成一组基础模型
为了验证组合协议,我们自动生成一组基础模型。从头开始生成基础模型可能既耗资源又耗时,我们只关注派生方面模型可能应用的基础模型,即接口模型匹配的模型。我们采用Sen等人的方法,生成一组完成接口模型的基础模型,以遵守元模型中定义的所有显式和隐式约束。
基础模型主要受接口模型的约束,接口模型为所需的基础模型定义了一组约束。因此,为了自动生成用于测试的基础模型,需要将接口模型中定义的结构信息和不变量解释为一组一致的信息,用于模型合成。在我们的方法中,使用基于一阶关系逻辑语言Alloy的Cartier工具将接口模型转换为约束。解决这些约束后,将从模型组合的输入域中选择符合条件的基础模型。
对于每个组合协议,我们会生成一份报告,指定符合测试预言机标准的织入模型的百分比。这份报告可帮助设计者验证和无效化组合协议的某些变体,但请注意,这并不证明组合是完全安全的。
4. 评估
我们以一个包含可变性的任务调度方面为例,在图中识别出四个派生方面不合理的情况。由于篇幅限制,我们详细分析其中两个有问题的情况:
1.
VMergingTW x VIntroductionSched x VIntroductionTWInheritance
:此情况下的派生方面中,Task和Worker类分别通过合并引入到TaskTarget和WorkerTarget类中,并在这两个合并类之间引入了一个关联。Scheduler类随后被引入,无论SchedulerBase类是否存在于接口模型中,Scheduler类都可以被引入。然而,引入的worker和scheduled关联存在问题,因为每个关联只有一个端点类被引入,即引用了结果模型之外的元素。这一问题通过违反规则1被检测到:
-
∃CREATEclass,Worker ∧∃ADD REFreferenceType,worker,Worker ⇒∃ADD CONTAIN , ,Worker
:Worker类不会被引入到基础模型中,但worker关联会引用它。
-
∃CREATEclass,Task ∧∃ADD REFreferenceType,scheduled,Task ⇒∃ADD CONTAIN , ,Task
:Task类不会被引入到基础模型中,但worker关联会引用它。
2.
VMergingTW x VMergingSched x VIntroductionTWInheritance
:此组合对应的派生方面违反了相同的规则。此外,由于Scheduler类通过合并引入到SchedulerTarget类中,worker和scheduled关联的两个端点都不在结果模型中,因此无法被引用。
通过对派生方面的静态分析,我们可以在织入之前确定这些有问题的情况。在方面模型设计的早期检测到这些问题,有助于设计者识别出在派生过程中缺少禁止这些配置的约束。我们的验证过程包括格式良好规则检查、通过部分评估进行的静态分析和测试,形成了一个模块化的验证过程,允许设计者逐步验证其方面模型。例如,如果静态分析检测到错误,则无需执行测试阶段。
在软件产品线中,确保软件正确性是一个重要问题,尤其是在减少产品族测试数量方面。相关工作主要引入形式化方法,利用软件家族的共性,依靠SAT求解器或模型检查技术来验证测试。
综上所述,我们的方法为面向方面建模中管理可变性复杂性提供了有效的解决方案,通过系统的分析和测试,提高了方面模型的一致性和可靠性。
面向方面建模中管理可变性复杂性
5. 相关工作与讨论
在软件产品线上,确保软件正确性是一个至关重要的问题。由于产品族的多样性,如何减少需要执行的测试数量成为了主要关注点。这其中涉及两个关键问题:一是程序员工作量的增加,二是测试执行所花费的时间。
为了解决这些问题,相关工作主要引入了形式化方法,旨在利用软件家族的共性来达成减少测试数量的目标。这些方法通常依赖于 SAT 求解器或者更广泛的模型检查技术来验证测试。
下面通过表格来对比不同方法的特点:
| 方法 | 优点 | 缺点 |
| — | — | — |
| 手动定义约束 | 可根据具体情况灵活设置 | 耗时、易导致约束过度或不足 |
| 形式化方法(依赖 SAT 求解器或模型检查技术) | 利用共性减少测试数量 | 对技术要求较高,实现复杂 |
| 本文方法 | 系统分析和测试,提高一致性和可靠性 | 需一定的计算资源和时间 |
6. 总结与展望
我们提出的系统方法为面向方面建模中管理可变性复杂性提供了有效的解决方案。通过生成、分析和测试方面族的所有可能变体,我们能够在早期发现并解决潜在的问题,提高方面模型的一致性和可靠性。
以下是整个过程的 mermaid 流程图总结:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B(可变方面):::process
B --> C(生成方面族的变体):::process
C --> D{方面是否一致?}:::decision
D -- 是 --> E(对生成的方面进行静态分析):::process
E --> F{静态分析是否通过?}:::decision
F -- 是 --> G(测试方面组合):::process
G --> H(生成报告):::process
H --> I{是否有错误?}:::decision
I -- 是 --> J(修复方面模型):::process
J --> C
I -- 否 --> K([结束]):::startend
D -- 否 --> L(结束并报告问题):::process
F -- 否 --> L
未来,我们可以进一步优化该方法,例如研究与测试覆盖率相关的方法,在覆盖率和测试成本之间找到更好的平衡。同时,可以探索如何将该方法应用到更复杂的软件系统中,以提高其通用性和实用性。
此外,随着软件技术的不断发展,新的可变性管理挑战可能会不断出现。我们需要持续关注这些变化,不断改进和完善我们的方法,以适应未来的需求。
总之,面向方面建模中管理可变性复杂性是一个持续的研究领域,我们的工作为解决这一问题提供了有价值的思路和方法,未来还有很大的发展空间。
超级会员免费看

被折叠的 条评论
为什么被折叠?



