Select Page

Customizable software cleverly implemented?!

Implementation mechanisms of adaptable software in comparison

Authors: Martin Becker and Bo Zhang, Fraunhofer Institute for Experimental Software Engineering (IESE)

Contribution – Embedded Software Engineering Congress 2016

In the successful implementation of reusable and configurable software modules, one of the most important steps is the selection of suitable variability mechanisms. Prominent examples include conditional compilation with the preprocessor, module selection, and parameterization in conjunction with conditional execution. However, a look at everyday development reveals that these mechanisms are often chosen carelessly and used arbitrarily. The consequence is often unwieldy and difficult-to-maintain software monstrosities. This article provides an overview of common variability mechanisms, highlights pitfalls, and presents best practices using practical examples.

Variability drivers in embedded systems

The demand for customized software solutions is growing unabated. The main drivers behind the product variants offered are primarily differing customer needs, technological advancements such as new multi-core processors, and cost pressures. These drivers are generally difficult to influence, making it challenging to avoid offering such variants altogether.

Especially regarding the software component of embedded systems, there's a prevailing opinion that it can be adapted quickly and cost-effectively to new requirements, which, compared to hardware, is initially true due to its extremely low production costs. Naturally, the necessary adjustments are then shifted to the software. Over time, this quickly leads to highly customizable, configurable, and parameterizable software solutions that become increasingly difficult to maintain and configure. Many embedded software developers have experienced this preprocessor or Makefile hell firsthand in one form or another.

Variability mechanisms in comparison

The differences between product variants can be implemented in various ways. These are referred to as variability mechanisms. Prominent examples include conditional compilation with the preprocessor, module selection, and parameterization combined with conditional execution. Variability mechanisms thus allow the implementation of variable product characteristics in the source code and other development artifacts (e.g., test cases, requirements, design models).

To promote a well-considered selection of variability mechanisms, we present typical variability mechanisms in the following overview (see Table 1) and characterize them along key properties. The comparison is based on corresponding overviews [1][2][5][6] that have been developed in the software product line engineering community over the last two decades.

According to our industrial experience and recent studies [3][4][7][8], the following mechanisms are used in particular to implement software variants in the context of embedded software:

  • Cloning – Software versions are copied between different projects and then modified.
  • Conditional compilation – The C preprocessor allows code blocks to be shown or hidden via a switch.
  • Conditional execution – Code blocks are activated/deactivated via variables (parameters) using control constructs in programming languages.
  • Module exchange – Build systems, such as make, allow the selection of modules to be used during the build process.

Furthermore, the following mechanisms can also be found in industrial practice:

  • Polymorphism – Language constructs such as function pointers, overloading, or virtual methods can be used to select between different implementations at runtime.
  • Aspect orientation – Variable aspects can be subsequently woven into components using appropriate weavers (for C, Java).
  • Frame Technology – Using dedicated preprocessors, the software to be built can be specifically adapted in a preprocessing step. A prominent example is Paul Basset's Frame Technology.

The following general aspects should be considered when selecting mechanisms:

  • Binding time: When is the variability bound, i.e., when is the specific variant formed in the artifacts?
  • Granularity: How fine can the changes be that can be made between the variants, e.g., individual lines, blocks, files, modules, subsystems?
  • Explicit points of variation: Can the points where the variants differ be easily located and linked to the corresponding variable characteristics?
  • Variant isolation. Is the implementation of a single variant isolated from the others, or are all variants contained within a single file?
  • Open variation: Is it possible to add new variations without affecting existing ones?
  • Non-code artifacts: Can the mechanism also be used beyond code?
  • Default values: Are default implementations supported?

The above mechanisms can be characterized with regard to their properties as follows.

 

mechanism

Techniques

Binding time

Granularity

Explicit variation points

Insulation variants

Open variation

Non-code artifacts

Default values

Cloning

Copying artifacts, branches in configuration management

Build time

all

Implicitly

Yes

no

Yes

no

Conditional compilation

preprocessor

Build time

all

Explicitly

no

no

Yes

Yes

Conditional execution

conditional instructions

Run time

limited

Implicitly

no

no

no

no

Polymorphism

Function pointer, overloading, etc.

mostly runtime

limited

Implicitly

Yes

Yes

no

no

Module exchange

Build system

mostly runtime

limited

Implicitly

Yes

Yes

Yes

no

Aspect orientation

Aspect Weaver

mostly runtime

limited

Implicitly

Yes

Yes

Yes

Yes

Frame Technology

Frame adjustment

Build time

all

Explicitly

Yes

Yes

Yes

Yes

Table 1: Characterization of the variability mechanisms

Practical experience with variability mechanisms

This section examines the practical application of variability mechanisms, discusses their practical advantages and challenges, and provides corresponding recommendations.

Advantages, challenges and recommendations are listed in the following table.

Mechanisms Practical advantages Practical challenges Recommendations
Cloning Quick implementation with minimal effort. Independent of other variants. Applies to any artifact type and size. High (long-term) maintenance costs. Incomplete propagation of changes and bug fixes, leading to lower code quality. Low overhead for short-lived clones. Changes should be clearly localized and managed. Periodic clone analysis and refactoring to other mechanisms should be performed to address maintenance issues.
Conditional compilation Easy to implement. All granularities. Explicit variation points. No runtime impact (resource requirements). #ifdef code is difficult to understand due to #ifdef nesting, mixing, dispersion, etc. #ifdef code is prone to erosion and is often difficult to maintain during evolution. Naming guidelines enable easy identification and analysis of variation points.

Analyze and actively avoid/reduce the unnecessary complexity of the #ifdef code. Rebuild in case of maintenance problems.

Conditional execution Easy to implement and understand. Supports runtime binding. High flexibility. Limited to small granularity. Difficult to distinguish between variation logic and code functionality. Runtime overhead. Consider whether the commitment for the duration of the contract is absolutely necessary.

If necessary, use a different mechanism, e.g., conditional compilation.

Polymorphism The separation of common and variant elements. High flexibility. Each variant element can develop in isolation. Reduced efficiency due to the fragmentation of variant elements. Increased risk of software errors. If problems arise, module replacement could be an alternative.
Module exchange Advantages of polymorphism: No runtime impact. Variation points and variant elements are difficult to identify and understand. Managing variation points and variant elements with dedicated models with suitable tool support, e.g., generating the corresponding Makefiles.
Aspect Orientation Advantages of polymorphism: Clear separation of changes from commonalities. Default support. Learning effort. Increases code size. Effective code is generated/modified. Requires revalidation. Low code readability. Use with caution. If you experience adverse effects, switch to other methods.
Frame Technology Advantages of polymorphism: No limited granularity. No runtime impact. Explicit variation points. Little known. Requires special tools. Requires revalidation. Use with caution. If you experience adverse effects, switch to other methods.


Table 2: Practical experience with variability mechanisms

Generally speaking, in the past, resource constraints led to a greater reliance on conditional compilation and module replacement. Increasingly, variability is being shifted to runtime due to greater flexibility, new business models, and reduced management effort. In addition to polymorphism and conditional execution, corresponding lifecycle management frameworks such as OSGi are also being used. Regardless of the mechanisms employed, ensure that the points of variation can be easily located and traced back to the underlying variabilities. This greatly simplifies variant/variability management and enables tool-supported analysis and improvements.

Summary

Inadequate implementation of software variants quickly leads to unnecessary complexity and should be avoided whenever possible. This article provides an overview of common variability mechanisms and highlights potential pitfalls and best practices. It is intended as a guide.

Bibliography and list of sources

[1] S. Apel, D. Batory, C. Kästner, G. Saake, „Feature-Oriented Software Product Lines“, Springer, 2013.
[2] F. Bachmann and P. Clements, „Variability in software product lines,“ Software Engineering Institute, Pittsburgh, USA, Tech. Rep. CMU/SEI-2005-TR-012, Sep. 2005.
[3] Y. Dubinsky, J. Rubin, T. Berger, S. Duszynski, M. Becker, K. Czarnecki, „An Exploratory Study of Cloning in Industrial Software Product Lines,“ Proceedings of the 17th European Conference on Software Maintenance and Reengineering, 2013
[4] S. Duszynski, „Analyzing Similarity of Cloned Software Variants using Hierarchical Set Models,“ PhD thesis, Fraunhofer IESE, Kaiserslautern, Germany, 2015.
[5] C. Gacek and M. Anastasopoulos, „Implementing product line variabilities,“ SIGSOFT Softw. Closely. Notes, vol. 26, no. 3, pp. 109-117, May 2001.
[6] T. Patzke, „Sustainable Evolution of Product Line Infrastructure Code“, PhD thesis, Fraunhofer IESE, Kaiserslautern, Germany, 2011.
[7] B. Zhang, M. Becker, T. Patzke, K. Sierszecki, and JE Savolainen, „Variability evolution and erosion in industrial product lines: a case study,“ 17th International Software Product Line Conference (SPLC 2013), pp. 168—177.
[8] B. Zhang, „VITAL – reengineering variability specifications and realizations in software product lines“, dissertation, Fraunhofer IESE, Kaiserslautern, Germany, 2015.

Download the article as a PDF


Implementation – our training & coaching

Do you want to bring yourself up to date with the latest technology?

Then find out more here MircoConsult offers training courses/seminars/workshops and individual coaching on the topic of implementation/embedded and real-time software development.

Training & coaching on the other topics in our portfolio can be found here. here.


Implementation – Expertise

Valuable expertise in the field of implementation/embedded and real-time software development is available. here Available for you to download free of charge.

To the specialist information

You can find expertise on other topics in our portfolio here. here.

MicroConsult Newsletter

With the MicroConsult newsletter, you'll stay on the pulse of the embedded world. Look forward to proven practical knowledge, real professional tips, and current events – directly from our experts for your project success.

Subscribe now!

Published by

weissblau media

weissblau media