top of page

Архітектура на фронтенді: керування штормом, компроміси та як мігрувати 15-річний моноліт

Архітектура на фронтенді:  як мігрувати 15-річний моноліт

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


Олег Дутченко, Frontend Team Lead продуктової компанії Kasta, поділився, як адаптувати систему до цих вимог. Під час виступу на конференції AI JavaScript fwdays'26 він розповів, як його команді вдалося відокремити клієнтську частину від 15-річного бекенд-моноліту за допомогою сучасного стеку технологій. Він розповів, чому компанія відмовилася від нішевої бібліотеки TwinSpark на користь React попри тренди на AI-генерацію коду, а також про використання патерну Strangler Fig для поступового рефакторингу. Публікуємо найважливіше з виступу.


Олег Дутченко, Frontend Team Lead продуктової компанії Kasta


Вебплатформа Kasta розвивається вже понад 15 років. Історично маркетплейс був великим бекендовим монолітом, написаним на Clojure. За динаміку на вебклієнті відповідала нішева бібліотека TwinSpark.js, яка концептуально схожа на популярний HTMX. І все б працювало й далі, але минулого року компанія ухвалила стратегічне рішення: остаточно відділити фронтенд від бекенд-моноліту.


На це було три ключові причини:


  1. Кадровий голод: будувати бізнес на роки неможливо без сильної команди, а наймати амбітних розробників на застарілу, нішеву технологію ставало дедалі складніше.

  2. Стагнація технологій: оскільки бібліотека нішева, екосистема навколо неї розвивалася вкрай повільно. Ком'юніті було невеликим, а необхідний для розробки тулінг — мінімальним.

  3. Time-to-Market: швидкість доставки нових фіч почала стрімко падати. Для сфери e-commerce це не просто технічна проблема, а питання виживання бізнесу.



«Фікус-душитель»


Коли причина міграції стала зрозумілою, нам як інженерам потрібно було відповісти на два ключові запитання: що саме ми будуємо і як будемо це впроваджувати.


З першим питанням — ментальною моделлю майбутнього фронтенду — все виявилося доволі просто. У команди вже були мобільні застосунки Kasta для Android та iOS. Вони давно й успішно спілкувалися з монолітом через API. Тобто задача зводилася до того, щоб зробити ще один клієнт. 


Зрозумівши, що ми будуємо, ми перейшли до найскладнішого: як це зробити. Переписати все «з нуля», а потім в один момент просто перемкнути «рубильник» — нереально. Навіть якщо взяти купу AI-агентів, «згодувати» їм мільйони токенів і спробувати за кілька ночей переписати всю платформу, з цього нічого не вийде. Завдяки довгій історії Kasta має чимало неочевидних технічних рішень, які штучний інтелект просто не зрозуміє. Через відсутність розвиненої екосистеми та тулінгу згенерований штучним інтелектом код вимагав би колосальних ресурсів на мануальне тестування та автоматизацію. 


Тому єдиний правильний шлях — інкрементальний підхід. Для цього команда обрала архітектурний патерн Strangler Fig. Якщо англійська назва здається трохи дивною, то переклад звучить ще цікавіше — «Фікус-душитель». Цей патерн описав Мартін Фаулер на початку 2000-х років, взявши за основу аналогію з дикої природи. У тропіках існує рослина, яка обвиває дерево-господаря, поступово закриваючи всі його гілки та стовбур. З часом дерево всередині відмирає, а фікус повністю перебирає на себе його форму. Якщо перенести цю метафору в IT, ми отримуємо патерн поступової, безпечної заміни старої системи на нову.


архітектурний патерн Strangler Fig

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


Архітектура на фронтенді приклад


Муки вибору: яку технологію обрати, щоб не плодити «зоопарк»


Коли ми перейшли до вибору конкретних технологій, вибір був прагматичним і спирався на жорсткі історичні обмеження Kasta: по-перше, не створювати ще більший технологічний зоопарк, а по-друге, максимально використовувати вже існуючу експертизу команди. Оскільки у внутрішніх проєктах вже досить успішно використовувався React, вибір ядра був очевидним компромісом.


Далі потрібно було визначитися з екосистемою навколо React. Щоб уникнути суб'єктивності, ми вирішили діяти методом створення Proof of Concept. Команда зібрала вимоги від маркетингу (включно з потребами в персоналізації та тестуванні) і насетапила декілька варіантів: NextJS, React Router та навіть Astro, щоб не бути упередженими. Більш того, ми вирішили прогнати ці PoC у різних рантаймах: Node, Deno та Bun. Проте під час налаштування інструментів моніторингу Deno та Bun почали видавати помилки під час старту сервера або повертати порожні результати. Тому ці рантайми відклали. 


Щоби прийняти остаточне рішення, ми звернулися до SWOT-аналізу: прогнали кожен варіант через чотири метрики (сильні, слабкі сторони, можливості та загрози). Без особливих сюрпризів переможцем став стек NextJS + TypeScript + Node. Це далеко не ідеальний вибір (у нього є свої слабкі сторони), але переваги та можливості, які він відкривав, переважали багаторазово.


Кожне рішення важливо правильно записати. Якщо воно не задокументоване, за місяць ви забудете, чому взагалі обрали ці технології і заради чого страждаєте. Для цього використали ADR (Architecture Decision Records). Це звичайні Markdown-файли, де фіксується контекст, проблема, обране рішення та його наслідки. Неочевидний бонус сучасності: ці файли ідеально підходять для AI-агентів. Ви просто «згодовуєте» їх своєму ШІ, і він миттєво починає розуміти контекст проєкту та причину вибору конкретних бібліотек.



Lean Clean Architecture


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


Для наведення порядку ми вирішили використати концепцію Чистої архітектури (Clean Architecture). Але свідомо не брали всю методологію повністю, адже ми не створюємо fullstack-застосунок із базами даних. Зазвичай у "Чистій архітектурі" шар UI знаходиться десь скраю. Ми ж зробили його центром нашої системи, вибудувавши всередині власну гнучку архітектуру. Головне, що ми запозичили — беззаперечне правило залежностей: зв'язки між шарами мають іти завжди лише в одному напрямі.


Lean Clean Architecture

Ми адаптували цю ідею під свої потреби й отримали чотири основні шари:


  1. Сутності: фактично це просто TypeScript інтерфейси.

  2. Юзкейси: тут ми описуємо, як ці сутності формуватимуться та звідки братимуться дані (найчастіше з бекенду).

  3. Адаптери: шар, де контролери оркеструють юзкейси, маплять дані у презентери та передають їх вище.

  4. Презентація: фреймворк та UI-компоненти.


Також ми додали ще два специфічні шари, утворивши таку надбудову:


  • Інфраструктура: тут живуть наші сервіси — HTTP-клієнт, модулі перекладів, телеметрія, кеш тощо.

  • Shared: місце для глобальних констант та різних утиліт.


Всю цю конструкцію ми для себе назвали Lean Clean Architecture. 


Lean Clean Architecture структура

Вочевидь, папка shared має всі шанси згодом перетворитися на звалище коду. Ми чудово розуміли це на старті, та її створення було усвідомленим компромісом. Ідеальний світ патернів і теорій — це прекрасно, але є жорстока реальність e-commerce. Коли у вас «пожежа» перед деплоєм, коли треба терміново доставити фічу, вам потрібна проста домовленість: не знаєш, куди покласти модуль — поклади його в shared, проганяй тести, деплой і видихай. Коли ситуація стабілізується, повертайся і наводь порядок. Архітектура повинна мати гнучкість, щоб допомагати бізнесу виживати.



Перевірка реальністю: сумніви, оверхед та порятунок


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


приклад Kasta

Так виглядав типовий лейаут Kasta — за таким шаблоном побудовано майже 90% наших сторінок. Тут є багато рішень: профіль користувача, кошик, пошук, каталоги та чимало маркетингових блоків. Бекенд не може віддати всі ці дані одним махом, їх треба збирати частинами. І саме тут наша нова архітектура відпрацювала ідеально — юзкейси, адаптери та рендери.


Архітектура на фронтенді:  як мігрувати 15-річний моноліт_3

Так виглядає псевдокод нашого серверного рендеру (SSR) та адаптерів. Шар презентації просто викликає контролер і отримує готовий об'єкт (презентер) для рендеру в React.


Архітектура на фронтенді:  як мігрувати 15-річний моноліт_4

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


Але саме тоді зʼявилися перші серйозні сумніви. Під час створення простих сторінок, де бекенд віддавав готові дані для рендеру, нова архітектура здавалася гігантським оверхедом. Складні шари стали порожніми «обгортками», і виникла спокуса від них відмовитися. Проте команда вирішила не ламати систему, щоб зберегти порядок та уникнути хаосу. Ми переконалися у правильності рішення, коли вимоги бізнесу раптово змінилися. Менеджери прийшли із запитом на персоналізацію користувача, маркетинговими блоками та новими SEO-інструкціями. Буквально за один спринт «проста» сторінка стала складною. І саме в цей момент наші рішення стали зручними важелями. Кожен розробник знав, куди піти, де додати логіку отримання даних, а де — рендер, і всі працювали паралельно, не заважаючи один одному.


Цей випадок нагадав про головне: архітектура окупається не в моменті, а в перспективі, коли приходять неминучі зміни умов.



Фреймворк — це лише деталь


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


Архітектура на фронтенді:  як мігрувати 15-річний моноліт_5

Так виглядає реалізація шару інфраструктури. Деякі модулі, як-от API, ми писали самі, але для інших речей (наприклад, телеметрії) логічніше брати готові рішення з ринку, щоб не створювати велосипед. Ми створили модуль телеметрії з власними функціями та сигнатурами, під капот якого підклали Sentry. Тепер по всьому коду застосунку ми просто викликаємо умовний метод з телеметрії, який реалізує банальні get чи set. Якщо через півроку DevOps-інженери скажуть, що ми переходимо на Datadog, для нас це не буде проблемою, — ми змінимо лише «внутряк» цього модуля, а для решти застосунку не зміниться жоден рядок коду. Так само це працює і в UI-шарі. 



Canary Deployment та результати


Для міграції ми використовуємо Canary Deployment. Це підхід, за якого ми поступово «розкочуємо» нову сторінку на 5%, потім на 10%, далі на 50% аудиторії. Цей процес можна порівняти з масштабним A/B-тестуванням. Усе це щільно обкладено інструментами моніторингу: дані постійно зливаються в Sentry, Grafana та інші системи. Ми дивимося, як поводиться система: якщо бачимо проблеми — оперативно вносимо зміни; якщо все добре — збільшуємо відсоток. Наша глобальна мета — до кінця поточного року мігрувати всю вебплатформу на 100%. Бекенд має залишитися виключно API-провайдером із бізнес-логікою, а за весь UI відповідатиме новий фронтенд.


На поточний момент загальний показник Web Vitals для мігрованих сторінок становить 91. Це цілком непоганий скор, хоча ми бачимо, що метрика LCP іноді трохи просідає. Ми розуміємо причини і плануємо у третьому кварталі вийти на стабільні 95 балів загального скору.


Проте наша головна перемога — це метрика швидкості доставки фіч. Якщо до початку міграції цей процес міг займати понад місяць, то зараз ми скоротили цей час у середньому до 20 днів. Наша ціль на третій квартал — досягти показника у 7 днів. І саме це число виправдовує всі архітектурні складнощі.



Керування штормом


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

© 2035 by Business Name. Made with Wix Studio™

bottom of page