Як застосувати динамічну конфігурацію Feature Toggles
Мене звуть Сергій Бута, я бекенд-розробник і спеціаліст з Azure у фінтех-компанії Wirex, що створює фінансові рішення для розрахунків у цифровій і традиційній валютах. У цій публікації хочу поділитися з вами досвідом використання інструменту Feature Toggles та його динамічної конфігурації. Матеріал створено на основі мого виступу на .NET Fest, де я розповідав про еволюцію фічатоглів у Wirex і, зокрема, про actions — правила бізнес-логіки динамічного інтерфейсу клієнтів на основі доступних користувачеві дій. У цій статті проаналізуємо такі пункти:
- що таке фічатогли;
- фічатогли на Back-end;
- що таке actions та як вони працюють;
- які перспективи створюють фічатогли.
Зазначу, що в цьому матеріалі йтиметься про практичний досвід використання інструменту Feature Toggles у Wirex, механіку роботи, а також успіхи й труднощі, пов’язані з імплементацією фічатоглів. Більше про теорію використання цього інструменту можна дізнатися зі статті.
Розпочнімо нашу мандрівку з докладнішого ознайомлення з фічатоглами.
Що таке фічатогли
Фічатогл — це інструмент, що допомагає змінювати поведінку програми в реальному часі. Це має такий вигляд: у нас є умова, в якій ми перевіряємо доступність фічі. Order Card — назва фічі, її ідентифікатор. Залежно від того, доступна фіча чи ні, програма поводиться по-різному. Якщо доступна, то, наприклад, показуємо користувачеві кнопку «Замовити картку». В іншому разі користувач потрапить у список очікування і може бути одним з перших, хто одержить картку.
Уся «магія» ховається за перевіркою Feature Available. Перевірку доступності фічі можна звіряти з простим файлом конфігурації, а можна розвинути до крутої розподіленої системи з окремим UI, що дасть змогу змінювати фічі для всіх за одну мить.
Спочатку ми мали просту систему Feature Toggle, а також файл конфігурації з Feature Name та її статусом: доступна або недоступна. Тому змогли закрити більшість точок інтеграції партнерів. Наприклад, під час оновлення версії блокчейну могли вимкнути фічатогли, які відповідали за інтеграцію з цим блокчейном, щоб тимчасово вимкнути цю функційність для користувачів. Одночасно дозволяли клієнтам користуватися всіма іншими частинами нашого продукту. Тобто користувачі, які працювали б з фіатними валютами, узагалі не помітили б жодних змін.
Фічатогли на Back-end у Wirex
Не винятком була ситуація, коли партнери змінювали API, оновлювали до нестабільної версії або були просто недоступні. Тоді нам доводилося вимикати фічу, щоб у користувачів не виникло проблем з інтеграцією на собі. Проаналізувавши використання фічатоглів, зрозуміли, що можна використовувати Feature Context, щоб у продакшені команда QA стала першою, хто зміг використовувати й оцінювати нову функційність. У такий спосіб ми змогли перевіряти цілісність інтеграції з нашою third party ще до її ввімкнення для інших користувачів. Якщо все було гаразд, то відкривали для всіх інших ці фічі. Якщо ні, і продакшен-версія third party відрізнялася в поведінці від Sandbox (що також є звичною справою з third party), вмикали тогл лише після розв’язання всіх питань.
Як це все в нас працювало на Back-end? Попередня система з назви фічі та її статусу не була досить гнучкою (вона вмикала або вимикала функціонал відразу для всіх користувачів), тому ми спроектували нову версію фічатоглів у нашій системі. Нова версія містила три таблиці: Features, Rule sets (набори правил), Rules. Кожна фіча могла мати чимало таких наборів, і кожен з них містив щонайменше одне правило.
Rule sets сортували за пріоритетом, бо за першого збігу контексту з набором правил ми визначали статус фічі конкретного користувача. Наприклад, у нас є два типи цих наборів: один тип дозволяє фічу, інший її забороняє. Припустімо, ми хочемо ввімкнути фічу лише для Великої Британії. Тоді задаємо Rule sets з вищим пріоритетом, в якому перевірятимемо, чи справді користувач з Великої Британії, а вже після нього створюємо набір з нижчим пріоритетом DenyAll.
Самі правила були такі: ми задавали значення, наприклад Україна, а далі вказували властивість з контексту для перевірки, у цьому випадку — країна. І додавали оператора для перевірки, чи збігається країна користувача із заданою.
Припустімо, у нас є правило, що надає доступ лише для Великої Британії. Відповідно, користувач, в якого в контексті країна буде United Kingdom, матиме доступ до фічі. А для клієнта з Франції вона буде недоступна.
Також у нас використовують й інші оператори: більше, менше, починається з, закінчується на, які допомагають вирішувати інші кейси.
Отже, ми могли по-різному задавати фічі за контекстом, автоматично вмикати й вимикати їх залежно від вимог регуляторів. Наприклад, регулятор повідомив нас за два місяці про нові вимоги. Після розробки ми тестуємо всі зміни — і за два тижні готові до релізу. Щоб не відкладати час релізу до вказаного регуляторами, закриваємо нові вимоги фічатоглом. Потім, після релізу, команда QA перевіряє, чи все працює на фінальній версії, і тоді ми могли налаштувати автоматичне ввімкнення фічі для всіх користувачів у зазначений регуляторами час.
Що таке екшени (actions), і як вони працюють
Окрім бекендних, є ще й клієнтські фічі, і їхнє вимкнення може спричинити негативну реакцію користувачів. Щоб коригування відбувалося непомітно для клієнтів, ми вирішили використовувати такий інструмент як actions.
Аctions — це наша розробка, яка містить набір можливих дій клієнтів з певним ресурсом, а також глобальних дій. У нас actions розділяють на Global actions (це такі глобальні дії, як замовити нову картку, створити новий акаунт і все, що не пов’язано з конкретним ресурсом) та Object actions. Конкретний ресурс мав свій набір екшенів. Наприклад, для картки це може бути «заблокувати», якщо ви її загубили, для акаунту — отримати адресу, зробити переказ або обміняти кошти. Екшен складався із двох параметрів: {allowed:bool, reason:string}, де причину вказували тільки тоді, коли action був недоступний.
Щоб визначити, доступний чи недоступний action, недосить було самого фічатоглу. Хоча ми й маємо систему Rule sets, по-перше, задавати бізнес-логіку через них було б незручно. По-друге, підтримувати таку бізнес-логіку на рівні бази даних було б дуже складно, тому ми зробили Evaluation Chains, де могли перевіряти доступність фічі в Rule sets, і далі проводити валідацію за складнішою бізнес-логікою.
Наприклад, щоб визначити доступність action-активації картки, перевіряємо, чи доступна фіча, дивимося, чи користувач має верифікований профайл, чи в нього на всіх акаунтах позитивний баланс. Перевіряємо фічі (вони відразу зберігаються в нас в оперативній пам’яті) дуже швидко, а профайл — трішки довше, бо треба взяти профайл з одного з наших сервісів, зробити виклик, отримати дані й перевірити, чи юзер у нас верифікований. А перевірка балансу на всіх акаунтах найзатратніша в цьому разі.
Насправді різні фічі в різний час доступні тільки невеликій групі користувачів. Припустімо, що активувати картку можуть тільки ті користувачі, які насправді її мають. Отже, перевіряти для всіх Evaluation Chains від початку до кінця не треба. Якщо в нас фіча недоступна, ми можемо відразу відповісти, чому цей action недоступний для користувача. Ось чому ми вибудовували наші ланцюжки так: від початку ставили легші операції, а на кінець — важчі. Тому й не отримали сильного зростання навантаження на наші сервіси, коли зарелізили першу серію екшенів. Вони в нас уже були зоптимізовані для оптимального використання ресурсів.
Розгляньмо, що ще можна робити за допомогою цих екшенів на прикладі активації картки. Підтримуючи два типи карток у різних країнах чи в різних регіонах, ми могли б зав’язати частину бізнес-логіки на клієнтів. Залежно від типу картки, клієнти проходять відповідний процес її активації. Але якщо ми хочемо ввести третій вид картки — це виходить не так швидко, адже вимагає певного часу для проходження всіх етапів. Нам треба оновити всі наші клієнти (це OS, Android і Web-клієнти), перевірити, чи все працює, задеплоїти оновлені версії в маркетплейси, почекати, поки їх затвердять і користувачі оновляться до наступних версій. І якщо бізнесу треба змінити цей flow — доведеться проходити ці етапи заново.
Тому ми перенесли процес активації на рівень екшенів, щоб абстрагувати наших клієнтів від бізнес-логіки. Знаючи, який крок треба зробити далі або чому цей крок саме тепер недоступний, ми можемо вибудовувати нашу систему зовсім по-іншому.
Спрощена модель відповіді: {allowed:bool, reason:string} замінено на allowed, коли екшен доступний, і на Reason, якщо недоступний
Наприклад, два види карток на початку мають доступний екшен валідації. Тобто ми доставили картку поштою, а користувач повинен ввести дату завершення її дії та останні цифри номера картки, щоб ми переконалися, що клієнт справді її одержав.
Після валідації клієнти перечитують оновлені екшени картки. Для різних типів карток вони матимуть у доступі різні екшени.
В одному регіоні клієнтам стає доступний SetPin. Це означає, що користувачі бачать кожне наступне вікно для подальших операцій. А в іншому регіоні наступним для нього буде action активації. Що ж ми отримаємо? Ми можемо не передавати тип карток на клієнтів і змінювати поведінку без оновлення.
Наприклад, нещодавно трапилася ситуація, коли регулятори просили ввімкнути в певних країнах верифікацію всіх користувачів. І тоді в нас уже була причина Verification Required. Наші клієнти вміли його обробляти: показували сторінку, яку треба верифікувати. Тому ми могли змінити логіку роботи без зміни клієнтів. Для багатьох об’єктів зазначили, що цей екшен недоступний, бо потрібна верифікація. Так ми підтримували абсолютно новий flow.
Які можливості створюють фічатогли
Якщо розглядати самі екшени, то маємо новий потенціал. Можемо змінювати бізнес-логіку без деплою і релізів наших клієнтів. Проте ми розростаємося і запустили продукт в Азії, далі в США. Перед нами постають нові виклики, і треба буде підтримувати різну комбінацію фічатоглів у різних регіонах. Тому ми й далі вдосконалюватимемо нашу систему. Та навіть якщо розглядати систему тепер, то вже можна сказати, що наступну глобальну версію нашого продукту ми зможемо запускати зовсім інакше.
До використання фічатоглів й екшенів нам треба було синхронізувати роботу між різними командами й зарелізити Back-end, нові версії для клієнтів, почекати на затвердження і лише потім вмикати нову версію нашого продукту. Оновлення на клієнтах не відбувається миттєво, тому користувачі повинні були вручну оновлювати застосунок, щоб користуватися найновішою версією.
Тепер ми можемо зробити це миттєво: задеплоїти Back-end, проапдейтити клієнтів (усі вони отримають оновлення з вимкненими фічатоглами, а також вимкненими фічами на Back-end). Коли ж бачимо готовність до запуску, тоді вмикаємо фічатогли на Back-end та на клієнтах у конкретний час і можемо синхронізуватися з рекламною кампанією. Коли цей час настає — усі користувачі в усьому світі вже бачать іншу версію нашого застосунку, наш новий продукт. Для мене це сильний вау-ефект, і саме він розкриває весь потенціал фічатоглів.