Допустим, вы хотите разработать новую фичу, но не уверены, что она понравится пользователям, и вам нужно иметь способ безболезненно её скрыть. Или предположим, что вы работаете над новой большой фичей и хотите избежать монстр-коммитов. Или просто хочется сделать поведение сайта легко конфигурируемым. Как можно решить все эти проблемы, читайте под катом.
Проблема
Представьте, что циклы разработки вашей команды длятся по две недели, а реализация новой фичи потребует от команды 3 месяца разработки. На первый взгляд, есть две возможные схемы действий:
- Создать отдельную ветку и в течение трёх месяцев выполнять в ней всю работу, периодически делая pull из родительской ветки
- Использовать концепт непрерывной интеграции (Continious Integration или коротко CI): декомпозировать задачу и мёржить код небольшими порциями
Оба этих подхода имеют свои вполне очевидные достоинства и недостатки:
Достоинства
Недостатки
Долгоживущая ветка
Код вашей неготовой фичи не будет находиться в родительской ветке и не будет мозолить глаза другим разработчикам
- Постоянные merge-конфликты, которые вам потребуется разрешать
- Монструозный pull request, непригодный для code-review
Много коммитов из веток, с коротким сроком жизни
Задача хорошо декомпозирована и мёржится небольшими порциями, нет необходимости разрешать merge-конфликты
Ваша неготовая фича будет нервировать других разработчиков и, возможно, вызывать сторонние эффекты на UI
Использование feature switcher-ов для решения проблем
Такая проблема встречается в разработке довольно часто и есть изящное решение, позволяющее взять лучшее от описанных выше подходов — feature toggle или feature switcher.
По сути, feature switcher — это boolean флаг, который хранится в базе данных и содержит информацию о том, должна быть включена та или иная фича или нет. Значение этого флага может быть извлечено из базы данных по ключу. Удобство использования feature switcher-ов заключается в том, что они могут быть легко изменены бизнес-пользователем во время runtime через панель администратора без необходимости заново деплоить приложение.
Ниже приведен пример использования feature toggle на языке Java:
if (configurationManager.getParameter("is.some.functionality.enabled")) {
// do some stuff
} else {
// do default logic
}
В примере выше configurationManager — это класс, позволяющий извлечь значение определенного feature switcher-а из базы данных по его ключу.
Также, при помощи feature switcher-ов, можно отображать/скрывать определенные элементы на фронтенде. Для этого придется положить значение флага в Model и передать его на View как это показано ниже:
@ModelAttribute("isSomeFunctionalityEnabled")
public void isSomeFunctionalityEnabled() {
return configurationManager.getParameter("is.some.functionality.enabled");
}
После чего использовать переданное значение для рендеринга того или иного HTML кода:
<c:choose>
<c:when test="${isSomeFunctionalityEnabled}">
<!-- Render some stuff -->
</c:when>
<c:otherwise>
<!-- Render some other stuff -->
</c:otherwise>
</c:choose>
Виды feature switcher-ов
Описанный концепт использования feature switcher-ов — это лишь один возможный случай использования и такие feature switcher-ы называются release toggles. Всего выделяют 3 разных вида feature switcher-ов:
- release toggles — позволяют скрывать не до конца имплементированные фичи во время их разработки
- experiment toggles — переключатели для A/B-тестирования
- permissioning toggles — включатели/выключатели фич для различных групп пользователей
Таким образом, используя feature switcher-ы, можно построить две различные версии сайта на одной кодовой базе, используя разные БД и разные наборы feature switcher-ов. Например, на европейском сайте имеет смысл включать все фичи, имеющие отношение к GDPR, а на российском этого можно и не делать.
Проблемы использования feature toggle-ов
Поскольку я работаю на проекте, где активно используются feature toggle-ы, то кроме очевидных достоинств их использования я начал замечать и проблемы, связанные с ними:
- Сложность тестирования: при выходе нового релиза, QA инженеры тестируют все фичи, которые в него входят, а также пробуют включать и выключать их, используя feature switcher-ы. Это требует большого количества дополнительного времени, так как желательно протестировать всевозможные комбинации флагов
- Появление мёртвого кода: значения многих feature toggle-ов не меняются на протяжении длительных промежутков времени или не меняются вовсе, и таким образом код, написанный для другого значения флага, фактически становится «мёртвым»
- Неожиданные поломки сайта: многие из устаревших feature switcher-ов имеют досадное свойство ломать что-либо при изменении своего значения (так как никто давно не проверял, что они работают). Так как feature switcher-ы хранятся в БД и могут быть легко изменены бизнес-пользователями из панели администратора, часто происходят поломки, вызванные изменением их значения. Работоспособность давно неиспользованных feature switcher-ов стоит сперва проверить на тестовом окружении
Решения некоторых из описанных проблем
Помочь решить вышеописанные проблемы могут следующие действия:
- Документирование имеющихся feature switcher-ов: чтобы понимать, какой эффект имеет тот или иной feature toggle и по какому ключу его искать в базе данных, следует создать подробную документацию с описанием всех feature switcher-ов.
- Периодическая ревизия feature switcher-ов: чтобы избежать появления “мёртвого” кода, нужно периодически удалять устаревшие feature switcher-ы и связанный с ними код
Итоги
Feature switcher — очень простой и одновременно мощный механизм, позволяющий избегать монструозных коммитов, легко менять поведения приложения или собирать несколько разных приложений на одной кодовой базе, используя разную конфигурацию feature toggle-ов.
Однако, стоит также помнить, что этот паттерн разработки имеет некоторые недостатки, которые выливаются в трудночитаемый и трудно поддерживаемый код, поэтому следует избегать чрезмерного использования этого паттерна и периодически проводить документирование feature switcher-ов и их ревизию, чтобы удалять неиспользуемые и, как следствие, очищать проект от “мёртвого” кода.