Delen via


Building VSTS Extensions with feature flags

We started talking about features flags (or features toggles) in our Software Development with Feature Toggles MSDN Magazine article. Today, with the increasing deployments of our extensions, and with a view to improving the user experience and our DevOps processes, we embarked on a research project to investigate the feasibility of using LaunchDarkly to eliminate risk and deliver value.

The purpose of this blog series is to share our learnings and engage in a discussion with you.

What are the features flags?

A feature toggle, (also feature switch, feature flag, feature flipper, conditional feature, etc.) is a technique in software development that attempts to provide an alternative to maintaining multiple source-code branches (known as feature branches), such that the feature can be tested, even before it is completed and ready for release. ” - Wikipedia

We wanted any solution we chose for developing Visual Studio Team Services (VSTS) extensions to allow us to:

  • Enable (expose) | disable (hide) new features
  • Allow user to opt in | out of features
  • Enable | disable internal features

Enable (expose) | disable (hide) new features

This is the most common scenario. It allows us to deploy new features and selectively expose them. If a new feature is faulty or does not receive positive feedback, we’re able to hide the features without having to redeploy.

scenario1-sideByside

The scenario allows us to experiment with new features in production and gather feedback. This This scenario is a global feature ON | OFF switch, managed from a central point.

Allow user to opt in | out of features

Allow users to choose which features they want to use. It’s commonly used to expose preview features to users and allowing them to switch between a classic and preview experience.

A good example of this scenario is the Preview features option implemented by Microsoft in VSTS.

clip_image004

Here’s an example implementation of the scenario in our extension prototype:

Scenario2

This scenario does not require maintenance by an administrator, but is more complex and requires more development time for the user interface, APIs, workflow, and security.

Enable | disable internal features

Many times, we collect data that would be invaluable to have when investigating issues but would otherwise be undesirable to display always. For example, logging verbose information to a console window or displaying the Application Insights telemetry could all be useful. Flags would allow us to choose when to enable that behavior or not - without redeploying code.

Furthermore, feature flags allow us to control the configuration in each environment independently. For example, if telemetry in the canary and early adopter deployment rings were overloading/blurring our metrics, we could decide to disable the behavior without redeploying.

Scenario3

It’s invaluable to have the ability to enable detailed Application Insights and console logging in production when investigating an issue. Similarly, we recommend to separate telemetry on canary, early adopter, and production environments, or use feature flags to control the metrics in production. We’re looking at disabling telemetry in canary and early adopter deployment rings, so as not to overload or blur the production metrics.

Why did we choose the LaunchDarkly solution?

We considered a few feature flag solutions. (Read How to implement feature flags and A|B testing for details.)

We decided to evaluate LaunchDarkly for these reasons:

  • Sass solution is always the preferred solution for us since it will be having a less administrative and ownership overhead.
  • Well documented SDK that supports a multitude of languages, for example .NET, JavaScript, and Node.
  • Integrated with VSTS and TFS with an extension  on the marketplace, seamlessly integrating into our existing CI/CD pipelines
  • When we approached the LaunchDarkly's team, they were open to collaborating with us on our research project.
  • These and other noteworthy service features:
    • Streaming API to decrease latency
    • Multiple failure modes

How did we use the LaunchDarkly solution?

We created self-explanatory feature flags within the test environment of the prototype project.

clip_image010

● ❶ internal feature

● ❷ new feature

● ❸ Optional feature- features that end users can opt-in/out of

LaunchDarkly has a concept of a user key, which is a unique key for every user passed into the platform. This ensures that a single user will be given a consistent result when flags are evaluated. To use the user key, you can add arbitrary attributes that can be used for targeting. For instance, you might pass in a user email to use as a unique key. For example,  for the feature flag “enable-telemetry”, we configured the default rule and target users such that anyone on the VSTS team would receive the “true” flag except for certain people who needed to test the old functionality.

clip_image012

clip_image014

clip_image016

Flags can also be applied to front-end attributes, through the LaunchDarkly JS SDK.

How did we implement LaunchDarkly in our VSTS extension?

Remember that VSTS extensions are client-side only applications, based on JavaScript, HTML, and CSS. Here are a few useful references links:

Install and import the SDK

The JavaScript SDK is imported inside the extension by the npm package “ldclient-js” (link : https://www.npmjs.com/package/ldclient-js), which we referenced in the package.json package file.

The packages files will be minified with others extension scripts by webpack. Read step 2 of post How to create or upgrade your team services extension in 4 steps for details.

LaunchDarkly Services class

We created a new TypeScript class that import the JavaScript SDK and centralize all LaunchDarkly helper methods and call methods to SDK. (Refer to our sample for details.)

The class contain some methods to Initialize, Get flags and Update Flags.

The Init Method call the Initialize method from the SDK with the environment key and the user object

image

All environments parameters such as the environment Id are tokenized. These tokens will be replaced in our CI/CD pipelines using the Replace Tokens build task.

Integration of LaunchDarkly services methods inside extension

The integration and usage of the LaunchDarkly services is done in 2 principals steps:

First step is the Initialization and the get of the flags value for the current user.

image

  • ❶First step for call methods is, in our extension scripts we import the LaunchDarkly services class.
  • Then just before to register the extension:
    • ❷ Construct the user object with key property which have the format: vstsaccount:email
    • ❸ Call the init from the services class for initialize.
      • When the initialize is returned we can call the “ready” method from the SDK ❹.
      • To complete this first step, we’re getting all flags for the current user ❺.

The second step is to “manipulate” the features with returned flags. For example, for the display log feature we create a method for manage the console.log.

image

We’re getting the flag of the desired featured (with the LaunchDarkly feature key). Then, based on the flag value, the extension displays log data in console developer of the browser.

This implementation pattern is the same for all other features.

What’s Next?

We’re working with the VSTS and LaunchDarkly engineering teams to find a way to exchange a more secure user key. We’re also working with the Ranger DevLabs extension teams to validate our research and implement feature flags in all our extensions. But, that’s a story for a future post in this series. Watch this space!

So, what are your ideas, thoughts and feedback?

References

https://blogs.msdn.microsoft.com/visualstudioalmrangers/2017/04/04/how-to-implement-feature-flags-and-ab-testing/

https://dev.to/samueleresca/continuos-delivery-using-feature-toggle

https://featureflags.io/

https://launchdarkly.com/