Що таке "Layered Architecture" у фронтенді?
Що таке Layered Architecture
Layered Architecture (багаторівнева архітектура) - це принцип розділення застосунку на шари, де кожен шар має свою зону відповідальності і обмежені залежності.
Іншими словами:
Кожен шар відповідає за один аспект системи, і знає тільки про шари нижче, але не вище.
Навіщо потрібні шари
Коли застосунок росте, логіка, дані та UI починають змішуватися. Шари дозволяють це структурувати:
- кожен шар вирішує своє завдання,
- взаємодія між шарами чітко визначена,
- і код стає передбачуваним і масштабованим.
Типові рівні (frontend-версія)
| Шар | Зона відповідальності | Приклад |
|---|---|---|
| UI / Presentation Layer | Відображає дані користувачу | Компоненти React, форми, кнопки |
| State / Application Layer | Керує станом застосунку і бізнес-правилами | Redux / Zustand / Hooks / Context |
| Domain Layer | Зберігає бізнес-логіку і моделі предметної області | функції на кшталт calculateDiscount(), UserEntity |
| Data / Infrastructure Layer | Працює із зовнішніми джерелами даних | REST, GraphQL, API-клієнти, LocalStorage |
Приклад (React + API)
Без шарів (все в одному компоненті)
function ProductList() {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch("/api/products")
.then(res => res.json())
.then(setProducts);
}, []);
return (
<div>
{products.map(p => (
<div key={p.id}>{p.name} - {p.price}$</div>
))}
</div>
);
}Тут компонент одночасно:
- робить запит (data layer),
- керує станом (application layer),
- відображає UI (presentation layer).
→ Архітектурна "каша".
З розділенням на шари
// data/productsApi.js
export async function getProducts() {
const res = await fetch("/api/products");
return res.json();
}
// domain/productService.js
export function calculateDiscount(product) {
return product.price * 0.9;
}
// model/useProducts.js (application/state layer)
import { useEffect, useState } from "react";
import { getProducts } from "../data/productsApi";
import { calculateDiscount } from "../domain/productService";
export function useProducts() {
const [products, setProducts] = useState([]);
useEffect(() => {
getProducts().then(res => {
setProducts(res.map(p => ({
...p,
discounted: calculateDiscount(p)
})));
});
}, []);
return products;
}
// ui/ProductList.jsx (presentation layer)
import { useProducts } from "../model/useProducts";
export function ProductList() {
const products = useProducts();
return (
<div>
{products.map(p => (
<div key={p.id}>
{p.name} - {p.discounted}$
</div>
))}
</div>
);
}Тепер кожен шар ізольований:
data/- відповідає за запитиdomain/- за бізнес-логікуmodel/- за станui/- за відображення
Правила залежності шарів
UI → Model → Domain → Data- UI знає про Model, але не про Domain напряму
- Model може звертатися до Domain і Data
- Domain - незалежний (не знає про UI чи API)
- Data - найнижчий шар, обслуговує всіх
Напрямок залежностей завжди "вниз".
Layered Architecture у Feature-Sliced Design
У FSD (Feature-Sliced Design) цей принцип формалізовано у вигляді шарів проєкту:
shared/ ← (інфраструктура і спільні модулі)
entities/ ← (доменні моделі)
features/ ← (прикладні фічі)
pages/ ← (збірка фіч у сторінки)
processes/ ← (наскрізні сценарії)
app/ ← (ініціалізація застосунку)Кожен шар залежить тільки від нижчерозташованих - наприклад,
featuresможуть використовуватиentities, але не навпаки.
Переваги Layered Architecture
| Перевага | Опис |
|---|---|
| Розділення відповідальності | Кожен шар вирішує одне завдання |
| Ізоляція змін | Можна змінювати шар, не ламаючи інші |
| Зрозуміла структура | Проєкт легко читати і масштабувати |
| Тестованість | Шари тестуються незалежно |
| Перевикористання | Можна виносити бізнес-логіку в інші проєкти |
| Сумісність з DDD/FSD | Легко інтегрується із сучасними архітектурними підходами |
Layered vs Feature-Based Architecture
| Підхід | Поділ за... | Приклад |
|---|---|---|
| Layered Architecture | Ролями (UI, Logic, Data) | ui/, domain/, data/ |
| Feature-Based Architecture | Функціональністю (auth, cart) | features/auth/, features/cart/ |
Кращий варіант - комбінувати обидва: всередині кожної фічі теж можна тримати шари (
ui/,model/,domain/,api/).
Підсумок
| Що | Опис |
|---|---|
| Ідея | Ділити застосунок на логічні рівні з чіткими залежностями |
| Основні шари | UI / Application / Domain / Data |
| Напрямок залежностей | Тільки згори вниз |
| Ціль | Структура, читабельність, масштабованість |
| У React | Часто реалізується всередині фіч (через FSD або Clean Architecture) |
Головна думка: Layered Architecture - це "архітектурний скелет" застосунку: кожен шар знає своє місце і не втручається в чужі справи.
Це робить код зрозумілим, тестованим і стійким до росту проєкту.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.