Олександр Тарабанов, Frontend Developer в ІТ-команді NIX
Уявіть ситуацію: вам дістався код, у якому немає ані структури, ані розуміння, де й як шукати певні частини коду, куди вносити зміни. «Змучена» папка компонентів нагадує перелік слів із тлумачного словника, але без жодного визначення, що означає кожен зі складників.
Ні, це не старий проєкт, він тільки нещодавно вийшов у продакшн. Ви отримали завдання від замовника: покращити та збагатити застосунок новими фічами. Відкриваєте його, а там — і хаотично розкидані по різним дерикторіям файли, і дублікати коду, яких мали позбутися «ще вчора». Починаєте думати, як тут навести лад, гуглите… І згодом натрапляєте на описи різних методологій, які частково або повністю можуть вирішити ваші проблеми. То що ж обрати?
Перш ніж розглянути кілька популярних методологій, давайте розберемося, для чого потрібна архітектура, які переваги та недоліки вона має. Так буде простіше обрати те, що підійде саме вашому проєкту.
Переваги архітектурних методологій
Простота у використанні, розширенні та підтримці коду
З використанням того чи іншого підходу зʼявляється можливість організувати весь застосунок у вигляді окремих незалежних частин. Розробник може не турбуватися, чи впливатимуть подальші зміни у коді на роботу інших частин системи.
Додавати новий функціонал також буде простіше, адже вся команда однаково розумітиме, куди та як вносити зміни. Розробники будуть притримуватись архітектурних рішень і правил. Кожен працюватиме з логічно відокремленою, визначеною згідно обраної архітектури частиною проєкту. Наприклад, модулем, компонентом або файлом.
Повторне використання коду
Відокремлення функціоналу з використанням певної структури та правил дозволяє легко використовувати його в окремих частинах застосунку або навіть за межами проєкту.
Гарним прикладом, який можна часто зустріти, є складна таблиця з набором різних властивостей і конфігурацій, у якої є багато стилів, свої окремі змінні, інтерфейси або навіть функції для роботи із зовнішніми API. Таке відокремлення суттєво впливає на швидкість розробки, адже певний блок функціоналу може бути використаний кілька разів.
Доступність для нових членів команди
Можете зазначити, який підхід ви застосували, що є стандартом. Новому учаснику команди або вже може бути знайома логіка, або він може дослідити її, прочитавши джерела в інтернеті чи звернувшись до проєктної документації.
Полегшення тестування коду
З чіткою архітектурою зʼявляється можливість протестувати кожен модуль окремо, що робить тестування контрольованим і зменшує ризик виникнення помилок.
Масштабованість коду
Незалежні частини програми легше змінювати та розширювати без необхідності вносити зміни до всього коду. Всі учасники команди можуть бути одночасно задіяні в роботі над певною частиною застосунку, маючи мінімальну залежність один від одного.
Недоліки архітектурних методологій
Додаткові часові витрати
Створення абстракцій, додатковий код для налаштування комунікації між різними частинами системи, старт проєкту та підтримка всіх умов обраної архітектури — все це потребує чимало додаткових годин.
Складно для початківців
Junior-розробнику, скоріш за все, буде складніше влитися у проєкт, адже деякі правила, умови та обмеження можуть бути незрозумілими та неочевидними для нього.
Джунам важче розібратися зі складними концепціями. Відповідно, їм потрібно більше часу на адаптацію та онбординг у проєкті. Не виключаємо і можливі помилки на початку роботи.
Щоб досягти зазначених переваг, розробники постійно вдосконалювали структуру своїх у своїх проєктах. Згодом стало зрозуміло, що напрацювання команди з одного проєкту можна використати в іншому або поділитися ними з колегами з іншого проєкту. Так почали зʼявлятися самостійні архітектурні методології, які поступово набирали популярності й завоювали нових прихильників серед розробників.
Розібравши переваги та недоліки використання архітектурних підходів, пропоную перейти до прикладів.
Різновиди архітектурних методолій
Модульна архітектура
Одна з найбільш поширених методологій, проста у використанні. В такій архітектурі застосунок розділяють на різні рівні, де кожен має свою роль і відповідальність. Ось як це виглядає:
Розглянемо кожний елемент окремо.
Pages (Сторінки): рівень сторінок відповідає за відображення модулів, не маючи в собі бізнес-логіки. Наприклад, сторінка входу в застосунок передбачатиме відображення таких модулів, як «шапка», футер застосунку та форма входу.
Modules (Модулі): це ядро логіки застосунку. Модулі обробляють помилки, працюють з API, відповідають за бізнес-логіку, зберігають власний стан та мають свої константи чи утиліти, які використовує компонент.
Вони мають певну структуру, що реалізує концепт публічного API за допомогою індекс-файлу, що своєю чергою експортує тільки ті частини модуля, які ви зробите доступними. Це і реалізує принцип інкапсуляції, якщо провести аналогію з ООП.
Прикладами тут можуть бути форма входу в застосунок або список продуктів. Модулі працюють незалежно один від одного і не взаємодіють напряму з іншими модулями.
Components (Компоненти): це елементи, що можуть містити певну логіку, але на відміну від модулів не реалізують специфічну функціональність. Наприклад, компонент картки товару може обробляти події або відображати передані в нього дані.
UI (Компоненти інтерфейсу): рівень UI включає базові елементи інтерфейсу: кнопки, поля введення, підказки тощо. Це невеликі компоненти, які використовуються як будівельні блоки в інших частинах програми.
Можна також створювати глобальні директорії для зберігання таких загальних ресурсів, як хуки, утиліти чи константи, які можуть використовуватись по всьому застосунку. Але зверніть увагу: модулі не використовують інші модулі. Цей принцип підтримує ізоляцію та дозволяє уникати зайвих залежностей між модулями.
Переваги модульної архітектури:
- Ізоляція модулів за допомогою публічних API: кожен модуль має свій індекс-файл, який експортує лише ті функції та компоненти, які необхідні ззовні. Це знижує ризик ненавмисного втручання в логіку інших модулів.
- Повторне використання модулів: завдяки чітко визначеній структурі модулі згодяться для повторного використання в окремих частинах застосунку або в різних проєктах.
- Легкість у видаленні модулів: завдяки ізоляції можна видалити або замінити окремий модуль без значних змін у всьому застосунку.
- Гнучкість використання feature flags: модулі просто включити або відключити за допомогою feature flags, а це спрощує розгортання нових функцій.
Щодо недоліків, то маємо такі:
- Модулі не можуть напряму використовувати інші модулі. Це обмеження викликає труднощі, коли модулі потребують обміну даними або встановлення залежностей між ними.
- Складно визначити, куди помістити код: розробники можуть зіткнутися з дилемою: чи має певний функціонал належати до модуля, чи краще, щоб він залишався окремим компонентом.
- Глобальні змінні та стан: хоча цей різновид архітектури орієнтований на ізоляцію, все одно можуть існувати глобальні константи чи стан (наприклад, загальний глобальний store), які використовуються по всій програмі.
Модульну архітектуру можна застосовувати у проєктах будь-якої складності та в різноманітних за чисельністю командах.
Існує й інший підхід, складніший порівняно з модульним, але з власною документацією і навіть спільнотою. Архітектура, яку розглянемо далі, підійде як для середніх, так і для великих команд і проєктів.
Atomic Design
Методологія, розроблена для створення структурованих і масштабованих інтерфейсів. Вона заснована на ідеї, що інтерфейс можна розділити на п'ять рівнів абстракції, які відповідають природним структурним елементам дизайну. Цей підхід допомагає організувати компоненти у зрозумілій і повторно використовуваній структурі.
Atomic Design сприяє чіткості, узгодженості та масштабованості інтерфейсу. Такого принципу дотримуються в дизайні при створенні мокапів для вебзастосунків.
Також цей підхід використовують для створення бібліотек компонентів, які будуть використовувати на різних проєктах. Загалом методологія схожа на модульний підхід, про який йшлося вище, проста і зрозуміла.
Структура рівнів в архітектурі Atomic Design має такий вигляд:
Atoms (Атоми): основні, найдрібніші одиниці інтерфейсу, які не можна розділити далі. Не містять складної логіки або взаємодій і використовуються для створення більших компонентів. Атоми є базовими компонентами інтерфейсу. Наприклад, кнопка або поле вводу.
Molecules (Молекули): комбінації атомів, які працюють разом як єдиний функціональний блок. Це компоненти середнього рівня, які можуть містити просту логіку. Вони мають інкапсулювати та виконувати просту задачу. Наприклад, поле вводу з текстовим лейблом до нього.
Organisms (Організми): складніші компоненти, що складаються з молекул та атомів, утворюючи функціональні блоки інтерфейсу. На цьому рівні зазвичай присутня бізнес логіка. Організми зазвичай відповідають за значну частину UI. Наприклад, навігаційні панелі, таблиці або картки.
Templates (Шаблони): рівень шаблонів відповідає за розташування організмів на сторінці. Вони визначають структуру інтерфейсу без конкретного наповнення даними. Тобто по суті шаблони є прототипом майбутньої сторінки вашого застосунку. Саме тут визначається позиціонування функціональних блоків сторінки. Наприклад хедеру, футеру або сайдбару з навігацією.
Pages (Сторінки): цей рівень наповнює шаблони конкретним контентом. Сторінки відображають кінцевий вигляд інтерфейсу з усіма даними та стилями, які будуть відображені користувачу.
Для зберігання загальних ресурсів, конфігурації, констант можна створювати додаткові директорії на вищому рівні.
Архітектура Atomic Design має такі переваги:
- Легко зорієнтуватися в коді: чітка структура полегшують розуміння коду та навігацію по проєкту.
- Гнучкість: виходить просто додавати, видаляти або замінювати окремі частини застосунку.
- Легка підтримка: зміни в базових компонентах автоматично відображаються на всьому інтерфейсі.
- Масштабованість: сприяє масштабуванню як застосунку, так і команди розробників.
Серед недоліків:
- Орієнтованість на UI: методологія більше фокусується на інтерфейсі, а не на бізнес-логіці.
- Додаткові часові витрати: підхід вимагає додаткових витрат на створення абстракцій у вашому застосунку, таких як шаблони.
Згадані у статті методології та інші приклади, які ви можете зустріти в інтернеті, на перший погляд здаються складними тим, хто раніше не стикався з подібними рішенням для організації архітектури на проєкті. Однак опанування цих підходів неодмінно стане вам у пригоді та допоможе в рутинних задачах. А з ними точно стикається кожен розробник: це і формування структури проєкту, і правильне розташування та повторне використання коду.
Обидві розглянуті архітектури є дуже розповсюдженими та можуть часто зустрічатися у проєктах. Вони є простими у використанні, з безліччю наочних прикладів та адаптацій під потреби конкретного проєкту. Тож починаючи роботу над новим проєктом або знайшовши час на рефакторинг наявного, попіклуйтеся про майбутнє вашого коду — створіть для нього правильну архітектуру.
Редакція не несе відповідальності за інформацію, викладену у блогах. Це особиста думка автора.
Підписуйтеся на ProIT у Telegram, щоб не пропустити жодної публікації!