Чистая архитектура во фронтенде

Что такое чистая архитектура, чем она полезна и как ей пользоваться во фронтенде

Привет! 👋

Меня зовут Саша, я разработчик в DRIVE2.

Веду технический блог, пишу книги о разработке. Сегодня расскажу о чистой архитектуре и как её можно применять во фронтенде.

System Design

Designing is fundamentally about taking things apart... in such a way that they can be put back together. ...Separating things into things that can be composed that's what design is.

Rich Hickey Design. Composition and Performance

Чистая архитектура

Ответственности и функциональность разделены на три слоя: домен, прикладной и адаптеров

Правило зависимостей

Только внешние слои могут зависеть от внутренних, не наоборот

Преимущества

Издержки

Способы уменьшить издержки

Самое главное:

Лайв-дизайн!

Пример приложения — онлайн-магазин печенек Из корзины можно будет сделать заказ

С его начать?..

Пустая схема со слоями и разделением на UI и инфраструктуру

Домен

В домене будут находиться сущности пользователя, товара, корзины и заказа, а так же код для обработки их данных

Прикладной слой

В прикладном слое описываем пользовательские сценарии типа покупки, аутентификации и т.д.

Слой адаптеров

В слое адаптеров находятся модули, которые связывают приложение с внешним миром

Тип пользователя

Доменный тип пользователя
export type UserName = string;
export type User = {
    id: UniqueId;
    name: UserName;
    email: Email;
    preferences: Ingredient[];
    allergies: Ingredient[];
};

Товар и корзина

Доменный тип продукта Доменный тип корзины
export type ProductTitle = string;
export type Product = {
  id: UniqueId;
  title: ProductTitle;
  price: PriceCents;
  toppings: Ingredient[];
};
export type Cart = {
  products: Product[];
};

Тип заказа

Доменный тип заказа
export type OrderStatus =
    "new" | "delivery" | "completed";
export type Order = {
    user: UniqueId;
    products: Product[];
    created: DateTimeString;
    status: OrderStatus;
    total: PriceCents;
};

Смотрим, работает ли

Взаимодействие доменны типов

Подумаем над преобразованием данных

Shared Kernel

type Email = string;
type UniqueId = string;
type DateTimeString = string;
type PriceCents = number;
        

Проектируем сценарий покупки

В прикладном слое описываем пользовательские сценарии типа покупки, аутентификации и т.д.

«Нечистый» контекст для чистых функций

Нечистые функции вызывают чистые, а не наоборот

Сценарий покупки

type OrderProducts = (user: User, cart: Cart)
    => Promise<void>

Порты во внешний мир

Проверим сценарий

Сценарий работает так, как мы заявляли ранее

Закладываем фундамент адаптеров

Как теперь работает приложение

Пользователь общается с приложением через порты-спецификации, само приложение общается с внешними сервисами тоже через порты; сценарий описан отдельно, обособлено, все бизнес-правила собраны в домене

Feature Slice

Программный компонент — как кусок гексагонального пирога

А как же ООП?

Сгенерированное дерево как результат приложения, написанного с использование ЧА и ООП

Список литературы

Саша Беспоясов 👋