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

GadFul EVA - система інтелектуального моніторингу маркетплейсів

!!! З огляду на дуже складний договір про нерозголошення в цій кейс-статті практично не буде зображень. Тільки візуалізація загальних фронт-рішень.



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

Коротко: GadFull - ТОП 1 бренд, партнер компанії Amazon, у кількох країнах лідер за різними напрямами - смартфони, акумулятори, оргтехніка та витратні матеріали, інструменти, товари для дому. Сотні тисяч клієнтів, тисячі відгуків, штат аналітиків, найскладніші бізнес-процеси.

Через кілька років клієнт планує отримати багатофункціональну платформу моніторингу, частково керовану штучним інтелектом. Усе просто (ні).

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

Звичайно, вдаватися в конкретику та нюанси, з огляду на NDA, не вийде, але суть така: співробітники відділу аналітики та топменеджери компанії повинні мати інструмент, який цілодобово, безперебійно й автоматизовано збирає дані з різних ресурсів, відображає ці дані, дозволяє працювати з цими даними, будувати графіки, зведені таблиці, будувати складні об’єднання та фільтри. Також система дозволяє встановлювати різні цілі (у числових конкретних показниках), і виходячи з цих цілей виникатимуть ті чи інші завдання для різних відділів компанії та позаштатних співробітників.

Складний майнінг даних

Одним із суттєвих викликів було те, що Amazon усіляко блокує можливість збору такого роду даних навіть для своїх партнерів, але надає спеціальний програмний інтерфейс для деяких даних. Цих даних недостатньо для цілей компанії.

Тому це не лише парсинг, а радше складний майнінг з обходом інтелектуальних блокувань різними засобами, це аналіз функціонування серверів Amazon, при тому що доступу до вихідного коду Amazon, природно, немає. Потрібно уявити й відновити алгоритми роботи Amazon за дуже непрямими ознаками.

GadFul EVA - система інтелектуального моніторингу маркетплейсів

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

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

Синтаксичний аналіз даних маркетплейсів

Після отримання даних усе тільки-но починається. Адже ці дані були призначені зовсім не для читання людиною. Ці дані необхідні для аналізаторів стандартних браузерів і містять 98% сміття, необхідного для коректного відображення та позиціонування їх на сторінці.

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

До вимог до алгоритмів також входила необхідність їхньої стійкості. Оскільки ще однією специфікою такого гіганта, як Amazon, є те, що він постійно “викочує” нові зміни. І якщо написати алгоритми “абияк”, вони можуть відпрацювати сьогодні, а завтра вже бути марними. Вони повинні працювати практично інтелектуально, аналізуючи отриману сировину з розміткою та даними так, як аналізує їх людина.

І навіть за професійного підходу іноді ми стикалися з необхідністю коригувати ці алгоритми. Та що там казати, іноді навіть живій розумній людині буває складно відшукати необхідні дані з огляду на всі фільтри та зонування. Хто працював, мене зрозуміє =)

Продуктивність праці

За 5 днів у систему додавалася величезна кількість коду завдяки команді розробників. Йдеться не про чернетки, а про налагоджений та оптимізований код, який відповідає складним вимогам до якості.

Спадщина старих проєктів (легасі)

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

GadFul EVA - система інтелектуального моніторингу маркетплейсів

Інфраструктура

Необхідно сказати кілька слів про інфраструктуру. Звичайно, у межах дозволеного й не секретного. Для створення інфраструктури був залучений окремий спеціаліст-архітектор і DevOps. Система деплою та доставки розгорталася з використанням платформи для оркестрації контейнерів Kubernates і сервером автоматизації Jenkins. Звичайно, був використаний Docker для цілей девелопменту й тестування, були введені дев-сервери, стейджинг і продакшн. Як система контролю версій використовувався git на базі преміум акаунта github. Сервери були налаштовані на базі Digital Ocean.

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

Мікросервісна архітектура

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

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

Виходячи з вхідних даних, нами було оскаржено це рішення на користь розробки спочатку модульної системи, системи шарів, концентрації зусиль на створенні та тестуванні виразної й нормалізованої моделі предметної області як ядра та опори системи і всього проєкту. Надалі систему можна було б розділити за контекстами й обчислити зручні “лінії” розмежування на мікросервіси. Тобто ми заперечували зручність того, що називають “microservice first”.

Однак рішення щодо мікросервісної архітектури вже було прийнято, і з огляду на те, що ми могли не знати деяких нюансів і тонкощів у подальших цілях компанії (а вивчити такий обсяг за перші консультації не було можливим), ми прийняли ідею розробки системи починаючи з мікросервісної архітектури. До команди був залучений досвідчений архітектор, завданням якого було розщепити систему на мікросервіси й проконсультувати щодо їхньої зв’язки. Архітектор з нашого боку відповідав за так звану архітектуру інтер’єру, яка була ближчою до предметної області та об’єктно-орієнтованого аналізу.

Також ми втішали себе тим, що в певному сенсі ми не робимо мікросервіси з нуля, адже в компанії вже були трохи розосереджені напрацювання програмного забезпечення у вигляді величезних алгоритмів, які додавалися до системи електронних таблиць, а також була трохи денормалізована база даних і так званий легасі код на Zend Framework (зараз це не є комерційною таємницею з огляду на заміну рішення). Пізніше з’ясувалося, що перевикористати й “відрізати” від цих напрацювань мікросервіси не було можливим. Напрацювання слугували радше прототипом, ніж перевикористовуваними підсистемами, і вже точно не могли стати мікросервісами.

GadFul EVA - система інтелектуального моніторингу маркетплейсів

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

Знову ж таки, не вийде описати в усіх деталях ключові проблеми, але загальна суть була в тому, що на стартовому етапі було неможливо точно визначити межі мікросервісів (це найскладніше завдання і зазвичай це обчислюється емпірично, шляхом спостереження). Таким чином, щоб перейти від проєктування до програмної реалізації, розділення було проведено логічним і очевидним чином, виходячи з модулів, які вимальовувалися і, можна сказати, напрошувалися, дивлячись на величезну намальовану схему системи “ЄВА”.
Але на практиці, коли почали розписуватися всі алгоритми системи, виявилося, що деякі мікросервіси мають дуже велику кількість зв’язків. Особливо в частині складних зведених таблиць зі складною фільтрацією. Таким чином вийшло так, що дуже багато алгоритмів, які бере на себе СУБД і містить їх під капотом, тепер було необхідно виносити назовні й переписувати при склеюванні даних вручну, оскільки якби ми не підтримували окремі ізольовані бази даних для кожного мікросервісу персонально - ми б порушили ідею мікросервісної архітектури як таку. Або ж дублювати схеми даних від мікросервісу до мікросервісу й отримати купу тасків на написання алгоритмів складної та нетипової синхронізації. Альтернативним варіантом було введення шини, у яку можна було помістити ключову логіку об’єднання множин, але під час підрахунків з’ясувалося, що в сумі вся ця логіка породить досить жирний центральний сервіс. Тобто найоптимальнішим рішенням було справді писати моноліт від самого початку й відрізати в мікросервіси лише необхідну та слабко залежну функціональність.

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

Мікросервісний фронтенд

Так, фронтенд ми також планували мікросервісним. І якщо щодо мікросервісного бекенду на момент старту проєкту були складені більш-менш хороші й зрозумілі практики та методології, то щодо фронтенду все було неоднозначно. Ми вивчили низку рішень, зокрема рішення, яке допомагало створювати справді ізольовані рішення на різних фреймворках у межах однієї системи. Найтоншою частиною, як і на бекенді, було перетинання функціональних елементів. У нашому випадку це глобальні компоненти, які відповідають, наприклад, за меню, леяут, фільтри (які застосовуються глобально до всіх даних, наприклад можна було перемкнутися тільки на зріз даних одного маркетплейса і\або в межах вибраного діапазону дат (і не тільки), і тоді весь застосунок, усі таблиці та графіки показуватимуть дані виключно виходячи з цих глобальних налаштувань), і таких фільтрів було на момент розробки 4, а в майбутньому це могло розширитися. Менш очевидні (технічні) глобальні функції системи, такі, наприклад, як роутинг - також було не зовсім зрозуміло - як зберігати й підтримувати. Були спроєктовані абстрактні об’єктні інтерфейси, які декларували спосіб постачання правил роутингу кожним незалежним мікросервісом.

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

Сервіс моніторингу та налаштування моніторів

Застосунок містив досить складну функціональність моніторів. Візуально один монітор - це картка, яка відображає в графічному вигляді стан певного зрізу даних. І ці картки не були задані від самого початку. Їх можна було створювати й налаштовувати принцип зрізу. Тобто бачити стан певного продукту або групи продуктів на певному маркетплейсі, їхню динаміку зміни ціни, динаміку додавання коментарів, динаміку зміни попиту, а також похідні всіх перелічених (і не згаданих) способів розглядати ситуацію на ринку. Монітор будувався на свіжих і актуальних даних та враховував глобальні фільтри, про які було вище.

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

Кастомний і гнучкий REST-like протокол

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

Наш протокол ідеально підходив саме під цю систему й був спроєктований виходячи з тих запитів, які передбачалися вже зараз - як між мікросервісами, так і клієнт-серверні запити. Що також важливо, протокол враховував деякі заплановані на майбутнє функції системи, які були спрогнозовані разом із відділом аналітики та технічним директором. Протокол враховував вищезгадані глобальні фільтри, мав гнучкість управління (наприклад, дозволяв будувати складні запити з об’єднанням множин або групуванням, що дозволяло без додаткового програмування впроваджувати нові функції на фронтенді). Унікальною можливістю протоколу був параметр запиту, який дозволяє зробити запит в один мікросервіс і скомандувати йому зробити об’єднання даних з іншим мікросервісом. Подібні винаходи були місцевими ноу-хау, оскільки подібної функціональності в готовому вигляді ми не знайшли. Важливо розуміти, що протокол був не просто ідеєю і форматом. Це була група досить хитрих алгоритмів, які забезпечували його роботу. Метою протоколу було суттєве прискорення розробки в умовах гетерогенності середовища та різноманітності форматів даних. Протокол підводив усе під єдиний знаменник і задавав дисципліну розробки, виразність архітектури, наочність програмних інтерфейсів. Звичайно, протокол був добре задокументований і само собою містив правила безпеки (такі як білі списки), які не дозволяли фронтенду та іншим мікросервісам запитувати дані, на які не було дозволу в межах авторизації.

HATEOAS

https://ru.wikipedia.org/wiki/HATEOAS

Однією зі спадщин REST протоколу було застосування гіпермедіа-запитів. Це дозволяло в межах відповіді видавати додаткові дані про запитуваний ресурс, наприклад запити, які підтримувалися в межах цього ресурсу. Це дозволяло втілювати цікаві задуми, такі як автоматизований і єдиний спосіб будувати таблиці даних і графіки, таким чином, наприклад, на фронтенді (переважно React Redux) була написана функціональність, яка не хардкодила всі дії з множиною даних, а автоматизовано виводила її виходячи з гіпермедіа. Це привело всі типові рендери даних до єдиного формату й позбавило від величезної кількості зайвого коду. Фронтендери, зрозумівши цей аспект архітектури, багато разів захоплено перепитували - “А що, так завжди можна було? Чому ми раніше так не інтегрувалися!”. І їх можна зрозуміти, адже це знімало з них багато рутини. Але ми тільки добираємося до найцікавішого…

Метадані

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

Перше, що спадало на думку, - це стандартизувати таблиці, таким чином були спроєктовані багатофункціональні поліморфні гріди. Їхня багатофункціональність полягала в тому, що вони мали функції сортування, пагінації, складної фільтрації, вивантаження, налаштування колонок, їхніх розмірів і розташування. Їхня поліморфність полягала в тому, що залежно від контексту таблиці могли відображати різні додаткові функції та фільтри - діапазони, множинні чекбокси тощо. Також таблицю було легко розширити, додавши до неї унікальні керуючі елементи, які мали сенс лише для певних наборів даних. Хоча це може здатися банальним експертам, які розробляють адміністративні інтерфейси та складні корпоративні облікові системи, для програмістів фронтенду це було справжнім подарунком, оскільки вони помітили суттєве спрощення роботи, трохи помучившись із втіленням поліморфізму в таблиці. Вони зрозуміли суть усіх пов'язаних компонентів (а аналітичний грід - це десятки співзалежних об'єктів-компонентів) і відкрили для себе поліморфізм заново.

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

Зазвичай ці правила валідації прописуються у вигляді окремих функцій на фронтенді, дублюються на бекенді, потрібно писати зайвий код, та ще й двома мовами. Трохи краще справи в ізоморфних застосунках, де, якщо все робити правильно, логіка валідації пишеться однією мовою один раз і не дублюється на бекенді та фронтенді. Однак у будь-якому разі функції валідації пишуться хардкодом. У кращому разі ці правила організовані у вигляді декларативних стейтментів, що спрощує їхнє перевикористання (наприклад при введенні даних в інпут фільтра і введенні аналогічних даних у, ніби, аналогічний інпут під час заповнення форми додавання деякого об'єкта). Ми пішли ще далі. Ми створили універсальні сховища метаданих, такі метадані кожен мікросервіс може постачати у вигляді інформації про себе. Валідація - це яскравий і наочний приклад, але також там були й інші дані, необхідні як для технічних потреб, так і для потреб фронтенду. У метаданих ми зберігали унікальні налаштування таблиці - розміри. позиціонування, положення комірок, ввели типи даних, правила валідації, деякі попередньо встановлені кондишени, а головне - ми прив'язали це до певного користувача. Що це дало? По-перше - дуже багато тонкощів можна було налаштувати без програміста і не знаючи програмування - наприклад розміри і зовнішній вигляд таблиць (і графіків теж), логіку перевірки даних, їхні типи (наприклад, якщо тип властивості множини “дата” - то під час додавання цих даних або під час використання форми фільтрів у таблиці ці дані будуть відображатися у вигляді дата-пікера, проходити валідацію на єдиний для всієї системи формат дати). Також можна було додавати кастомні правила - і теж без програмістів. Додатковою зручністю стала можливість для аналітика налаштувати таблицю з попередньо встановленим фільтром. Тобто, наприклад, Вася дивиться таблицю продуктів, відсортовану за датою, а Петі зручніше проводити аналіз у продуктах, відсортованих за алфавітом - це можна налаштувати. І одна й та сама таблиця для різних користувачів буде відповідною до його зручності.

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

У проєкті були й інші цікаві та інноваційні винаходи, але оскільки вони були розроблені або іншою командою та іншим архітектором, або спільно і без особистого авторства - ці рішення описані не будуть.

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

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

Звертайтеся до нас за детальною консультацією перед стартом проєкту - це безкоштовно та інформативно.

Потрібен веб-проєкт під ваш бізнес?

Розробляємо CRM/ERP, кабінети, B2B/B2C-сервіси та корпоративні веб-системи: від ТЗ й архітектури до запуску та підтримки.

Часті питання

Виділіть одну проблему клієнта та сформулюйте конкретну цінність рішення, яку можна виміряти у грошах і строках.
Почніть з вузького MVP для одного сегмента, заміряйте конверсію, вартість залучення та швидкість угод перед масштабуванням.
Контролюйте виручку в USD, CAC, валову маржу, конверсію в оплату та строк окупності. Це база для рішень про масштаб.
Отримати оцінку проєкту

Последние проекты

Последние комментарии

Теги

15 октября