Feature flags and A/B testing are vital techniques for modern software development. They empower developers to roll out new features gradually, experiment with user experiences, and make data-driven decisions. In this chapter, we’ll explore how to implement feature flags and A/B testing in an Express.js application, providing both theoretical concepts and hands-on examples.
Feature flags (also called feature toggles) allow developers to enable or disable specific features in an application without deploying new code. This is crucial for:
A/B testing is a method to compare two or more variations of a feature by exposing different segments of users to each variation and analyzing the results to determine the best-performing version.
const express = require('express');
const app = express();
// Define feature flags
const featureFlags = {
newFeature: true,
};
app.get('/', (req, res) => {
if (featureFlags.newFeature) {
res.send('New Feature is Enabled!');
} else {
res.send('Welcome to the old version!');
}
});
app.listen(3000, () => console.log('Server is running on port 3000'));
Explanation:
featureFlags
object acts as a centralized store for toggling features.
const users = {
1: { name: 'Alice', isBetaTester: true },
2: { name: 'Bob', isBetaTester: false },
};
app.get('/dashboard', (req, res) => {
const userId = req.query.userId;
const user = users[userId];
if (user?.isBetaTester) {
res.send('Welcome to the beta dashboard!');
} else {
res.send('Welcome to the standard dashboard.');
}
});
Client-side feature flags can be delivered as part of the app’s configuration or fetched from a feature flag service. These are useful for UI-related changes.
LaunchDarkly
npm install launchdarkly-node-server-sdk
const LDClient = require('launchdarkly-node-server-sdk');
const client = LDClient.init('YOUR_SDK_KEY');
client.once('ready', () => {
app.get('/', async (req, res) => {
const user = { key: 'user123' };
const showFeature = await client.variation('new-feature-flag', user, false);
if (showFeature) {
res.send('New Feature Enabled!');
} else {
res.send('Default Experience');
}
});
});
Explanation:
LaunchDarkly
dynamically evaluates feature flags based on user attributes.variation
method retrieves the flag’s value for a specific user.
app.get('/experiment', (req, res) => {
const variant = Math.random() < 0.5 ? 'A' : 'B';
if (variant === 'A') {
res.send('Variant A: Original Feature');
} else {
res.send('Variant B: New Feature');
}
});
Explanation:
app.get('/experiment', (req, res) => {
let variant = req.cookies.variant;
if (!variant) {
variant = Math.random() < 0.5 ? 'A' : 'B';
res.cookie('variant', variant);
}
res.send(`You are in Variant ${variant}`);
});
Explanation:
Platforms like Optimizely or Google Optimize can handle traffic splitting and data analysis.
Integrate analytics tools (e.g., Google Analytics) to collect data on user behavior:
app.post('/track-event', (req, res) => {
const event = req.body;
console.log('Event tracked:', event);
res.status(200).send({ success: true });
});
LaunchDarkly
for managing flags at scale.Feature flags and A/B testing are transformative techniques for agile development, allowing for safe experimentation and data-driven optimization. Using Express.js, you can build robust solutions that leverage these techniques to enhance user experiences and minimize risks during feature rollouts. This chapter has covered everything from basic implementations to advanced integrations, equipping you to build feature-rich, scalable applications.