Feature Flags в JavaScript: Как включать фичи без риска и деплоя
Представьте: вы написали новую крутую фичу — умный поиск с автодополнением. Код готов, тесты пройдены, но вы боитесь выкатывать это сразу на всех пользователей. Вдруг баг? Вдруг кому-то не понравится? Раньше вы бы сидели до ночи с деплоем, а потом откатывали бы версии. Сегодня есть элегантное решение — feature flags (или feature toggles).
Feature flags — это флаги в коде, которые позволяют включать или выключать функциональность без повторного деплоя. Просто меняете значение в конфиге или на админке — и фича оживает или исчезает. В этой статье мы разберем, как их использовать в JavaScript, покажем реальные примеры кода и дадим чек-лист для внедрения.
Что такое feature flags и зачем они нужны в JS?
Feature flags (они же feature toggles, фиче-флаги) — это простые условные конструкции, которые контролируют, показывать пользователю новую фичу или нет. Они работают на уровне кода: вместо того чтобы удалять старый код, вы оборачиваете новый в проверку флага.
Зачем это нужно в JavaScript-проектах?
- Canary release (канареечный релиз) — выкатываете фичу на 5% пользователей, следите за ошибками, потом расширяете.
- A/B тестирование — показываете разным группам разные версии интерфейса и сравниваете метрики.
- Мгновенное отключение — если фича сломала продакшн, вы просто выключаете флаг без деплоя.
- Разработка без веток (trunk-based development) — можно мержить незавершенный код, скрытый за флагом.
Простейший feature flag в JavaScript: пример
Начнём с самого базового варианта — флаг в конфиге. Допустим, у нас есть функция поиска, и мы хотим включить автодополнение только для тестировщиков.
// config.js
const featureFlags = {
enableAutocomplete: false, // выключено по умолчанию
enableDarkMode: true
};
// search.js
function initSearch() {
if (featureFlags.enableAutocomplete) {
console.log('Автодополнение включено');
loadAutocompleteModule();
} else {
console.log('Автодополнение выключено');
loadBasicSearch();
}
}
Меняете enableAutocomplete на true в конфиге — и фича включена. Просто? Да. Но это только начало. Для продакшена нужно больше — динамические флаги, управление через API, A/B тесты.
Продвинутый подход: библиотеки для feature flags
Писать свои велосипеды для флагов можно, но лучше использовать проверенные библиотеки. Вот топ-3 для JavaScript:
- LaunchDarkly — корпоративный стандарт. Есть SDK для React, Vue, Node.js. Умеет A/B тестирование, сегментацию, процентный rollout.
- Flagsmith — open-source альтернатива. Поддерживает self-hosted и облако. Работает с любым фреймворком.
- Unleash — легковесная библиотека с открытым исходным кодом. Отлично подходит для небольших проектов.
Пример с Unleash:
// Установка: npm install unleash-client
const { initialize } = require('unleash-client');
const unleash = initialize({
url: 'https://your-unleash-instance.com/api',
appName: 'my-js-app',
environment: 'production',
customHeaders: { Authorization: 'API-TOKEN' }
});
// Проверка флага
const isEnabled = unleash.isEnabled('new-checkout-flow');
if (isEnabled) {
renderNewCheckout();
} else {
renderOldCheckout();
}
Такие библиотеки синхронизируются с сервером в реальном времени. Если вы измените флаг на дашборде, клиент подхватит это через несколько секунд (обычно 30-60 секунд, настраивается).
Feature flags в React: Hooks и контекст
В React-приложениях удобно использовать контекст и кастомные хуки. Вот пример архитектуры:
// FeatureFlagContext.js
import React, { createContext, useContext } from 'react';
const FeatureFlagContext = createContext({});
export const FeatureFlagProvider = ({ flags, children }) => (
<FeatureFlagContext.Provider value={flags}>
{children}
</FeatureFlagContext.Provider>
);
export const useFeatureFlag = (flagName) => {
const flags = useContext(FeatureFlagContext);
return flags[flagName] ?? false;
};
// App.js
const flags = {
newDashboard: true,
betaSearch: false
};
function App() {
return (
<FeatureFlagProvider flags={flags}>
<MainContent />
</FeatureFlagProvider>
);
}
// Dashboard.js
function Dashboard() {
const showNewDashboard = useFeatureFlag('newDashboard');
return showNewDashboard ? <NewDashboard /> : <OldDashboard />;
}
Такой подход чистый, тестируемый и легко расширяется. Если нужно A/B тестирование, вы передаёте флаги с сервера, загружая их при старте приложения.
A/B тестирование с feature flags: реальный пример
Допустим, вы хотите протестировать два варианта кнопки «Купить». С флагами это делается так:
// Флаг ab_test_button: 'A' или 'B'
const buttonVariant = getFlag('ab_test_button') || 'A';
function renderBuyButton() {
if (buttonVariant === 'B') {
return <button className="buy-btn-new">Купить сейчас</button>;
}
return <button className="buy-btn-old">Купить</button>;
}
Затем вы отслеживаете конверсию через аналитику (Google Analytics, Mixpanel). Через неделю смотрите, какой вариант показал лучший CTR, и оставляете его. Без лишнего кода, без переписывания логики.
Когда feature flags — это плохая идея?
Да, у них есть тёмная сторона. Вот главные риски:
- Захламление кода — если не удалять старые флаги, код превращается в спагетти из if-else. Правило: фича выкачена на 100% — удаляй флаг.
- Сложность тестирования — нужно тестировать все комбинации флагов. Чем больше флагов, тем больше комбинаций.
- Технический долг — забытые флаги могут влиять на производительность и безопасность.
Как бороться? Внедрите процесс TTL (time-to-live) для флагов. Установите дедлайн — через 2 недели после полного rollout флаг должен быть удалён. Используйте линтеры, которые подсвечивают старые флаги.
Best practices для feature flags в JavaScript
Собрали главные советы от практиков:
- Храните флаги централизованно — один конфиг или одна библиоте