Tagging and Feature Flags
Tags: javascript, tagging, adobelaunch, featureflags
Published: 2022-08-11 15:22:16

> This post is part of a series about auto-tagging

Feature Flags or Feature Toggle is a common practice used by developers. It allows to deploy specific functionalities in an incremental manner and only enable them when needed.

In the tagging world feature flags is a little-known concept. Most of the time a standard tagging release will consist of creating the tag, testing it with the tag management system dev endpoint then publishing it to production. This means that sometimes the release timing is crucial as it needs literally to be done at the same time as the new platform feature has been released to production so it does not impact user experience.

## What are feature flags? 

Feature flags are a development concept that allows to wrap a functionality inside an `if` condition that checks a specific variable value. This variable is usually a Boolean, so the possible values are either `true` for enable my feature or  `false` for disable my feature. This allows the development team to deploy part or a full feature in an incremental manner. By doing so you can then enable/disable a feature during runtime without a code release.

```javascript
if (featureFlags.feature1 === true) {
    executeCode();
}
```

By doing so you can allow the development team to deploy a feature to production and complete the QA process before making the feature available to your users. 

If the feature relies on multiple teams to complete their work, this allows your tagging and development team to work in parallel without having to wait on each other.

## Are Tagging and Feature Flags incompatible?

One might think that tagging is as simple as deploying a script tag on a platform, however it does require some planning and orchestration to make sure the tags fire in the correct order, at the right time and with the right configuration. Tags configuration can become really complex based on the business needs and the layout of the website.

If you look at how tag management systems work you will find that feature flags are being used in tags configuration without the tagging team realising it.

TMSs, like Adobe Launch, are usually structured around these 3 main sections:
* Triggers: these are the events that needs to be fulfilled in order for the tags to be eligible for execution. Most TMS provides events like DOM events, custom events or directly call the tag.
* Conditions: even if the event is fulfilled it does not necessary mean that we want the tag to be executed. In most instances we will provide a set of conditions that need to be met to execute the tag
* Actions: this will be the list of actions or scripts that will be executed when the tag is launched. 

In a sense, the conditions section can be considered as the feature flag section. But unlike traditional feature flags they are only usable by the TMS during its runtime. These conditions are most of the time scoped to the TMS object and cannot be evaluated by the platform scripts.

Now that we have understood that the feature flags concept is being used for tag configuration, the next step will be to figure out how to expose the feature flag functionality to be used outside of the TMS runtime. Our goal is for the feature flag to be set and ingested during runtime by our TMS, our platform scripts and any third party vendor scripts that we deploy on the platform via the TMS.

To achieve this, we will need to have one common location where these feature flags can be set and accessed. Luckily for us we have defined a [generic data layer](https://dev.to/alcazes/generic-data-layer-1i90) which is the ideal candidate to host our feature flags. 

In the next section I will describe how we can extend our generic data layer to support the `featureFlags` property.

## Extend the generic data layer to support feature flags

Luckily for us the generic data layer is a nested type data layer with a root of an object that can be easily extended.

This is an example of how our feature flags will be defined:
```javascript
var digitalData = {
    "featureFlags": {
        "featureName1": true,
        "featureName2": false,
        "overWrite": {
            "featureName1": false,
            "featureName3": true
        }
    }
}
```

We can clearly see that we want to extend the root object to contain a new `featureFlags` property. This property will be an object.

To support future use cases, we will have 2 feature flag levels:
* The first level will be used by the development team to set default behaviours. This will be optional as by default if a feature is not defined on the first or second level it will be considered to be disabled. An example of use case would be when a tagging release introduce a new product that should only be executed at runtime when the platform migrates to a new design. As the release of the platform will be outside of the business hours, the feature flag will need to be enabled by the development team. The tagging team would have released their build with the configuration to support the new product, days or weeks or even months before the live date.
* The second level in the `overWrite` object will be used primarily by the tagging team. This will allow the business to be in charge to enable or disable specific features as required in the least amount of time. This level will prevail over the first level. For example when the business wants to deploy a chat functionality on your platform, they might want to first test that the chat functionality has a positive impact on the conversion rate. Before fully committing a lot of resources for the chat functionality we want to confirm that by having it on our checkout funnel it will increase the conversion rate. This use case is best answered by an A/B test. In this use case we will deploy the core functionality of the chat via a tag from our TMS. We will add a condition that will depend on our feature flag for the tag to be executed during runtime. Now in the A/B test instead of having the chat code we just need to have 2 experiences, one for chat enabled which will set `digitalData.overWrite.chatEnabled` to true and one for chat disabled which will set `digitalData.overWrite.chatEnabled` to false. As you can see the A/B test is now simpler to compose.

Now as our generic data layer is defined using the JSON schema definition, we will extend our definition by adding the `featureFlags` property definition inside the top level `properties` property:
```json
{
    "properties": {
        "featureFlags": {
            "type": "object",
            "properties": {
                "overWrite": {
                    "type": "object",
                    "additionalProperties": {
                        "type": "boolean"
                    }
                }
            },
            "additionalProperties": {
                "type": "boolean"
            }
        }
    }
}
```

> Notice that the only item you will need to add to your generic data layer definition will be the `featureFlags` object inside your top level "properties" property.

## Feature flags benefits

Now you might be wondering why we will spend time and effort to create a feature flag functionality that is already covered by the conditions section of our TMS.

One of the main limitations of the conditions section of your TMS is that the conditions can only be evaluated by your TMS. This means that your platform has no indication if a specific feature is enabled or not. 
Some personalization products deployed on your platform will sometime require the development team to deploy custom components to create an optimal user experience. In order for the platform to know at runtime which component to display in the journey, they will need a feature flag. However, as the conditions section of your TMS is not globally accessible and we do not want to create technical debt by adding code from the TMS object into our platform code then the feature flag functionality is the best option.

Here are some other benefits when using globally scoped feature flags with your tagging implementation:
* QA process: while it is possible to use development and staging libraries of your TMS at runtime by using a browser extension, this is not necessary the best option for your QA engineers. Some of them might not know how your TMS work and how to enable this or simply if you are in a financial company, they might not get the rights to install any browser extension. By using feature flags, the QA engineer can switch on and off the functionality and validate that it works as expected. This will also be much easier to create automated tests as the only requirement would be to set the data layer feature flag to true of false for the test. This can be achieved using local overwrite using localStorage functionality or query parameters. 
* Conducting experiments: in most TMSs there is no functionalities or limited functionalities to run a tag for a specific subset of your audience. At that point you will need to make a call to either deploy your functionality for all users which might result in unnecessary cost as it will ultimately not increase the conversion rate. By using a feature flag, you can release your tag to production and then control who can see/use it by creating A/B tests using your A/B test product like Adobe Target. The test will have 2 experiences, one which will enable the feature flag and one which will disable the feature flag.
* Migration: in some instances your platform will have a staggered migration to a new system or new capabilities that will impact your tagging implementation. You can either do your best to keep up with your development team releases and understand which part of the platform will be impacted in a specific release or you can create 2 tags one for each version and ask your developers to switch the legacy feature tag off and the new feature tag on when they deploy the new content for a specific section of their platform. This way no downtime will be experienced by your users.
* Minimize the risk to switch off a functionality completely: it is unlikely that your tagging team is only composed of yourself. It might be that multiple persons work at the same time and on different sections of the platform to deploy the same functionality. It can be that the tag conditions may vary between one section to another therefore it will be quite difficult in some instances to completely switch off a specific functionality. By using a feature flag, you can centralize on how you wrap/conditions the tags for a specific product in your tagging implementation.
* Continuous deployment: in some instances, you will need to release several products together in your tagging implementation. It might take months for all the products to be setup before your get the configurations for each product and it will therefore delay your implementation work. It can also result in a massive build by the time you configure all of your products. One approach would be to configure each tag as the configuration comes available and wrap it inside a feature flag. You can then deploy this configuration to production. Once all the products have been deployed to production you can then enable the feature flag. Prior to pushing it live you can use the feature flag to test your implementation.

Using a feature flag approach will allow your business to run campaigns in an agile way where you can stop/start any functionalities without waiting on your development team to do a release. Your tagging build can be pushed to production before the platform release date.

It also provides a new type of collaboration between your development and tagging team where specific components can be created for specific use case. These components can then be displayed based on values of specific feature flags at runtime.

## Real life example

A good example would be the surveys displayed on your website. 
Traditionally you will use your TMS to inject your survey script code when the customer reaches a specific milestone like a page in your application. This will result in the survey being displayed on the page before your customer can see the content of the page which results in a bad user experience.

An easy fix for this issue would be to provide a button when the customer completes/close the application which will give an option to take the survey. To do so your development team will need to display this new component whenever and wherever the business wants the survey.

As the content of the survey can change at any time due to regulations, we will need to rely on something other than the development release cycle to switch on/off the survey.

The best option would be for:
* your development team to create a component that will push an event to our data layer indicating that the user chose to see the survey
* tagging team will configure a tag to watch for this specific event and then trigger the survey code
* the developers will evaluate as the application loads if the feature flag to enable the survey is present and use  the survey component if the feature flag is enabled. 
* the tagging team will be the one that will switch the feature flag on/off as the business needs it as they are not bound by the development release cycle.

## Feature flags and testing

In order for us to be able to test specific product/feature behaviours, we need to be able to switch a feature flag on/off without having to do a release. This means that we want to overwrite the feature flag value after the tagging library is loaded and application library is loaded.

To overwrite the values set we can use 2 routes:
* use localStorage to store our new configuration. When the application loads, the TMS will check the local storage and merge its configuration to the `featureFlags` object.
* use URL query parameters to provide specific configuration.  You will need to decide is query parameters will prevail over local storage overwrite during testing.

By doing so this will allow us to test both the scenarios with the feature on and off without having to a tagging or development release each time. This is particularly useful for your QA engineers to validate their tests.

## Conclusion

We have seen that in its core tagging revolves around TMS based feature flags (conditions). While it is a viable approach and is mainly used, there is additional benefits to adopt a more traditional approach around globally scoped featured flags. These feature flags allow additional A/B test capabilities, tailored custom implementation to improve customer experience and a better QA process.