FeatureIDE – A novel approach to developing software
Fabian Benduhn and Thomas Thüm delve into feature-oriented programming with Eclipse
One size fits all? In software development this rule can hardly be applied. Developing software products that try to include every possibly useful function is often not a good idea. While unnecessary functions are a possible source of errors and may confuse the user, it is often not possible to include them all in one product. Embedded systems, smart phones, or automotive systems are typical examples for domains in which all-in-one software is not applicable. Most software products today come at least in a set of variants to let the customer choose the one that he prefers – or can afford.
Developing Software Variants
A common technique to manage different variants of software products is to use version-control tools like SVN, GIT, or Mercurial. Following this approach, each variant is being developed in its own branch. However, most variants will share big parts of code and differ only in details or certain features. When developing a new variant, you will probably copy the whole source code of an existing variant to a new branch and then start to modify or extend it. But, using version-control tools for the implementation of software variants comes with disadvantages:
- Fixing a bug in one variant makes it often necessary to apply the changes in all other variants thatalso contain this piece of code – resulting in redundant work.
- Creating a variant is complex and expensive. Thus, variants are not developed in advance andthere is a long time to market.
The Eclipse plug-in FeatureIDE offers a novel approach to develop different software variants while avoiding these problems. It allows programmers to develop software variants in a user-friendly manner providing a comfortable way to reuse code which is needed in multiple variants.
Feature IDE by Example
The basic idea of FeatureIDE is to develop every feature separately. Variants can afterwards be generated automatically by selecting and combining the desired features. We show how this works with a small calculator example.
Mapping Code to Features
In FeatureIDE, the whole application is divided into parts representing different features. While this may sound similar to the concept of classes there is an important difference. A feature in our sense always represents a certain aspect of the application with meaning to the end-user, e.g., the operations Addition and Multiplication are features, because it makes a difference to the user whether these operations are included in the final product.
Every feature can be related to an arbitrary number of software artefacts. In FeatureIDE, these artefacts can be classes, methods, fields or even single statements as well as additional resources like graphics or user-documentation. Especially, the option to change only parts of a method offers great flexibility in the design of features. Figure 1 shows the mapping of features to code in our example. Columns are related to the features and rows are related to classes or other documents.The cells contain more detailed information about the artefacts that belong to the particular feature.
Figure 1: Mapping Code to Features
We can see that the feature Addition contains three methods and one field in the Calculator class.The class Addition Operation is also introduced by the feature Addition. Feature Graphical contains the User Interface class, which contains five methods and two fields.
Implementation of Features
Figure 2 shows the source code of the features Addition and Multiplication. Feature Addition introduces the methods initCalculator() and initUI(), which contain functionality to supply our calculator with an addition operation. Both methods are extended by the feature Multiplication in order to extend the calculator with a multiplication operation. We use the keyword original() to access the original method, as it is defined in feature Addition. The keyword original() is similar to the keyword super(), but does refer to a member of another feature instead of a member of the superclass.
Figure 2: Feature Implementation
After implementing the features we can generate variants of our calculator. In order to generate a tailor-made application, we select a set of features that we want to include. A selection of features is called configuration and can be created with a graphical editor (see Figure 3). Once we have chosen the desired feature, the resulting variant is generated automatically and is ready to use. . Variants can be tailored to functional requirements, such as addition and multiplication, as well as non-functional requirements, such as program size and execution time.
Figure 3 – Selecting Features
Specifying Valid Combinations of Features
Certain combinations of features may not lead to useful variants (e.g., mobile and PC support must not be selected together in our example). FeatureIDE guides us when selecting features by disabling options that lead to such invalid configurations, e.g. after selecting Mobile the feature PC will be disabled for this configuration because these two features are alternative. Alternative means that our application does not support both features in the very same variant.
Figure 4: Feature Model
A programmer creates a feature model to define how features relate to each other. A feature model is basically a hierarchy of features that can be created and edited graphically and textually in FeatureIDE (see Figure 4). The root feature (feature Calculator in our example), must be selected in every configuration and contains functionality that is used in every variant. Other features can be added to the feature model in a couple of ways representing different forms of dependency. Generally, a connection in the feature model represents a dependency between two features. If two features are connected we call the feature that is located higher within the hierarchy parent feature and the other one child feature. A child feature can only be selected if the connected parent feature is selected, e.g. Multiplication can only be selected if Operations is selected. A feature can have multiple child features but only one parent feature.
Features can be related to their parent in different ways. In our example, the feature Addition is mandatory and must be selected in every configuration while the feature Multiplication is optional and can be left out. The features Mobile and PC are alternatives and cannot be selected together,Graphical and Console are related in an Or group, which means that at least one of them must be selected in a configuration. Further dependencies can be given using arbitrary propositional formulas.
The feature model also helps to organize the features in a structured manner (e.g. it is easy to understand that the features Addition and Multiplication are considered as operations). This is especially helpful in larger projects in which feature dependencies can be more complex than in our example.
FeatureIDE is being developed as an academic open source tool. It supports developing software variants in different programming languages like Java, C, C++, C#, Haskell, XML or JavaCC. The technique presented in this article is called feature-oriented programming. FeatureIDE also allows the usage of other approaches based on pre-processors (Antenna, Munge), aspect-oriented programming (AspectJ), and delta-oriented programming (DeltaJ). FeatureIDE is constantly being extended and improved to ease the development of software variants.
With FeatureIDE it is possible to create software variants efficiently. Its seamless integration into the development environment Eclipse makes it easy to start developing. Whether you want to manage only a few variants of your software product or a large-scale software product line – there is not much to learn to start with FeatureIDE. Many interesting example projects and a cheat sheet are included to assist you with the first steps. FeatureIDE is available as an open source Eclipse plug-in over the Eclipse Marketplace or the featureIDE website