Skip to content

guide feature toggle

devonfw-core edited this page Dec 13, 2022 · 10 revisions

Feature-Toggles

The most software developing teams use Feature-Branching to be able to work in parallel and maintain a stable main branch in the VCS. However Feature-Branching might not be the ideal tool in every case because of big merges and isolation between development groups. In many cases, Feature-Toggles can avoid some of these problems, so these should definitely be considered to be used in the collaborative software development.

Implementation with the devonfw

To use Feature-Toggles with the devonfw, use the Framework Togglz because it has all the features generally needed and provides a great documentation.

For a pretty minimal working example, also see this fork.

Preparation

The following example takes place in the oasp-sample-core project, so the necessary dependencies have to be added to the according pom.xml file. Required are the main Togglz project including Spring support, the Togglz console to graphically change the feature state and the Spring security package to handle authentication for the Togglz console.

<!-- Feature-Toggle-Framework togglz -->
<dependency>
  <groupId>org.togglz</groupId>
  <artifactId>togglz-spring-boot-starter</artifactId>
  <version>2.3.0.RC2</version>
</dependency>

<dependency>
  <groupId>org.togglz</groupId>
  <artifactId>togglz-console</artifactId>
  <version>2.3.0.RC2</version>
</dependency>

<dependency>
  <groupId>org.togglz</groupId>
  <artifactId>togglz-spring-security</artifactId>
  <version>2.3.0.RC2</version>
</dependency>

In addition to that, the following lines have to be included in the spring configuration file application.properties

# configuration for the togglz Feature-Toggle-Framework
togglz.enabled=true
togglz.console.secured=false

Small features

For small features, a simple query of the toggle state is often enough to achieve the desired functionality. To illustrate this, a simple example follows, which implements a toggle to limit the page size returned by the staffmanagement. See here for further details.

This is the current implementation to toggle the feature:

// Uncomment next line in order to limit the maximum page size for the staff member search
// criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT);

To realise this more elegantly with Togglz, first an enum is required to configure the feature-toggle.

public enum StaffmanagementFeatures implements Feature {
  @Label("Limit the maximum page size for the staff members")
  LIMIT_STAFF_PAGE_SIZE;

  public boolean isActive() {
    return FeatureContext.getFeatureManager().isActive(this);
  }
}

To familiarize the Spring framework with the enum, add the following entry to the application.properties file.

togglz.feature-enums=io.oasp.gastronomy.restaurant.staffmanagement.featuremanager.StaffmanagementFeatures

After that, the toggle can be used easily by calling the isActive() method of the enum.

if (StaffmanagementFeatures.LIMIT_STAFF_PAGE_SIZE.isActive()) {
  criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT);
}

This way, you can easily switch the feature on or off by using the administration console at http://localhost:8081/devon4j-sample-server/togglz-console. If you are getting redirected to the login page, just sign in with any valid user (eg. admin).

Extensive features

When implementing extensive features, you might want to consider using the strategy design pattern to maintain the overview of your software. The following example is an implementation of a feature which adds a 25% discount to all products managed by the offermanagement.

Therefore there are two strategies needed:
  1. Return the offers with the normal price

  2. Return the offers with a 25% discount

The implementation is pretty straight forward so use this as a reference. Compare this for further details.

@Override
@RolesAllowed(PermissionConstants.FIND_OFFER)
public PaginatedListTo<OfferEto> findOfferEtos(OfferSearchCriteriaTo criteria) {
  criteria.limitMaximumPageSize(MAXIMUM_HIT_LIMIT);
  PaginatedListTo<OfferEntity> offers = getOfferDao().findOffers(criteria);


  if (OffermanagementFeatures.DISCOUNT.isActive()) {
    return getOfferEtosDiscount(offers);
  } else {
    return getOfferEtosNormalPrice(offers);
  }

}


// Strategy 1: Return the OfferEtos with the normal price
private PaginatedListTo<OfferEto> getOfferEtosNormalPrice(PaginatedListTo<OfferEntity> offers) {
  return mapPaginatedEntityList(offers, OfferEto.class);
}

// Strategy 2: Return the OfferEtos with the new, discounted price
private PaginatedListTo<OfferEto> getOfferEtosDiscount(PaginatedListTo<OfferEntity> offers) {
  offers = addDiscountToOffers(offers);
  return mapPaginatedEntityList(offers, OfferEto.class);
}

private PaginatedListTo<OfferEntity> addDiscountToOffers(PaginatedListTo<OfferEntity> offers) {
  for (OfferEntity oe : offers.getResult()) {
    Double oldPrice = oe.getPrice().getValue().doubleValue();

    // calculate the new price and round it to two decimal places
    BigDecimal newPrice = new BigDecimal(oldPrice * 0.75);
    newPrice = newPrice.setScale(2, RoundingMode.HALF_UP);

    oe.setPrice(new Money(newPrice));
  }

  return offers;
}

Guidelines for a successful use of feature-toggles

The use of feature-toggles requires a specified set of guidelines to maintain the overview on the software. The following is a collection of considerations and examples for conventions that are reasonable to use.

Minimize the number of toggles

When using too many toggles at the same time, it is hard to maintain a good overview of the system and things like finding bugs are getting much harder. Additionally, the management of toggles in the configuration interface gets more difficult due to the amount of toggles.

To prevent toggles from piling up during development, a toggle and the associated obsolete source code should be removed after the completion of the corresponding feature. In addition to that, the existing toggles should be revisited periodically to verify that these are still needed and therefore remove legacy toggles.

Consistent naming scheme

A consistent naming scheme is the key to a structured and easily maintainable set of features. This should include the naming of toggles in the source code and the appropriate naming of commit messages in the VCS. The following section contains an example for a useful naming scheme including a small example.

Every Feature-Toggle in the system has to get its own unique name without repeating any names of features, which were removed from the system. The chosen names should be descriptive names to simplify the association between toggles and their purpose. If the feature should be split into multiple sub-features, you might want to name the feature like the parent feature with a describing addition. If for example you want to split the DISCOUNT feature into the logic and the UI part, you might want to name the sub-features DISCOUNT_LOGIC and DISCOUNT_UI.

The entry in the togglz configuration enum should be named identically to the aforementioned feature name. The explicitness of feature names prevents a confusion between toggles due to using multiple enums.

Commit messages are very important for the use of feature-toggles and also should follow a predefined naming scheme. You might want to state the feature name at the beginning of the message, followed by the actual message, describing what the commit changes to the feature. An example commit message could look like the following:

DISCOUNT: Add the feature-toggle to the offermanagement implementation.

Mentioning the feature name in the commit message has the advantage, that you can search your git log for the feature name and get every commit belonging to the feature. An example for this using the tool grep could look like this.

$ git log | grep -C 4 DISCOUNT

commit 034669a48208cb946cc6ba8a258bdab586929dd9
Author: Florian Luediger <florian.luediger@somemail.com>
Date:   Thu Jul 7 13:04:37 2016 +0100

DISCOUNT: Add the feature-toggle to the offermanagement implementation.

To keep track of all the features in your software system, a platform like GitHub offers issues. When creating an issue for every feature, you can retrace, who created the feature and who is assigned to completing its development. When referencing the issue from commits, you also have links to all the relevant commits from the issue view.

Placement of toggle points

To maintain a clean codebase, you definitely want to avoid using the same toggle in different places in the software. There should be one single query of the toggle which should be able to toggle the whole functionality of the feature. If one single toggle point is not enough to switch the whole feature on or off, you might want to think about splitting the feature into multiple ones.

Use of fine-grained features

Bigger features in general should be split into multiple sub-features to maintain the overview on the codebase. These sub-features get their own feature-toggle and get implemented independently.

Clone this wiki locally