BetaДокументация для beta‑теста, возможны ошибки и неточности.
Перейти к содержимому

WARNING

Эта статья сгенерирована AI и требует ручной доработки.

FEOD для бэкенда и BFF ​

FEOD можно применять не только во фронтенде. Для BFF и серверных приложений подход полезен тем же самым: структура предсказуема, правила импорта понятны, масштабирование не превращает проект в хаос.

Ниже — минимальная, но достаточная модель уровней и правил для бэкенда.

Базовые уровни ​

  • app: bootstrap приложения, интеграции, конфигурации, точка входа.
  • routes: маршруты (часто file-based routing).
  • middlewares: middleware уровня приложения.
  • modules: бизнес-логика и доменные модули.
  • global: сущности без импорта (типы, полифиллы, расширения интерфейсов).

Направление импорта ​

Главный принцип остаётся тем же: верхние уровни знают о нижних, но не наоборот.

app -> (routes | middlewares) -> modules
global не импортируется

Дополнительно:

  • routes и middlewares не импортируют друг друга.
  • модули импортируются только через index.ts.
  • внутренние файлы модуля не импортируются извне.

Пример структуры ​

text
src/
  app/
    entry.ts
    integrations/
      db.ts
  routes/
    users/
      [id].ts
  modules/
    Users/
      index.ts

Показана только загрузка пользователя. app/integrations/db.ts предоставляет настроенную функцию чтения из БД; серверный фреймворк передаёт обработчику id из URL.

ts
// modules/Users/index.ts
export interface User {
  id: string
  name: string
  email: string
}

export function createUsers(loadUser: (id: string) => Promise<User | null>) {
  return { getById: loadUser }
}
ts
// routes/users/[id].ts
import type { createUsers } from '@/modules/Users'

export function createGetUser(users: ReturnType<typeof createUsers>) {
  return async (id: string): Promise<Response> => {
    const user = await users.getById(id)
    if (!user) return Response.json({ error: 'Пользователь не найден' }, { status: 404 })
    return Response.json({ id: user.id, displayName: user.name })
  }
}
ts
// app/entry.ts
import { createUsers } from '@/modules/Users'
import { createGetUser } from '@/routes/users/[id]'
import { loadUser } from './integrations/db'

export const getUser = createGetUser(createUsers(loadUser))

Обработчик преобразует доменный User в DTO без email. Чтение из БД остаётся зависимостью модуля; routes не импортирует инфраструктуру app. Аутентификация и обработка ошибок сервера здесь опущены. Это фрагмент адаптации запроса, а не готовый сервер.

Как это выглядит в BFF ​

BFF часто строится вокруг маршрутов и адаптации данных для фронтенда. FEOD помогает держать границы:

  • routes: только адаптация запроса/ответа, маппинг DTO, валидация.
  • modules: бизнес-логика, доступ к данным, доменные правила.
  • middlewares: авторизация, трассировка, логирование.
  • app: сборка всего вместе, подключение инфраструктуры.

Такой подход позволяет легко менять реализацию внутри модуля, не ломая маршруты.

Когда выделять подмодуль ​

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

modules/
  Billing/
    modules/
      Invoices/
        index.ts
      Payments/
        index.ts

Подмодули имеют те же правила: собственный index.ts, изоляция, отсутствие глубоких импортов. Если маршрут выставляет счёт, он обращается к API Billing:

ts
// modules/Billing/index.ts
export { createInvoice } from './modules/Invoices'
ts
// routes/invoices/create.ts
import { createInvoice } from '@/modules/Billing'

Реализация createInvoice остаётся в Invoices; этот фрагмент показывает границу импорта, а не платёжный процесс.

Где держать типы ​

  • Если типы используются внутри одного модуля — остаются в модуле.
  • Если типы нужны без импорта по всему проекту — в global.
  • Если типы универсальные, но с импортом — можно вынести в отдельный модуль (например, SharedTypes).

Итог ​

FEOD для бэкенда сохраняет ключевые свойства методологии:

  • чёткие уровни;
  • ограничение связности;
  • предсказуемая структура;
  • возможность роста без пересмотра уровней.

Это особенно полезно в BFF, где важно быстро ориентироваться в проекте и не допускать сквозных зависимостей между маршрутизацией и доменной логикой.