Фичи как конфигурация: когда хранить правила в БД для лимитов, текстов и экспериментов, какие риски правок в прод и какие проверки нужны.

Подход «фичи как конфигурация» означает, что часть продуктовых правил живет не в коде, а в настраиваемых данных: в базе, конфиг-сервисе или таблицах админки. Приложение читает эти значения при старте или на лету и ведет себя по ним. Релизы нужны реже: вы меняете данные, а не пересобираете приложение.
Правила, зашитые в код, часто замедляют изменения по простой причине: даже маленькая правка запускает цепочку шагов. Нужно завести задачу, внести изменения, пройти ревью, прогнать тесты, выкатить релиз и дождаться раскатки. Для лимита «10 в день» или текста кнопки это кажется слишком дорогим процессом.
Но есть и обратная сторона. Когда правки делают прямо в проде, скорость растет, а риск тоже. Ошибка в значении, случайное отключение проверки или неверный диапазон могут сразу ударить по пользователям и деньгам. Поэтому цель не «менять без контроля», а «менять быстрее и безопасно».
Чаще всего из релизов выносят лимиты и пороги (сколько действий доступно на бесплатном тарифе), тексты и формулировки (заголовки, подсказки, названия тарифов), фичефлаги и эксперименты (кому показать новую форму или цену), а также параметры, которые часто подкручивают (таймауты, коэффициенты, минимальные суммы).
Простой пример: команда хочет проверить, повысит ли конверсию текст «Попробовать бесплатно» вместо «Начать». Если текст в коде, это минимум один релиз. Если текст в конфигурации, вы меняете значение, включаете его для 10% пользователей и откатываете за минуту, если метрики просели.
Ключевая идея проста: код остается «движком», а изменяемые правила становятся «настройками», которые можно проверять, версионировать и откатывать.
Хранить правила в базе данных удобно, когда это бизнес-решение, а не часть защиты системы. Быстрый тест такой: если ошибку можно быстро откатить и она не дает пользователю лишних прав, правило обычно подходит для конфигурации.
Подход особенно хорошо работает, когда правила часто меняются и зависят от сегмента: тарифа, региона, типа клиента, канала продаж. Тогда проще обновить лимит, текст или условие эксперимента без релиза и без срочных правок в коде.
Признаки, что правило пора выносить в БД:
Но есть случаи, когда правило лучше оставить в коде. Если это безопасность (доступы, роли, права на данные, защита платежей), ошибка в конфиге может стать дырой. То же касается сложных вычислений, где легко допустить несогласованность: расчеты, завязанные на несколько источников данных, или условия, которые трудно покрыть тестами.
Практический пример: «максимум 20 проектов на тарифе Pro» удобно держать в БД и менять под акции или разные планы. А вот «можно ли пользователю экспортировать исходники чужого проекта» лучше жестко закреплять в коде, потому что это про доступ.
Чаще всего все начинается с единого реестра настроек: одной таблицы, где каждое правило хранится как запись. Это позволяет менять лимиты, тексты или параметры эксперимента без релиза и при этом держать порядок.
В минимальной модели у записи обычно есть:
upload.max_mb)50)Чтобы не было сюрпризов, конфигурацию почти всегда делают версионной. Самый простой вариант: хранить текущую опубликованную версию и отдельный черновик. Изменения копятся в черновике, проходят проверку, и только потом публикуются как новая версия.
Следующий шаг - сегментация. Одно и то же правило может отличаться по тарифу (free, pro, business), роли (пользователь, модератор), региону или группе пользователей (например, группа для A/B теста). Чтобы не плодить хаос, вводят приоритеты и наследование: есть глобальное значение по умолчанию, а затем точечные переопределения.
Обычно правило выбирается по простой логике:
Для экспериментов и временных акций полезно добавить срок действия. У записи может быть «включить с» и «выключить до», либо окно времени по расписанию. Тогда A/B эксперимент сам завершится, а временный лимит не останется навсегда из-за человеческой ошибки.
Начните не с таблиц, а с описания правила на человеческом языке: что именно меняется, для кого, какой эффект ожидается. Добавьте 2-3 примера входных данных и ожидаемого результата. Так быстрее станет понятно, подходит ли подход «фичи как конфигурация», или правило слишком сложное и лучше оставить его в коде.
Дальше разделите правило на параметры и логику. Параметры уезжают в конфиг (число, дата, список тарифов), логика остается в коде (как считать, какие проверки делать, что считать ошибкой). Если переносить в БД еще и логику, легко получить «скриптовую» систему, которую никто не понимает.
На старте помогает короткая структура:
max_projects_per_user)После этого подключите чтение конфига в приложение и обязательно заложите значения по умолчанию. Если БД недоступна, запись битая или не найдена, система должна продолжать работать предсказуемо. Хорошая практика: логировать срабатывание дефолта, чтобы вы не искали «пропавший лимит» наугад.
Первый запуск делайте безопасным: миграция создает таблицу и добавляет запись, но код еще может использовать старое значение. Затем включите чтение из БД для небольшой доли пользователей или внутренней группы.
И отдельно закрепите процесс публикации. Не давайте править прод напрямую: нужен черновик, автоматическая проверка (типы, диапазоны, обязательные поля) и только потом выпуск. Даже простое правило стоит сопровождать историей изменений и возможностью быстрого отката.
Лимиты почти всегда проще поддерживать как конфигурацию. Меняются тарифы, появляются новые метрики, спорные ситуации с пользователями нужно разбирать быстро. В модели «фичи как конфигурация» лимиты становятся данными: вы меняете правило, а не код.
На практике удобно хранить лимиты по тарифам: сколько проектов можно создать, сколько запросов в сутки доступно, сколько мест в команде, какой объем хранилища или число деплоев разрешены.
Важный момент - разделить мягкие и жесткие лимиты. Мягкий лимит не ломает сценарий: он показывает предупреждение и предлагает следующий шаг. Жесткий лимит блокирует действие (например, создание проекта), но должен быть понятным и предсказуемым.
Пороговые значения лучше задавать отдельно, чтобы интерфейс мог предупредить заранее. Например, баннер можно показывать при 80% использования хранилища, а подсказку рядом с кнопкой - при 95%. Тогда ограничение не выглядит «внезапной стеной».
Полезно сразу предусмотреть исключения: временное повышение лимита на неделю, индивидуальные условия для крупного клиента, бонус за рефералов или контент. Такие исключения лучше хранить с датой окончания и причиной, чтобы они не превращались в вечные «костыли».
Чтобы потом не спорить «система сама списала», логируйте срабатывания лимитов. Достаточно фиксировать: какое правило сработало (тариф, метрика, значение), кто и когда уперся в лимит (пользователь, проект, действие), было ли это предупреждение или блокировка, применилось ли исключение, и что показали пользователю (код сообщения или тип предупреждения).
Эти записи помогают поддержке и продукту: видно, где люди застревают и какие лимиты стоит пересмотреть без релиза.
Тексты чаще всего правят не разработчики, а поддержка, продакт или юристы. Это подсказки в формах, тексты ошибок, уведомления о статусе оплаты, предупреждения про лимиты и короткие объяснения «почему не получилось». Если такие фразы зашиты в код, любая мелочь превращается в релиз. Поэтому «фичи как конфигурация» особенно хорошо подходят для текстов: меняется смысл, логика остается прежней.
Обычно удобнее хранить текст как запись в БД: ключ (например, billing.limit_reached), язык (ru, en), вариант (для A/B или разных тарифов) и само содержимое. Так проще вести локализацию: один и тот же ключ имеет несколько языков, а вариант позволяет аккуратно менять формулировку без копипаста по интерфейсу.
Чтобы правка не ломала экран, добавьте проверки перед публикацией: ограничения длины (например, заголовок до 60 символов), запрет недопустимых символов или переносов, проверку формата (плейсхолдеры вроде {count} должны остаться), предпросмотр в типовых местах (веб и мобильный), автопроверку на пустые строки и дубликаты ключей.
Важно продумать согласование. Рабочая схема: один человек редактирует черновик, другой подтверждает, и только потом текст становится активным.
План отката обязателен. Храните историю версий и давайте возможность быстро вернуть предыдущую. Реалистичный сценарий: утром поменяли текст ошибки на «более понятный», днем увидели всплеск обращений (люди поняли иначе), и за минуту вернули прошлую формулировку, не трогая код и не останавливая сервис.
Фичефлаги и A/B тесты удобно хранить как правила в базе данных, потому что ими часто нужно управлять быстро и аккуратно, без релиза. Это один из самых понятных примеров подхода «фичи как конфигурация»: поведение меняется, а код остается прежним.
Обычно у флага есть ключ (например, new_checkout), статус и аудит (кто и когда поменял). Дальше добавляются условия, кому показывать новую версию: всем пользователям, выбранной группе (например, только бизнес-тариф), по проценту (например, 10% трафика), по признаку (регион, платформа, версия приложения) или по списку (конкретные аккаунты для проверки).
Для A/B важно не просто раздать процент, а закрепить группу. Пользователь, попавший в тест, должен оставаться в нем, иначе метрики будут шумными. Обычно это делают через сохранение варианта в профиле, куке или отдельной таблице назначений.
Метрики успеха лучше определить до старта: что считаем (конверсия, удержание, выручка, время до действия) и где смотрим. Даже если расчет идет в аналитике, в конфигурации полезно хранить цель и владельца эксперимента, чтобы было ясно, зачем он запущен.
Самая частая ошибка - править правила так, что сравнение «контроль vs тест» теряет смысл. Ограничьте изменения:
Остановка эксперимента тоже должна быть правилом: дата окончания, условия досрочного выключения (например, рост ошибок) и кнопка принудительного выключения.
Когда правила живут в базе данных, правка в админке может мгновенно изменить поведение продукта. Это и есть сила подхода «фичи как конфигурация», но без защит он быстро превращается в источник инцидентов: случайный ноль в лимите, неверный сегмент в эксперименте, и пользователи уже видят поломку.
Разделите просмотр, редактирование и публикацию. Схема похожа на работу с документом: один человек готовит, другой утверждает.
Двухшаговая публикация (черновик -> подтверждение) снижает риск. В черновике полезно показывать дифф: что меняется и где это используется.
Дальше нужны две линии защиты. Первая - валидация при сохранении: типы, обязательные поля, диапазоны (лимит не может быть отрицательным, процент в A/B - от 0 до 100), форматы текстов. Вторая - автопроверки при публикации: небольшой набор тестовых кейсов, который прогоняет конфиг в симуляции (несколько заранее заданных пользователей и тарифов) и ловит очевидные конфликты.
Хороший минимальный набор практик: дифф перед публикацией и обязательное поле «почему меняем», автопроверки (например, сегменты не пересекаются, суммы долей в эксперименте сходятся), блокировка публикации при ошибках, версионирование и кнопка отката на прошлую версию.
Практичный пример: контент-менеджер меняет текст кнопки, продукт поднимает квоту с 100 до 200, аналитик запускает эксперимент 50/50. Без журнала изменений непонятно, что именно сломало конверсию. С журналом видно, кто и когда опубликовал, а откат возвращает состояние за минуту.
Первые проблемы обычно не в самой идее, а в реализации. Ошибки выглядят так: «вроде поменяли одно число, а поехало все».
Самая частая ловушка - свалить все настройки в один большой JSON без схемы и типов. Сегодня там число, завтра строка, послезавтра вложенный объект, и код начинает угадывать, что ему пришло. Даже простую конфигурацию лучше хранить так, чтобы были понятны типы, обязательность полей и допустимые диапазоны.
Еще один источник хаоса - менять сразу несколько параметров одним заходом. Потом никто не может сказать, что именно изменило поведение. Разделяйте правки и делайте их маленькими, чтобы откат был очевидным.
Чаще всего ломает прод вот что:
Простой пример: маркетинг меняет текст кнопки и одновременно увеличивает квоту. Конверсия упала, поддержка видит ошибки, но непонятно, из-за текста или из-за лимита. Если правки раздельные, с проверками и быстрым откатом, такие ситуации закрываются за минуты.
Доступ к правкам нельзя выдавать только потому, что «так быстрее». Сначала убедитесь, что система переживет ошибку, спешку и человеческий фактор.
Перед тем как открывать админку или выдавать права на изменение правил в БД, проверьте базовые вещи:
После публикации договоритесь о простом правиле: заметные изменения проверяются по метрикам. Минимум - алерты на рост ошибок и просадку конверсии. И полезно видеть «до/после» рядом с правкой.
Пример из практики: менеджер увеличил лимит в 10 раз для теста и забыл вернуть. Если у вас есть предпросмотр, лимиты по умолчанию и быстрый откат, это будет короткий инцидент, а не счет за инфраструктуру и неделя разборов.
У вас продукт с тарифами Free, Pro, Business, Enterprise, а правила живут как конфигурация. День начинается с запроса от продаж и поддержки: повысить ценность Pro, поправить формулировку в интерфейсе и аккуратно проверить новую идею, не затрагивая всех пользователей.
К 11:00 вы поднимаете лимит: в Pro увеличиваете количество доступных снапшотов и откатов. В конфиге это правило по тарифу (tariff=pro) и новое значение, без изменения логики. Чтобы не задеть всех сразу, вы включаете применение только для новых проектов, созданных после времени публикации.
К 14:00 правите текст: в разделе экспорта исходного кода меняете подпись кнопки, чтобы меньше путали «экспорт» и «деплой». Тексты лежат в БД с версией и языком, поэтому правка не требует релиза и может быть включена для части пользователей.
К 17:00 запускаете эксперимент: для 10% пользователей Free показываете упрощенную подсказку про planning mode, чтобы проверить, растет ли конверсия в создание приложения.
Перед публикацией таких правок прогоните короткий набор:
После публикации смотрите не только на метрики, но и на «живые» сигналы: обращения в поддержку по тарифам и доступности функций, ошибки в логах (например, лимит стал 0 из-за опечатки), просадки конверсии в ключевых шагах.
Если пошли жалобы или метрики просели, действуйте как с кодом: откатите конфиг на прошлую версию, временно выключите эксперимент флагом и зафиксируйте причину в журнале изменений.
Начните с инвентаризации: какие правила меняются чаще всего и создают больше всего мелких релизов. Обычно это лимиты, тексты в интерфейсе и простые фичефлаги. Внедряйте подход постепенно: он дает скорость, но не превращает продукт в набор непредсказуемых переключателей.
Сведите стартовый набор конфигов к минимуму. Не пытайтесь вынести в БД все сразу: сложные бизнес-цепочки лучше оставить в коде, а в конфиги отдать только то, что легко проверить и легко откатить.
Рабочий порядок действий:
И параллельно зафиксируйте короткий процесс публикации: черновик -> проверка -> публикация -> быстрый откат.
Если вы делаете продукт на TakProsto (takprosto.ai), эту же дисциплину стоит заложить с самого начала: отделяйте конфиг (лимиты, тексты, фичефлаги) от критичных проверок, а для изменений используйте планирование, снимки и откат, чтобы быстро пробовать новое и так же быстро возвращаться к стабильной версии.
Это значит, что изменяемые правила продукта хранятся как данные (в БД или конфиг-сервисе), а приложение читает их и ведет себя по ним. Тогда для правки лимита, текста или включения фичи чаще не нужен релиз, потому что вы меняете значения, а не код.
Выносите то, что часто меняется и где ошибку можно быстро откатить без дыр в доступах: лимиты, пороги, тексты, фичефлаги, параметры таймаутов. Если правило про права, деньги и безопасность, по умолчанию оставляйте его в коде и усиливайте тестами.
Удобно, когда правила различаются по тарифам, ролям, регионам или группам для эксперимента. Тогда у одного ключа есть базовое значение по умолчанию и более точные переопределения для сегментов, а приложение выбирает самое подходящее.
Минимум — таблица с ключом, типом, значением и описанием, плюс статус «черновик/опубликовано». Это дисциплинирует изменения и снижает шанс, что параметр внезапно превратится из числа в строку и сломает поведение.
Сделайте версионирование: черновик редактируется отдельно, а в прод попадает только опубликованная версия. Это позволяет видеть дифф, хранить историю и откатываться на прошлое состояние за минуты, не вспоминая «что мы меняли вчера».
Задайте безопасные значения по умолчанию в коде и используйте их при ошибке чтения, битом значении или отсутствии записи. Лучше предсказуемо ограничить функциональность, чем случайно открыть бесконечный лимит или уронить сервис из‑за пустого поля.
Кэшируйте конфиг в памяти и обновляйте по расписанию или по событию, иначе каждый запрос начнет ходить в БД и нагрузка вырастет незаметно. Одновременно логируйте, когда применился дефолт или конфиг изменился, чтобы диагностика была быстрой.
Держите текст как конфиг с ключом и языком, а перед публикацией проверяйте формат и плейсхолдеры, чтобы не сломать экран и не потерять подстановки вроде переменных. Обязательно храните историю версий, потому что «неудачная формулировка» — частая причина отката.
Храните флаг, условия показа и аудит изменений как данные, но закрепляйте назначение варианта для пользователя, чтобы он не «прыгал» между A и B. Не меняйте распределение и смысл вариантов посреди теста, иначе метрики перестанут быть сравнимыми.
Разделите роли: кто видит, кто редактирует черновик, кто публикует, и кто имеет экстренный доступ на откат. Добавьте валидацию типов и диапазонов, дифф перед публикацией и журнал «кто/когда/зачем», чтобы инциденты разбирались быстро и с фактами, а не догадками.