Software product line engineering¶
ABS supports the development of software product lines with a set of language constructs for defining system variants. Following a feature-oriented software development approach, variants are described as sets of features. Features and their dependencies are specified in a feature model. Each feature has its corresponding ABS implementation. A feature’s implementation is specified in terms of the code modifications (i.e., additions and removals) that need to be performed to a variant of the system that does not include that feature in order to add it. This style of programming is called delta-oriented programming. The ABS code modules that encapsulate feature implementations are called delta modules (deltas).
Delta-oriented programming¶
ABS supports the delta-oriented programming model, an approach that aids the development of a set of programs simultaneously from a single code base, following the software product line engineering approach. In delta-oriented programming, features defined by a feature model are associated with code modules that describe modifications to a core program. In ABS, these modules are called delta modules. Hence the implementation of a software product line in ABS is divided into a core and a set of delta modules.
The core consists of a set of ABS modules that implement a complete software product of the corresponding software product line. Delta modules (or deltas in short) describe how to change the core program to obtain new products. This includes adding new classes and interfaces, modifying existing ones, or even removing some classes from the core. Delta modules can also modify the functional entities of an ABS program, that is, they can add and modify data types and type synonyms, and add functions.
Deltas are applied to the core program by the ABS compiler front end. The choice of which delta modules to apply depends on the selection of a set of features, that is, a particular product of the SPL. The role of the ABS compiler front end is to translate textual ABS models into an internal representation and check the models for syntax and semantic errors. The role of the back ends is to generate code for the models targeting some suitable execution or simulation environment.
DeltaDecl ::= |
|
[ |
|
[ ModuleAccess ] { ModuleModifier } |
|
DeltaParam ::= |
Type ( SimpleIdentifier | QualifiedTypeIdentifier ) |
HasCondition |
|
HasCondition ::= |
|
| |
|
| |
|
ModuleAccess ::= |
|
ModuleModifier ::= |
|
| |
|
| |
|
[ |
|
[ |
|
|
|
| |
|
| |
|
| |
|
|
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
ClassModifier ::= |
|
| |
|
| |
|
| |
|
| |
|
InterfaceModifier ::= |
|
| |
The DeltaDecl clause specifies the syntax of delta modules, consisting of a unique identifier, an optional list of delta parameters, an optional module access directive, and a sequence of module modifiers.
The ModuleAccess clause specifies the semantics of unqualified
identifiers within a delta. Any identifiers without namespace prefix
will be resolved as if they occurred in the module named in the
ModuleAccess clause. A delta can always make additions and
modifications in any module by fully qualifying the TypeName within
module modifiers. New program elements (classes, interfaces, etc.)
with unqualified names are added to the module given in the uses
clause; it is an error to add new program elements with unqualified
names in a delta that does not have a uses clause.
While delta modeling supports a broad range of ways to modify an ABS model, not all ABS program entities are modifiable. These unsupported modifications are listed here for completeness. While these modifications could be easily specified and implemented, we opted not to overload the language with features that have not been regarded as necessary so far.
- Class parameters and init block
Deltas currently do not support the modification of class parameter lists or class init blocks.
- Functions
Deltas currently only support adding functions, and adding and modifying data types and type synonyms. Removal is not supported.
- Modules
Deltas currently do not support adding new modules or removing modules.
- Imports and Exports
While deltas do support the addition of import and export statements to modules, they do not support their modification or removal.
- Main block
Deltas currently do not support the modification of the program’s main block.
The feature model¶
Software variability is commonly expressed using features which can be present or absent from a product of the product line. Features are defined and organised in a feature model, which is essentially a set of logical constraints expressing the dependencies between features. Thus the feature model defines a set of legal feature combinations, which represent the set of valid software variants that can be built.
Specifying the feature model¶
The FeatureModel clause specifies a number of “orthogonal” root feature models along with a number of extensions that specify additional constraints, typically cross-tree dependencies. Its grammar is as follows:
FeatureModel ::= |
{ |
FeatureDecl ::= |
FName [ |
FeatureExtension ::= |
|
Group ::= |
|
|
|
Cardinality ::= |
|
AttributeDecl ::= |
|
| |
|
| |
|
| |
|
| |
|
Limit ::= |
IntLiteral | |
Constraint ::= |
Expr |
| |
|
| |
|
| |
|
| |
|
Expr ::= |
|
| |
|
| IntLiteral |
|
| StringLiteral |
|
| FName |
|
| AName |
|
| FName |
|
| UnOp Expr |
|
| Expr BinOp Expr |
|
| |
|
UnOp ::= |
|
BinOp ::= |
|
Attributes and values range over integers, strings or booleans.
The FeatureDecl clause specifies the details of a given feature, firstly by giving it a name (FName), followed by a number of possibly optional sub-features, the feature’s attributes and any relevant constraints.
The FeatureExtension clause specifies additional constraints and attributes for a feature, and if the extended feature has no children a group can also be specified. This is particularly useful for specifying constraints that do not fit into the tree structure given by the root feature model.
Here is an example feature model for the DeltaResourceExample
product line, defining valid combinations of features and valid ranges
of parameters for cost, capacity and number of machines:
root Calculations {
group oneof {
Wordcount,
Wordsearch
}
}
root Resources {
group oneof {
NoCost,
Cost { Int cost in [ 0 .. 10000 ] ; }
}
}
root Deployments {
group oneof {
NoDeploymentScenario,
UnlimitedMachines { Int capacity in [ 0 .. 10000 ] ; },
LimitedMachines { Int capacity in [ 0 .. 10000 ] ;
Int machinelimit in [ 0 .. 100 ] ; }
}
}
Feature model reflection¶
There is support for limited reflection on the feature model and
configured product in the module ABS.Productline. The datatype
Feature contains constructors for all feature names. The function
product_features returns a list of features contained in the
current product, and product_name returns the name of the product,
or the empty string if no product was specified.
The following sample code shows the usage, assuming that product
Product was generated:
module Test;
import * from ABS.Productline;
{
List<Feature> foo = product_features(); // => Cons(FeatureA, Cons(FeatureC, Nil))
String name = product_name(); // => "Product"
}
productline Test;
features FeatureA, FeatureB, FeatureC;
product Product(FeatureA, FeatureC);
Software product lines and products¶
A (software) product line is a set of software variants that can be built by selecting any combination of features allowed by the feature model and applying the deltas that provide the implementation for those features to the core program. How features are associated with their implementation is defined in ABS with a SPL configuration.
An ABS product is simply a set of features associated with a name.
Specifying the product line¶
The ABS configuration language links feature models, which describe the structure of a SPL, to delta modules which implement behavior. The configuration defines, for each selection of features satisfied by the product selection, which delta modules should be applied to the core. Furthermore, it guides the code generation by ordering the application of the delta modules.
Configuration ::= |
|
Features ::= |
|
DeltaClause ::= |
|
DeltaSpec ::= |
DeltaName [ |
DeltaName ::= |
TypeId |
DeltaParams ::= |
DeltaParam { |
DeltaParam ::= |
FName {vbar} FName |
AfterClause ::= |
|
WhenClause ::= |
|
AppCond ::= |
AppCond |
| AppCond |
|
| |
|
| |
|
| FName |
Features and delta modules are associated through application conditions (a.k.a. activation conditions), which are logical expressions over the set of features and attributes in a feature model. The collection of applicable delta modules is given by the application conditions that are true for a particular feature and attribute selection. By not associating the delta modules directly with features, a degree of flexibility is obtained.
Each delta clause has a DeltaSpec, specifying the name of a delta module name and, optionally, a list of parameters; an AfterClause, specifying the delta modules that the current delta must be applied after; and an application condition AppCond, specifying an arbitrary predicate over the feature names (FName) and attribute names (AName) in the feature model that describes when the given delta module is applied.
Example:
productline DeltaResourceExample;
features Cost, NoCost, NoDeploymentScenario, UnlimitedMachines, LimitedMachines, Wordcount, Wordsearch;
delta DOccurrences when Wordsearch;
delta DFixedCost(Cost.cost) when Cost;
delta DUnboundedDeployment(UnlimitedMachines.capacity) when UnlimitedMachines;
delta DBoundedDeployment(LimitedMachines.capacity, LimitedMachines.machinelimit) when LimitedMachines;
Specifying products¶
ABS allows the developer to name products that are of particular interest, in order to easily refer to them later when the actual code needs to be generated. A product definition states which features are to be included in the product and sets attributes of those features to concrete values. In the simplest case products are declared directly, by listing the features that they include. It is also possible to declare products based on other products using product expressions. Product expressions use set-theoretic operations (union, intersection, complement) over products and sets of features.
Selection ::= |
|
ProductExpr ::= |
|
| ProductExpr |
|
| ProductExpr |
|
| ProductExpr |
|
| TypeId |
|
| |
|
FeatureSpecs ::= |
FeatureSpec { |
FeatureSpec ::= |
FName [ AttributeAssignments ] |
AttributeAssignments ::= |
|
AttributeAssignment ::= |
AName |
Here are some product definitions for the DeltaResourceExample
product line:
product WordcountModel (Wordcount, NoCost, NoDeploymentScenario);
product WordcountFull (Wordcount, Cost{cost=10}, UnlimitedMachines{capacity=20});
product WordsearchFull (Wordsearch, Cost{cost=10}, UnlimitedMachines{capacity=20});
product WordsearchDemo (Wordsearch, Cost{cost=10}, LimitedMachines{capacity=20, machinelimit=2});
Here are some product definitions for the CharityOrganizationExample with ProductExpr:
product Org1 = SekolahBermainMatahari || {Continuous};
product Org2 = SekolahBermainMatahari || {Continuous, Automatic_Report};
product Org3 = SekolahBermainMatahari || PKPU;
product Org4 = SekolahBermainMatahari || PKPU || RamadhanForKids;
product Org5 = SekolahBermainMatahari || PKPU || RamadhanForKids || BeriBuku;
product Org6 = SekolahBermainMatahari && RamadhanForKids;
product Org7 = SekolahBermainMatahari && BeriBuku;
product Org8 = SekolahBermainMatahari - {Eventual};
product Org9 = SekolahBermainMatahari - {Eventual, Income};
product Org10 = SekolahBermainMatahari && RamadhanForKids || {Money, Item};
product Org11 = SekolahBermainMatahari && (RamadhanForKids || {Money, Item});
Checking the SPL¶
Because the number of variants in an SPL can be very large, checking them efficiently (e.g., to ensure that they are all well-typed) is challenging. Building each variant in order to type-check it is usually not feasible from a performance perspective. Instead, the ABS compiler employs a number of efficient consistency checks. These fall into two categories.
Family-based analysis steps operate on the SPL definition itself,
Analysis steps operate on lightweight abstractions of the SPL variants.
These checks are performed automatically upon compilation and help ensure that all variants defined by an SPL specified in ABS can be built and are well-typed ABS programs.