Много было написано о преимуществах достижения настоящей непрерывной интеграции (CI) в производственные системы. В этом руководстве будет продемонстрирован простой рабочий процесс, обеспечивающий непрерывную интеграцию. Мы будем использовать Feature Flags и Remote Config, чтобы избежать необходимости в ветках функций в Git, а также в любых тестовых или промежуточных средах. Два основных инструмента, которые мы будем использовать для демонстрации этого подхода, — Netlify и Bullet Train.

Что мы подразумеваем под флагами CI и функций

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

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

Почему КИ так эффективна

Интеграция кода небольшими порциями и более часто позволяет командам разработчиков гораздо быстрее выявлять проблемы, а также как можно быстрее предоставлять пользователям новые функции. Конвергентная инфраструктура также устраняет необходимость в крупных релизах, когда команда инженеров должна бодрствовать до полуночи, чтобы свести к минимуму неудобства для своих пользователей.

Как флаги функций помогают непрерывной интеграции

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

Раньше это означало бы (вероятно) длительную и (определенно) болезненную процедуру отката и перенос релиза на еще один безбожный час в другой день, когда ошибка будет исправлена. Вместо этого с помощью переключателя эту функцию можно отключить для всех или части пользователей, и проблема исчезнет. После того, как ошибка будет выявлена ​​и исправлена, может быть выпущен выпуск исправления, а функция может быть повторно включена.

Схема нашего типового проекта

Чтобы продемонстрировать интеграцию флагов функций и удаленной конфигурации, мы собираемся основывать нашу исходную кодовую базу на учебнике де-факто React JS игры в крестики-нолики. Это отличный учебник для изучения основ React, поэтому обязательно ознакомьтесь с ним, если вы еще этого не сделали.

Не волнуйтесь, если вы плохо знаете React или Javascript. Все концепции, которые мы рассмотрим, касаются процесса и инструментов, а не кода.

Вместо того, чтобы повторять учебник с самого начала, мы начнем с того момента, когда у нас есть базовая игра в крестики-нолики.

На этом этапе мы будем использовать флаги функций и удаленную настройку для постоянной настройки, продвижения и развертывания новых функций. Чтобы довести эту концепцию до крайности, мы будем постоянно стремиться к совершенству; никакие другие ветки использоваться не будут. Мы введем ошибку (конечно, намеренно!) и отправим исправление в мастер, чтобы продемонстрировать, что работа с этим сценарием не требует полного отката или дополнительного ветвления.

Если вы хотите продолжить написание кода во время этого урока, вы можете разветвить репозиторий здесь.

Достижение непрерывной интеграции

Самый распространенный метод автоматизации непрерывной интеграции — запуск процесса сборки при отправке изменений в репозиторий git. Различные инструменты сборки достигают этого по-разному.

Мы собираемся использовать Netlify для нашего проекта. Netlify позволяет подключить репозиторий Git и автоматически развертывать сборки каждый раз, когда вы отправляете их в ветку.

Чтобы использовать Netlify, просто зарегистрируйте бесплатную учетную запись и выберите параметр «Новый сайт из Git» в правом верхнем углу панели инструментов. После того, как вы подключили свою учетную запись GitHub (или иным образом, если вы хотите использовать Bitbucket или GitLab), вам должны быть представлены параметры, показанные ниже.

На следующем шаге настройте Netlify для запуска приложения следующим образом.

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

Переход по этому URL-адресу должен показать вашу игру Tic Tac Toe во всей красе.

Настройка флагов функций для нашего проекта

Мы собираемся использовать функциональные флаги для управления объявлением победителя в игре крестики-нолики. Для создания флагов функций и управления ими мы будем использовать Скоростной поезд, поскольку в настоящее время он бесплатен, но есть много других продуктов с флагами функций. Мы позволим вам выбрать тот, который вы считаете правильным.

Чтобы продолжить с нами, создайте бесплатную учетную запись на Bullet Train. Нажмите на кнопку «Создать проект» и создайте свой проект. Мы назвали наш FF Tutorial.

Затем нам нужно создать новую функцию для объявления победителя.
Нажмите кнопку «Создать свою первую функцию» в нижней части следующего экрана, чтобы открыть следующую форму и добавить детали.

Обратите внимание, что мы оставили эту функцию отключенной с самого начала.

Обратите внимание на два фрагмента кода, доступные под функцией, которые помогут нам на следующем этапе.

Реализуйте флаг функции

Во-первых, давайте запустим этот проект в нашей среде разработки. В командной строке перейдите в папку проекта и выполните команду npm i, чтобы установить необходимые зависимости.

Затем запустите npm run dev и перейдите к http://localhost:8080 в браузере. Вы должны увидеть ту же игру в крестики-нолики, которую вы видели на URL-адресе Netlify.

Теперь мы собираемся внедрить наш новый флаг функции в существующий код. Давайте начнем с установки клиента Bullet Train для JavaScript, открыв другую командную строку и выполнив в каталоге проекта следующее:

npm i bullet-train-client --save

Откройте проект в предпочитаемом вами редакторе и отредактируйте ./web/App.js.

Найдите функцию calculateWinner(squares). Эта функция определяет, был ли победитель или нет, основываясь на том, может ли она найти линию той же формы или нет. Мы собираемся сделать так, чтобы эта функция возвращала null на основе значения нашего флага функции, чтобы мы могли протестировать заполнение доски без объявления победителя.

В самом верху App.js добавьте следующую строку:

var declareWinner = true;

Теперь давайте инициализируем наш клиент Bullet Train, который мы установили ранее. Скопируйте весь пример кода 2 со страницы «Функции» в интерфейсе Bullet Train и вставьте его сразу под только что добавленной строкой.

Идентификатор среды в вашем фрагменте кода будет правильным идентификатором среды, связанным со средой разработки в вашем проекте Bullet Train. Вы можете проверить это, перейдя на страницу «Настройки среды», если хотите.

Теперь нам нужно отредактировать функцию onChange() в функции bulletTrain.init() в коде, который мы только что вставили, в соответствии с нашими потребностями. Замените весь код одной строкой:

declareWinner = bulletTrain.hasFeature("declare-winner");

Теперь вы должны иметь это в верхней части вашего App.js.

var declareWinner = true; import bulletTrain from "bullet-train-client"; //Add this line if you're using bulletTrain via npm bulletTrain.init({ environmentID:"<your-environment-id>", onChange: (oldFlags,params)=>{ //Occurs whenever flags are changed declareWinner = bulletTrain.hasFeature("declare-winner"); } });

Прокрутите вниз до функции calculateWinner(squares) и вверху, чуть выше объявления константы lines, добавим строку:

if (!declareWinner) return null;

И это все! Наш флаг функции теперь будет определять, вычисляется ли победитель при каждом рендеринге игры. Обновите браузер и играйте. Вы больше не можете побеждать, и вместо этого вся доска теперь может быть заполнена крестиками и ноликами.

Вернитесь к администратору Bullet Train и включите функцию с помощью переключателя справа.

Обновите браузер, и игра снова станет выигрышной. Посмотрите код конца этой части здесь.

Зафиксируйте и отправьте свой код (да, все на master), и Netlify автоматически развернет ваш код. Снова перейдите к назначенному URL-адресу Netlify и переключите флаг функции, чтобы увидеть, как она работает в производственной среде. Сладкий!

Работа над ошибкой

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

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

Во-первых, давайте установим наш флаг функции, чтобы обернуть новую функцию. В своем проекте Bullet Train создайте новую функцию с именем select-who-goes-first следующим образом. Давайте оставим его отключенным для начала.

Теперь давайте добавим нашу новую функцию. В функции render() мы будем отображать кнопки вместо статуса, если игра еще не началась. В верхней части возврата функции render() замените строку:

<div className="status">{status}</div>

… со следующим кодом:

{!this.state.selected ? ( <div> Who goes first? <button onClick={() => this.setState({selected: true})}>X</button> <button onClick={() => this.setState({selected: true, xIsNext: false})}>O</button> </div> ) : ( <div className="status">{status}</div> )}

Теперь мы хотим написать код для управления нашей новой функцией с помощью созданного нами флага функции. Как и раньше, это нужно сделать в функции bulletTrain.init({...}).

Во-первых, давайте добавим функцию жизненного цикла componentDidMount() в компонент Board, а затем переместим внутрь нее всю функцию bulletTrain.init({...}), чтобы мы могли обновлять состояние компонента после получения флага:

class Board extends React.Component { componentDidMount() { bulletTrain.init({ environmentID:"<your-environment-id>", onChange: (oldFlags,params)=>{ //Occurs whenever flags are changed declareWinner = bulletTrain.hasFeature("declare-winner"); } }); } // [rest of class] }

Если бы мы оставили bulletTrain.init({...}) за пределами компонента, мы не смогли бы вызвать this.setState() и заставить компонент перерисовываться из-за изменений в наших флагах.

Теперь давайте добавим код для управления нашей новой функцией. Мы хотим, чтобы приложение вело себя так же, как до того, как мы добавили эту функцию, если флаг отключен. Для этого давайте установим значение состояния для selected в true, если флаг отключен. Добавьте следующую строку в метод bulletTrain.init({...}) прямо под строкой declareWinner.

this.setState({selected: !bulletTrain.hasFeature("select-who-goes-first")});

Давайте продолжим и нажмем это (опять же, прямо в master). Как только он будет построен, перейдите по URL-адресу Netlify. Вы должны увидеть, что ничего не изменилось — это потому, что эта функция по-прежнему отключена в нашем проекте Bullet Train.

Перейдите к Bullet Train и включите эту функцию.

Великолепно! Теперь мы видим, как это работает, но, о, есть ошибка! Можно начать игру, не выбирая, кто ходит первым. Если вы играете в игру таким образом, вы можете видеть, что статус никогда не устанавливается для отображения победителя. Это не правильно!

Вернитесь к Bullet Train и отключите эту функцию, пока мы не разберемся, что не так. Именно здесь пригодятся дополнительные функции Bullet Train, такие как среда и пользователи. Мы не будем вдаваться ни в один из них в этом руководстве, но ознакомьтесь с документами, чтобы узнать больше об использовании нескольких сред или управлении функциями для каждого пользователя.

Вернемся к нашей ошибке: есть еще одна строка, которую нам нужно было добавить в самый верх handleClick(), чтобы игроки не начинали, пока не будет выбран первый игрок. Добавьте следующее вверху функции handleClick().

if (!this.state.selected) return;

Снова включите эту функцию в Bullet Train и протестируйте ее в своей локальной среде, и вы должны увидеть, что теперь мы предотвращаем запуск игры без выбора того, кто ходит первым. Отлично! Снова зафиксируйте это в мастере и нажмите прямо для развертывания.

Перейдите по URL-адресу Netlify, и вы увидите, что новая функция исправлена ​​и работает правильно.

Вы можете увидеть окончательный код в конце этого раздела здесь.

Удаленная конфигурация

Теперь мы рассмотрим небольшую вариацию флагов функций, называемую удаленной конфигурацией. Удаленная конфигурация позволяет вам контролировать не только то, включена функция или нет, но и удаленно изменять заданное значение без изменения кода. Это удобно во многих разных местах, например, если вы хотите иметь возможность настроить некоторые аспекты стиля.

В нашем уроке мы будем использовать это, чтобы изменить формы, используемые каждым игроком в нашей игре. Давайте создадим два значения удаленной конфигурации для того, какие фигуры использовать на доске. В вашем проекте Bullet Train нажмите кнопку «Создать функцию», но на этот раз выберите вкладку «Удаленная конфигурация» вместо «Флажок функции». Заполните данные, как показано ниже.

Все сделано! Теперь вернемся к коду. В функции onChange() нашего клиента Bullet Train нам нужно получить эти значения и установить их в состояние компонента. Давайте изменим наш вызов this.setState() на:

this.setState({ selected: !bulletTrain.hasFeature("select-who-goes-first"), shape1: bulletTrain.getValue("shape-1") || 'X', shape2: bulletTrain.getValue("shape-2") || 'O' });

Теперь у нас есть две формы, и мы можем заменить все статические использования в App.js «X» и «O» значениями состояния. Должно быть 3 экземпляра каждого: 1 на фигуру в handleClick() и 2 на фигуру в render() (один находится в вызове return). Вот обновленный код ссылки в handleClick():

handleClick(i) { // ... squares[i] = this.state.xIsNext ? this.state.shape1 : this.state.shape2; // ... }

Обратите внимание, что для экземпляров в вызове return в render() вам нужно будет заключить JavaScript в фигурные скобки следующим образом:

<button onClick={() => this.setState({selected: true})}>{this.state.shape1}</button>

Зафиксируйте это в мастере и отправьте в свой репозиторий Git, чтобы увидеть изменения в вашем URL-адресе Netlify. Если вы все сделали правильно, игра должна продолжаться, как и прежде, с фигурами «X» и «O». Идите вперед и измените формы в админке на разные буквы и обновите страницу. Если все хорошо, теперь вы будете играть с разными фигурами.

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

Другие вещи, о которых стоит подумать

Однако флаги функций не следует рассматривать как золотую пулю, и они имеют определенные оговорки.

Например, если вы используете фреймворк, который обрабатывает схему базы данных за вас, например Django или Rails, вам нужно быть осторожным при реализации флагов функций в ваших моделях. Использование флагов функций в ваших моделях может привести к несоответствию схемы БД, что может привести к остановке некоторых частей вашего приложения.

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

Наконец, мы использовали Bullet Train в уроке выше, так как на данный момент он бесплатен, а также имеет открытый исходный код. Существует ряд других продуктов, делающих то же самое или с немного отличающимися вариантами — вам следует проверить их все, чтобы определить, что лучше для вас. Например, Launch Darkly и HQ Airship.

Познакомьтесь с автором

Бен основал лондонское агентство Solid State Group и The Hoxton Mix. Он увлечен программированием, созданием компаний, финансированием компаний и использованием технологий, чтобы сделать мир более приятным. Он написал свою первую веб-страницу в 1994 году, что, вероятно, делает его слишком старым.

Первоначально опубликовано на сайте www.sitepoint.com 25 июля 2018 г.