Архітектури сучасних фронтенд-додатків

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

pic

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

  • Модульна взаємодія: Ефективна комунікація та взаємодія між різними модулями/компонентами додатку (з використанням компонентної архітектури, повторно використовуваного коду).
  • Покращена навігація проектом: Структурування проекту таким чином, щоб його було легко навігувати та підтримувати (чітка ієрархія папок, правила найменування, розділення обов'язків).
  • Розділення бізнес-логіки від компонентів UI: Розділення бізнес-логіки (отримання даних, управління станом) від компонентів UI для покращення підтримуваності та повторного використання (наприклад, використання сервісів чи сховищ, таких як Redux, Context API).
  • DRY: Не повторюватися.
  • DAC: Розділяй і володарюй.

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

pic

Ідеальний результат — діаграма

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

Класична архітектура (без архітектури)

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

pic

Занадто багато компонентів (приклад)

У цьому прикладі є 3 сторінки, які явно не перевантажені. Однак на цих сторінках можуть бути всі компоненти, що наведені нижче. Якщо ми подивимося на ці компоненти, то побачимо справжній “хаос” 🤯: кожен компонент активно використовує інші, створюючи залежності між ними. Це ускладнює масштабування і повторне використання.

Ось інший приклад із використанням Redux менеджера стану:

pic

Розкидана логіка додатку — менеджер стану Redux (приклад)

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

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

pic

Руйнівне розділення — діаграма (приклад)

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

  • Мала команда (1–2 розробники)
  • MVP проект
  • Проект, що не передбачає довготривалої підтримки
  • Навчальний проект або шаблони

Модульна архітектура

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

pic

Модульна архітектура — структура шарів (приклад)

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

pic

Модульна архітектура — модуль та публічний API (приклад)

Як ми вже згадували, кожен модуль має свою область відповідальності. Також важливо зазначити, що кожен модуль повинен мати свій власний публічний API (index.ts файл), який інкапсулює всю внутрішню логіку модуля і надає тільки те, що потрібно ззовні. (Це дуже схоже на принципи ООП: коли клас має багато приватних методів, до яких не можна звернутися ззовні, але вони можуть використовуватися всередині самого класу). Що стосується сторінок, то тут все досить просто: в ідеалі вони повинні бути лише інкапсуляцією модулів і компонентів, а вся бізнес-логіка додатку повинна розміщуватися на рівні модулів і компонентів.

(⚠️) ВАЖЛИВО: модуль не повинен використовувати інший модуль, а компонент не повинен містити складної логіки.
Якщо логіка все ж необхідна, вона повинна бути якомога простішою і легко підтримуваною, в іншому випадку — це вже модуль!

Подивіться на наступну діаграму:

pic

Майже ідеальний результат — діаграма (приклад)

Є одне "але..." — ми все ще маємо глобальні директорії, такі як components/ і ui/, які можуть бути перевантажені. У деяких випадках логіка може розростатися, і вже не завжди зрозуміло, що є компонентом, а що є модулем. Крім того, часто спостерігається, що в міру зростання додатку розробники починають використовувати модулі в межах інших модулів, що порушує принципи цієї архітектури і викликає зайві залежності. Однак наша архітектура забезпечує:

  • Однонитковість (Single-threading)
  • Можливість повторного використання компонентів на різних шарах
  • Майже ідеальне шарування
  • Інкапсуляція

Архітектура Feature Sliced Design (FSD)

pic

Огляд — https://feature-sliced.design/

Архітектура Feature Sliced Design (FSD) — дуже схожа на модульну архітектуру, але вона також уникає того самого "але...", про яке ми говорили вище. Цей підхід структурує проект за функціональними областями (фічами), а не просто за шарами. Такий спосіб організації допомагає уникнути зростання глобальних директорій (як-от components, UI в модульній архітектурі) і забезпечує чітке розділення відповідальності між компонентами, модулями та шарами.

pic

FSD — приклад шарів

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

  • Сторінки — найвищий рівень містить сторінки, які відображаються в додатку.
  • Процеси — застаріло в цій архітектурі, тому можемо пропустити.
  • Фічі/Віджети — нижче сторінок розташовані основні фічі, які структуризують основну функціональність сторінки, роблячи її керованою і незалежною.
  • Сутності — нижче модулів фіч знаходяться сутності, які складаються з простіших UI компонентів, доступних у шарі “Shared”._
  • Shared — нижній шар містить загальні UI компоненти, доступні для використання в різних частинах додатку.

(⚠️) ВАЖЛИВО: як і у випадку з модульною архітектурою, шари не перевантажують один одного.

pic

Огляд (слайсів/сегментів) — https://feature-sliced.design/

Архітектура FSD має модульні елементи, відомі як “слайси” та “сегменти”. “Слайси” відносяться до модулів у кожному шарі, кожен з яких представляє окрему бізнес-область. Водночас “сегменти” охоплюють різні структурні компоненти, такі як api/, components/, config/, constants/ та інші, організовуючи архітектуру у більш чіткі, керовані частини.

Нарешті, ми досягли бажаного результату:

pic

Ідеальний результат — діаграма (приклад)

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

  • Чітку структуру
  • Чітко визначене шарування
  • Гнучкі компоненти
  • Незалежні модулі
  • Збалансовану повторне використання

До речі, ця архітектура пропагує використання “kebab case” при найменуванні файлів 👀

product-description.vue / shopping-cart.tsx / get-base-url.ts / тощо.

Приклади використання "Модульної архітектури":

Приклади використання "Архітектури FSD":

Висновки

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

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

pic

Webstack 2025

Перекладено з: Architectures of modern Front-end applications

Leave a Reply

Your email address will not be published. Required fields are marked *