Статьи

Переключатели функций (переключатели функций или флаги функций) и ветви функций

Особые ветви

Если вы используете филиалы, вы не делаете непрерывную интеграцию / развертывание / доставку !

У вас может быть отличное покрытие кода с модульными тестами , у вас может быть TDD , у вас могут быть функциональные и интеграционные тесты, написанные в формате BDD , и вы можете запускать их все при каждой фиксации в хранилище. Однако, если у вас есть ветви, интеграция откладывается до тех пор, пока они не объединятся, а это означает, что непрерывная интеграция отсутствует.

Люди, как правило, любят тематические ветви. Они предоставляют гибкость, чтобы решить, что выпустить и когда. Все, что нужно сделать, — это объединить функции, которые будут выпущены в основной ветке, и развернуть в производство. Проблема с этим подходом заключается в задержке. Интеграция задерживается до слияния. Мы не можем знать, работают ли все эти отдельно разработанные функции вместе, пока не будет выполнено слияние и не будут выполнены все модульные, функциональные, интеграционные и ручные тесты. Кроме того, существует проблема, связанная с болью самого слияния. Дни, недели или даже месяцы работы внезапно объединяются в основной ветке и оттуда во все еще не выпущенные ветки. Идея непрерывной интеграции заключается в обнаружении проблем как можно скорее. Минимальная задержка, пока проблемы не будут найдены.

Наиболее распространенный способ смягчить эту проблему — иметь небольшие и кратковременные ветви функций. Они могут быть объединены в основную ветку только через день или два. Однако во многих случаях это просто невозможно. Функция может быть слишком большой, чтобы ее можно было разработать всего за несколько дней. Бизнес может потребовать, чтобы мы выпустили его только в сочетании с другими функциями.

Другими словами, функциональные ветки отлично подходят для того, чтобы мы могли решить, что и когда выпустить. Они предоставляют нам гибкость, но они мешают нам осуществлять непрерывную интеграцию. Если бы была только одна ветвь, мы могли бы осуществлять непрерывную интеграцию, но проблемы с выпуском, которые были решены с помощью функциональных ветвей, снова преследовали бы нас.

Функция Toggles

Переключатели функций (иногда называемые переключателями функций или флагами функций) должны решить необходимость развертывания только выбранного набора функций при сохранении только одной (основной) ветви. С их помощью мы можем выполнять всю работу в одной ветке, непрерывно интегрироваться, заботясь о качестве нашего кода, и использовать флаги для отключения функций до тех пор, пока они не будут готовы к выпуску. Мы можем воспользоваться всеми преимуществами непрерывной интеграции, а также гибкостью выбора того, какие функции будут доступны, а какие скрыты. Более того, это шаг к непрерывному развертыванию. Если у нас есть удовлетворительное автоматическое тестирование и мы можем включать и выключать функции, то ничто не мешает нам развертывать в производство каждый коммит, прошедший всю проверку. Даже если какая-то ошибка проникнет в производство, с помощью Feature Toggles if будет очень легко отключить эту функцию, пока она не будет исправлена.

Основная идея состоит в том, чтобы иметь файл конфигурации, который определяет переключатели для функций, которые ожидают полного выпуска. Альтернативой файлу конфигурации может быть таблица базы данных. Приложение должно использовать эти переключатели, чтобы решить, делать ли какую-либо функцию доступной для пользователей или нет. Они могут даже использоваться для отображения некоторых функций для подмножества пользователей в зависимости от их роли, географического положения или случайной выборки.

Есть только несколько правил, которым нужно следовать:

  • Используйте переключатели только до тех пор, пока они не будут полностью развернуты и не доказали свою работоспособность. В противном случае вы можете получить «код спагетти», полный операторов if / else, содержащих старые переключатели, которые больше не используются.
  • Не тратьте слишком много времени на тестирование переключателей. В большинстве случаев достаточно подтвердить, что точка входа в какую-либо новую функцию не видна. Это может быть, например, ссылка на эту новую функцию.
  • Не злоупотребляйте переключателями. Не используйте их, когда в них нет необходимости. Например, вы можете разрабатывать новый экран, доступный по ссылке на домашней странице. Если эта ссылка добавляется в конце, может не потребоваться переключатель, который ее скрывает.

Примеры

Есть много библиотек, которые предоставляют решение для Feature Toggles. Однако их реализация настолько проста, что вы можете сделать это самостоятельно.

Вот несколько примеров возможных реализаций Feature Toggles. Они используют AngularJS, но их логика может быть применена к любому другому языку или структуре.

[JSON с переключателями функций]

01
02
03
04
05
06
07
08
09
10
11
{
  "feature1": {
    "displayed": false
  },
  "feature2": {
    "displayed": true
  },
  "feature3": {
    "displayed": false
  }
}

Я склонен иметь больше значений в моих переключателях JSON. Некоторые из них как отключенные, description, allow_users и т. Д. Приведенный выше пример является лишь минимальным решением.

Затем мы должны загрузить JSON, в этом примере, в область видимости AngularJS.

[AngularJS, который загружает функции Toggles в область действия]

1
2
3
$http.get('/api/v1/data/features').then(function(response) {
  $scope.features = response.data;
});

Как только функция Feature Toggles окажется в области видимости, все остальное будет довольно просто. Следующий пример AngularJS скрывает эту функцию, когда отображается значение false.

[AngularJS HTML, который скрывает некоторый элемент]

1
2
3
<div ng-show="features.feature1.displayed">
  <!--Feature HTML-->
</div>

В некоторых случаях вы можете работать над совершенно новым экраном, который заменит старый. В этом случае что-то вроде следующего может быть решением.

[AngularJS, который возвращает URL в зависимости от функции Toggle]

1
2
3
4
5
6
7
$scope.getMyUrl = function() {
  if($scope.features.feature2.displayed) {
    return 'myNewUrl';
  } else {
    return 'myOldUrl';
  }
}

Тогда из HTML это будет что-то вроде примера ниже.

[AngularJS HTML, который переключает URL]

1
2
3
<a href="{{getMyUrl()}}">
  This link leads somewhere
</a>

В некоторых других случаях изменения могут быть на сервере. Следуя рекомендациям REST API , вы должны создать новую версию API и использовать функцию Toggle, чтобы решить, какую из них использовать. Код может быть как следующий.

[AngularJS, который выполняет запрос, зависящий от переключения функций]

1
2
3
4
5
6
7
8
9
var apiUrl;
if($scope.features.feature2.displayed) {
  apiUrl = '/api/v2/myFancyFeature';
} else {
  apiUrl = '/api/v1/myFancyFeature';
}
$http.get(apiUrl).then(function(response) {
  // Do something with the response
});

Та же логика, примененная к клиентскому интерфейсу, может быть применена к серверному или любому другому типу приложения. В большинстве случаев это сводится к простым операторам if / else.