抽象行为规格化的软件产品线可变性建模方法
2020-04-09
(浙江工业大学 计算机科学与技术学院,浙江 杭州 310023)
软件复用被认为是解决软件危机、实现软件产业工业化生产方式的有效途径。软件产品线(Software product lines, SPLs)是实现系统化复用的基础,它采用以资产库为核心的架构平台和完备的资产开发和管理工具,支持以复用为目的的组件设计、开发和维护,通过大粒度的组件装配完成产品建造。
微服务架构是一种新兴的软件架构风格。它将软件系统分解成一个个微型且互相连接的服务,每个服务都有自己特定的功能,使得整个系统变得更加模块化。当系统需求发生变化时,只需改变服务的组合模式即可。但是系统的模块化不代表各模块完全独立,相当多的服务需要在多个模块配合下完成。当这些服务发生需求变化后,还是需要进行一些复杂的连带的系统变动。因此,对于微服务架构软件的可变性建模(Variability modeling)变得十分重要。笔者在特征模型和用例模型的基础上,将可变性建模方法应用到目前广泛应用的微服务架构中。通过其可变性建模方法中的可变性管理特性,来降低需求变更而导致的工作量。
1 相关工作
1.1 微服务架构
复杂而巨大的单体式应用不利于持续性集成与部署。许多公司,比如Amazon,eBay,NetFlix,通过采用微处理结构模式解决上述问题。其思路是将应用分解为小的、互相连接的微服务。一个微服务一般完成某个特定的功能,比如下单管理、客户管理等等。每一个微服务都是微型六角形应用,都有自己的业务逻辑和适配器。一些微服务还会发布API给其他微服务和应用客户端使用[1-2]。
在微服务架构中,软件系统各组件之间通过服务契约关系相互合作,简单讲就是服务输入输出的语义。在Restful service的实现中,消费者只需知道服务的根资源的URI,就可以由根资源引导到所需的资源。即消费者和发布者的耦合只在于根资源的URI以及各资源及其操作的语义。Restful service充分利用了HTTP协议本身语义的无状态性,在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度,更容易开发、理解和维护。
1.2 软件产品线工程
软件产品线是指具有一组可管理的公共特性的软件密集性系统的合集,这些系统满足特定的市场需求或任务需求,并且按预定义的方式从一个公共的核心资产集开发得到。基于软件产品线的系统,需要按照指定方式进行公共资产库的开发。与独立开发、从零开始开发、随机开发等方式相比较,可以获得显著的生产经济效益。每个产品都由来自公共资产库中的组件组成,然后按照预先定义的变化机制,如参数化或继承,对这些组件进行必要的裁剪,添加任何必须的新组件,根据一个产品线范围内的公共架构来组装这些组件。
可变性建模是软件产品线工程中的核心步骤。软件产品线工程允许通过定义产品之间的共性和差异,在单个开发周期中开发多个软件产品[3]。它将产品表示为一系列功能的组合,因此正好适用于微服务模块化的特性。
可变性建模方法通过特征模型和用例模型来表现其可变性[4]。卡内基梅隆大学提出的FODA采用树形结构将特征进行模块化,通过特征之间的关联进行领域分析。之后在FODA的基础上也提出了许多特征建模方法。如Zhang提出的基于角色的特征模型组件方法[5],以及Rahman等提出的基于贝叶斯网络的特征建模方法[6]。在用例模型方面,罗代忠等提出基于UML软件产品线建模方法[7],将统一建模语言UML中的用例图应用到可变性建模当中。张元鸣等提出了一种管理导向的可变性建模方法,在特征和用例的基础上引入了管理导向的理念[8-10]。但这些方法都倾向于采用图形元素的方式来描述可变性。
1.3 抽象行为规格化
ABS(抽象行为规格化)是一种用于建模分布式的、面向对象的系统的建模语言,它是完全可执行的,并且高度支持可变性建模,因而特别适用于软件产品线工程。欧盟2008年启动ABS研发工作,并将其用于欧盟的“高可适应及可信任软件”(Highly adaptable and trustworthy software, HATS)项目中[11]。ABS模型所包括的5 个语言层为
1)Core(核心)ABS:提供功能化的和面向对象的编程构造,用于说明对软件产品线上所有产品都具有的“内核”产品。
2)特征模型:定义软件产品线的特征及其相互依赖。
3)Delta(增量)模型:定义特征的实现。Delta模型通过在内核模型之上执行添加、删除、修改操作(涉及类、接口、属性、方法)来实现特征。
4)产品线配置:定义Delta模型和特征模型之间的连接关系。一个Delta可以被用在多个特征上,一个特征可能由多个Delta实现。产品线配置定义了两者之间的关系。
5)产品选择:将产品定义为特征的集合。
与面向对象的编程语言相比,ABS从数据结构的低级实现选择中抽象出来。与UML图等面向设计的语言相比,它可以执行并模拟系统的控制流程;通过分离执行的资源成本和(虚拟)位置的资源能力之间的关注来支持部署建模,可以在模型内部进行部署决策,因此特别适用于使用云API与云供应层进行交互的场合。
2 基于service Delta可变性表示机制
软件产品线工程包含领域工程和应用工程两个部分。领域实现是基于领域分析实现可重用工件的过程,在ABS中,此过程由核心和增量实现。核心是包含产品共性实施的基本产品。增量是一套实现产品变化的Delta模块。增量模块用于实现特征模型中的功能。Delta模块和功能之间的相关性由产品线配置协调。其增量模型举例描述如下:
Delta AlternativePath;
modifies class ClientJobImpl {
modifies Maybe
id = “data2/” + id;
Maybe
return res;
}
}
上述例子描述了一个ClientJobImpl的一个增量实现,和已有软件模块的不同之处是,它操作保存在另一文件夹里的备份数据。该例显示它需要修改ClientJobImpl类中的方法file,这个方法带有一个字符串参数id,并调用该类已有的方法。
与其他基于数学符号表示的可变性建模方法不同,ABS采用了类似编程语言的方式描述组件的可变化特性和可替换特性,可以更加迅速地应用于开发实践。笔者在ABS语言的基础上,针对web应用,提出了service Delta特征工程方法。
定义1特征集可表示为一个七元组,即
FG=
式中:Fname代表特征名称,用以保证特征的唯一性;Ftype代表特征可选类别,即强制(Mandatory)和可选(Optional)两种类型;Flayertype代表特征层级,包括根特征(Root)、对象特征(Object)、路由特征(Route)以及功能实现特征(Implement);Fdescription代表特征描述,用于对该特征功能进行描述;Fselect代表特征选择情况;M代表该特征所属模块;Fc代表特征所包含的约束集,描述了该特征与其他特征之间的连接关系。
定义2特征间的关系可以表示为一个三元组,即
RG=
也可以表示为
式中Rtype表示特征约束或者关系类型,包括父子特征关系(如parent,child,aggregation,generalization,implemented-by)以及约束关系(如exclude,require),选择关系(如alternative,mutiple)等等,比如
代表F1特征与F2特征之间存在需要关系。若
则代表F3与F4两个特征之间拥有多选一的关系。
定义3模块视图集可定义为一个三元组,即
MG=
式中:Mname代表模块名称;Mselect代表模块的选择情况;Mtype用于表示该模块为强制模块还是可选模块。每个模块视图下都会包含一个从根特征出发的特征树,根特征中的Fselect属性和Ftype属性与模块视图中的Mselect属性和Mtype属性相互对应。
定义4特征模型定义为一个六元组,即
FM=
FT={Mandatory,Optional}
FLT={Root,Object,Route,Implement}
RT={parent,child,aggregation,generalization,implemented-by alternative,multiple,exlcude,require}
式中:FG表示构建特征模型所需的特征集合;MG表示特征模型中包含的模块视图集合;RG表示特征之间的约束集合;FT表示特征选择类型集;FLT表示特征层级类型集;RT表示约束类型集。
由于领域特征模型在构建过程中往往存在特征节点繁多且依赖关系复杂的问题,使得特征建模时不可避免地出现相互矛盾的关系,需要对模型中的约束关系进行检查。笔者构建了8 条领域特征模型约束规则来保证领域特征模型的完整性以及一致性,具体约束定义如下:
1)特征唯一性,即特征集合中的各个特征名称互不相同,以维护特征的唯一性,其计算式为
∀f1,f2∈FG,∃f1.Fname=f2.Fname
2)对于所有约束,其起始特征与目标特征不能相同,即
∃r∈RG,r.Fformer=r.Flatter
3)关系集合中所有处于关系中的特征都必须来源于特征集合中,即
∀r∈RG,r.Fformer∈FG∧r.Flatter∈FG
4)除了根特征之外,特征集合中余下的所有特征都包含有父特征,即
∀f∈FG,∀r∈f.Fc∧f.Ftype≠root,∃f2∈FG→r.Fformer=f2∧r.Rtype=parent
5)特征集合中的任意两个特征,不能同时存在需要和互斥两种关系,即
∀r1,r2∈RG,∃f1,f2∈FG→((r1.Fformer=f1)∧(r1.Flatter=f2)∧r1.Rtype=require)∧((r2.Fformer=f1)∧(r2.Flatter=f2)∧r2.Rtype=exclude)
6)对于特征集合中的同一批特征,它们不能同时拥有多选一以及多选多两种约束机制,即
∀f∈FG,∀r1,r2∈f.Fc,∃f2∈FG→(r1.Flatter=f2)∧(r1.Rtype=alternative)∧(r2.Flatter=f2)∧(r2.Rtype=multiple)
7)在特征集合中两个强制特征之间不能存在排斥关系,即
∀f1,f2∈FG,∃r∈RG→r.Fformer=f1∧r.Flatter=f2∧r.Rtype=exclude∧f1.Ftype=Mandatory∧f2.Ftype=Mandatory
8)在多选一特征集合中,两个特征之间不能存在需要关系,即
∀f∈FG,∃r1,r2∈f.Fc→(f1=r1.Flatter)∧(f2=r2.Flatter)∧(r1.Rtype=alternative)∧(r2.Rtype=alternative)∧(require(f1,f2)∨require(f2,f1))
式中require函数用于描述两个特征之间存在需要关系。
这些规则采用一阶逻辑表示,因此可以用通用的一阶逻辑分析器进行验证,如对强制性的检查描述如下:
module feature/FeatureModel
sig Feature{}
disj sig Concept extends Feature {
holds: set Feature
} { this in holds}
func Mandatory(c: Concept, pf: Feature, s: set Feature)
{ pf !in s
pf in c.holds => all f:s | f in c.holds
pf ! in c.holds => all f:s | f !in c.holdes
}…
3 可变性建模过程
由于对象特征主要从业务需求中提取,而静态资产则是数据模型的静态描述,并为路由处理层提供面向对象的数据访问方法,两者之间具有一定的相似之处,因此对这两者之间建立映射关系,即一个对象特征对应一个数据模型文件。图1展示了对象特征与静态资产间的映射关系。
图1 对象特征映射策略
路由特征从属于对象特征且主要用于表示业务对象的功能需求,而业务资产中的API则对应于系统中的各个业务请求,每个业务请求都会对应于控制器文件中的单个业务逻辑函数。因此可以将路由特征同业务资产中的API以及API对应的业务逻辑函数进行映射。此外,通用资产不直接与特征模型进行映射,它通过与业务资产之间的调用关系间接地与特征模型相关联。路由特征与业务资产之间的映射策略以及业务资产与通用资产间的需求关系如图2所示。
图2 路由特征映射策略
当路由特征存在子特征时,则根据功能实现特征之间的选择约束又可以分为两种映射情况。第一种为当功能实现特征之间为多选一约束时,如图3中的特征a与特征b,他们分别与不同的业务逻辑函数进行映射,但是它们使用的是同一个API,即父特征(路由特征)映射的API。第二种是当选择约束为多选多时,如图3中的特征c与特征d,其分别对应各自的API以及业务逻辑函数,而它们的父特征则不进行特征映射。
图3 功能实现特征映射策略
4 应用实例
以企业ERP软件中的生产订单管理为例。BYMQ是一家专业设计、生产、安装建筑幕墙的企业,随着建筑的个性化特征日益明显,要求企业ERP系统需要具备足够的灵活性,能够更广泛地支持客户的个性化需求。在对企业原有的单体结构ERP系统进行改造的过程,笔者分步实现了整体架构的微服务化,新增了客户网上下单与更改管理、供应商网上接单与更改管理等模块。新系统设计时,使用ABS语言进行模型定义,包括遗留系统的反向建模和新增模块的建模工作,再由模型语言自动生成web服务框架脚本。
ERP中,生产订单除了普通订单(原料采购、加工制造、成品发货都由本企业完成)外,还包括来料加工(OEM)、委托外加工(Outsourcing)等可变性。通过对用户(领域专家)的多次访谈,列出生产订单管理的4 个特征:Type,Normal,OEM,Out。软件产品线要能够生成3 种微服务产品: normalOrder(普通订单),OEMOrder(来料加工订单),委外加工订单(OutOrder)。normalOrder服务包含Type和Normal特征,OEMOrder服务包含Type和OEM特征,委外加工订单服务包含Type和Out特征。
4.1 特征模型
首先,为产品线定义一个特征模型。ABS中的特征模型本质上是将特征图进行文本表示。图4为生产订单的特征图,它具有Type特性,具有两个子特性Normal和OEM。
图4 订单特征模型
如果选择Normal特征,则加工费属性的值必须为0,而选择OEM特征时,加工费属性则必须大于0。Normal和OEM之间的弧意味着只允许选择一个特征,也就是说普通订单和来料订单中只能选择一个,其ABS特征模型代码如下:
Root Order {
group allof {
Type {
Int fee;
group oneof {
Normal {
ifin: Type.fee=0;
}
OEM {
ifin: Type.fee>0;
}
}
}
}
}
4.2 微服务模块
微服务模块主要是进行一个或多个微服务的实现。例如,在生产订单模块中,其中包含两个微服务,即receive(发票接收),cancel(撤销订单)。该模块包括资源层(MOrderResource),服务层(MOrderService),领域层(MOrderModel),持久层(MOrderDbImpl和ABS ORM)。笔者只关注服务层。
生产订单模块的服务层实现提供了两个微服务,发票接收和撤销订单。撤销订单的实施应根据发票ID对数据库执行查询以获取订单模型,然后在发票模型上调用cancel方法并将其保存回数据库。发票接收服务遵循相同的模式来执行操作。撤销订单的实施描述如下:
class OrderServiceImpl implements OrderService {
Order cancel(String id){
OrderDb odb = new local OrderDbImpl();
Order o = odb.findById("MOrderModel.orderImpl",id);
o.cancel();
o.update();
return o;
}
}
4.3 Delta模块
这一步中为特征模型中定义的每一个特征创建Delta模块。将各个Delta模块命名为DeltaType,DeltaNormal,DeltaOEM。以DeltaOEM模块为例,它通过删除原本的费用变量并重新添加赋予新值的变量来修改类OrderImpl,其实施描述如下:
delta DeltaOEM(Int f);
uses MOrderModel;
modifies class OrderImpl {
removes Int fee;
adds Int fee = f;
}
4.4 路由配置
路由配置用于配置每个微服务的URL。路由配置的格式定义为
“
式中:URL为用户调用微服务功能的地址;资源类名为负责处理微服务请求的类的名称;方法名为微服务中方法的名称。生成订单的路由配置代码(例如,/ order/ cancel.abs是访问撤销订单的URL)描述如下:
class RouteConfigImpl implements RouteConfig {
String route(String url){
String r = case url {
"/order/receive.abs" => "MOrderResource.OrderResourceImpl@receive";
"/order/cancel.abs" => "MorderResource.OrderResourceImpl@cancel";
}
return r
}
}
4.5 模型验证与产品配置
该步骤中,采用一阶逻辑方法对模型进行验证,若发现问题,则退回到4.1节步骤,修改模型,并重新验证。若验证通过,则进行产品配置,定义特征和Delta模块之间的关系。例如,如果Type被选中,则Delta模块DeltaType将应用于Type特征,其实施描述如下:
productline Order;
features Type, Normal, Incoming;
delta DeltaType(Type.fee)when Type;
delta DeltaNormal after DeltaType when Normal;
delta DeltaOEM(Type.fee)after DeltaType when OEM;
4.6 产品选择
这一步需要定义生成的所有产品。本例中,将生成两个产品,即NormalOrder和OEMOrder。NormalOrder中包含有Type及Normal特征。OEMOrder则具有Type和OEM特征,其实施描述如下:
product NormalOrder(Type(fee=0), Normal);
product OEMOrder(Type(fee>0), OEM);
4.7 生成并运行产品
如果所有步骤都已完成,则使用命令ant-Dabsproduct = <产品名称> abs.deploy生成产品。产品名称为上一步定义的名称。例如,如果要生成NormalOrder,输入ant-Dabsproduct = NormalOrder abs.deploy即可。
5 结 论
基于特征的建模方法可以提供产品家族产品特征的简洁表示,特征模型的结构良好,通过识别特征之间的关系,将各个单独的特征组织成一个有机的整体。但是该方法的一个缺点是无法在特征模型中实现特征到核心资产的映射。为了实现特征到核心资产的映射,提出了利用基于抽象行为规格化语言,利用特征模型和UML模型模板实现可变性的建模,每个模型模板中的元素与特征关联。同一个特征跟需求规格、设计模型和实现等核心资产都有关联。从开发实践结果分析,采用形式化方法描述软件产品线建模,可以通过一致的视图、灵活的抽象层次、准确地描述软件产品线中的主要要素及其动态行为,使得产品线模型与实际开发过程之间的粒度和抽象层次更趋于一致,有利于软件工程环境和实际开发环境更加紧密地集成。