Назад до блогу

Абстракція пристроїв у системах керування кількома акаунтами: чотири ключові групи полів

Під час створення системи керування кількома акаунтами спочатку варто визначити не інтерфейс, а поля й життєвий цикл шару пристроїв. Невдала абстракція спричиняє каскад переробок, коли зростає кількість акаунтів або змінюються типи пристроїв.

Під час розробки системи керування кількома акаунтами першу версію найчастіше починають з інтерфейсу: створюють список акаунтів, до кожного прив’язують профіль браузера, а потім викликають інтерфейси для виконання операцій. Це здається достатнім, доки система не починає працювати по-справжньому.

Перша реалізація зазвичай дуже прямолінійна. Акаунт A вказує на профіль 001, акаунт B — на профіль 002, а акаунт C під’єднаний до хмарного телефона. Далі проблеми з’являються в трьох місцях: операційна команда каже, що машина зламалася, і питає, чи можна перенести акаунт A на хмарний телефон, але відповідь означає зміну бази даних, ручну роботу й ризик; підключається нове джерело пристроїв, і на запитання, як його додати, з’ясовується, що треба переробляти модуль акаунтів; або один і той самий акаунт має вранці працювати в браузерному середовищі, а після обіду — на хмарному телефоні, що майже неможливо нормально організувати за часовими слотами.

Ці три сценарії здаються не пов’язаними, але причина в них одна: у сутність акаунта поміщено дані, які їй не належать. Поточний пристрій входу, раніше використані пристрої, параметри відбитка та вихідна адреса зберігаються безпосередньо в акаунті. У результаті зміна пристрою стає зміною акаунта й тягне наслідки для всієї системи.

Пристрій має бути окремим типом об’єкта

Після розділення акаунти та пристрої повинні мати зв’язок багато-до-багатьох. Акаунт не зберігає відбиток, а лише фіксує, до якого пристрою він прив’язаний зараз. Зміну пристрою слід виконувати як атомарну операцію, історію прив’язок зберігати в окремій таблиці, а кожен пристрій має мати унікальний ідентифікатор — єдине зовнішнє посилання на нього — зі статусом, доступним у реальному часі.

Це робиться не заради красивої моделі. Такий підхід скорочує відстань між зміною, яку хоче зробити операційна команда, і зміною коду, яку має внести розробка, а ця відстань зростає разом із кількістю пристроїв.

Чотири групи полів, які шар абстракції має чітко визначити

Масштабована абстракція пристроїв повинна назовні відповідати лише на чотири запитання.

  • ID середовища: унікальний і стабільний. Верхні шари посилаються на середовище тільки через нього; внутрішні номери, назви контейнерів та ID процесів не повинні бути видимі зовні
  • Прив’язка виходу: через який мережевий вихід працює середовище і чи утворюють пов’язані часовий пояс, мова та DNS узгоджений набір. Винесення виходу в окрему абстракцію дає змогу змінювати його без зміни самого середовища
  • Статус: створюється, готове до запуску, працює, зайняте завданням, аварійне, очікує повернення. Без моделі статусів неможливо нормально керувати пулом і поверненням ресурсів
  • Життєвий цикл: хто запускає створення, старт, зайняття, звільнення та повернення; що відбувається при тайм-ауті завдання; і хто завершує очищення, якщо середовище працює ненормально

Статус і життєвий цикл часто об’єднують в одне поле. Це найпростіший і водночас найдорожчий варіант. Статус відповідає, яким середовище є зараз; життєвий цикл — хто може діяти з ним наступним. У продакшені справжні проблеми майже завжди виникають у другій частині: завдання падає, а середовище ніхто не звільняє, або ще активне середовище повертають у пул, і лише під час наступного запуску з’ясовується, що вихід уже змінився.

账号通过绑定历史连接设备抽象层,再统一接入浏览器环境和移动设备,并由四类字段管理

Помилка в абстракції виставляє рахунок під час масштабування

При десяти середовищах проблеми можуть бути непомітні. При десятках або сотнях вони з’являються одночасно:

  • Додавання нового типу пристрою вимагає змін у модулі акаунтів, тому область регресійного тестування розширюється із шару пристроїв на шар акаунтів
  • Зміна пристрою вимагає правки бази даних, через що операційна команда боїться це робити, а систему поступово можуть підтримувати лише розробники
  • Без записів про статус і зайнятість середовища, що залишилися після аварійних завершень, не повертаються, а «зомбі»-середовища накопичуються
  • Завдання, контент і автоматизація верхніх шарів побудовані на припущенні про зв’язок один-до-одного між акаунтом і пристроєм, тому зміна цієї основи вимагає переробки всього ланцюга

Пристрої з різних джерел дуже відрізняються реалізацією: локальні браузерні середовища та хмарні телефони використовують зовсім різні інтерфейси. Завдання шару абстракції — сховати їх за одним набором інтерфейсів. Для додавання нового типу пристрою має бути достатньо адаптера, який реалізує запуск, зупинку та запит статусу; логіка верхніх шарів не повинна змінюватися. Є й простий практичний тест якості абстракції: чи обмежується зміна коду одним файлом, коли додається новий тип пристрою?

На першому етапі краще зробити якомога менше

Коли технічну модель визначено, інтерфейс стає значно природнішим. Меню слід організовувати за бізнес-об’єктами: окремі розділи для акаунтів, завдань і пристроїв, а не для конфігурації, параметрів і журналів. Найпомітнішими мають бути статус і винятки, тому що користувач шукає проблеми, а не кількість записів.

Функціонально на першому етапі достатньо списку пристроїв, додавання пристроїв і одного мінімального наскрізного циклу виконання завдання. Меню варто максимально скоротити, спочатку повністю запустити один сценарій і відкласти все непотрібне.

Якщо не хочеться реалізовувати ізоляцію середовищ з нуля, можна скористатися готовими можливостями. PurpleMark надає незалежні середовища та прив’язку виходу, підтримує пакетне створення за групами й запити статусу. Верхньому шару залишається реалізувати шаблони, зайнятість і планування завдань, зберігаючи інженерні ресурси для бізнес-логіки.

Складність системи з кількома акаунтами полягає не в їх кількості, а в керуванні життєвим циклом пристроїв. Якщо спочатку розглядати пристрій як ресурс з ідентичністю, виходом, статусом і життєвим циклом, функції верхніх шарів не доведеться перебудовувати при кожному розширенні.