Бизнес-логика на frontend, backend и в БД

Где должна жить бизнес-логика. В традиционных приложениях — в трёх местах сразу (дублирование), что плохо. В Metarhia — в одном domain layer, исполняемом в любом контексте.

Три классических места

  1. В БД — stored procedures, triggers (Oracle PL/SQL, Postgres functions).
  2. На сервере — services/controllers (NestJS, Django, Spring).
  3. На клиенте — validation, optimistic updates, derived state.

Боль: одна и та же бизнес-правило часто дублируется во всех трёх. «Возраст пользователя должен быть > 18» — проверяется на фронте (UX), на бэке (безопасность), в БД (constraint).

Боль дублирования

  • Изменилось правило → надо менять в трёх местах.
  • Какая-то из трёх копий устарела → расхождение.
  • Тесты надо писать для каждой копии.
  • Бизнес-аналитик не знает, где истинное определение.

Подход Metarhia

Domain layer — единственное место правды:

domain/
  rules/
    user.js          # все правила про user
    order.js         # все правила про order

Этот код исполняется:

  • На клиенте (для UX-валидации и optimistic update).
  • На сервере (для безопасности и persistence).
  • Опционально транспортится в БД (если хочется constraint).

Как «деплоить» domain код везде

  • Сервер — Impress подгружает domain/ в sandbox.
  • Клиент — тот же файл собирается в бандл (или импортируется как ES-модуль).
  • БД — постгрес позволяет stored functions на V8/JS (plv8), туда можно прокинуть домен.

Local-first как радикализация

В local-first схема:

  • Domain-код только на клиенте.
  • Сервер — sync-точка, не обработчик бизнес-логики.
  • БД — storage, без логики.

Это уменьшает сложность до одного места.

Пример: проверка возраста

// domain/rules/user.js (общий код)
const isAdult = (user) => user.age >= 18;

// applications/api/v1/register.js (бэкенд)
const isAdult = require('../../domain/rules/user').isAdult;
module.exports = async (args) => {
  if (!isAdult(args)) throw new Error('Too young');
  // ...
};

// UI на клиенте
import { isAdult } from '@/domain/rules/user';
const btnEnabled = isAdult(formData);

Цитата

«Frontend application и backend application пишутся на одном языке. В Node это один из первых таких платформ, в которых совместили веб-сервер с бизнес-логикой в одну хрень.»

Что в этом нового

Чисто Node.js так умел давно (одинаковый JS на клиенте и сервере). Что добавляет Metarhia:

  • Transport-agnostic API → код не привязан к HTTP.
  • Sandbox → клиентский код безопасно исполняется на сервере.
  • Schema → единая валидация сверху до низу.
  • Local-first → domain становится primary executor.

🎓 Источники

См. также