Последние несколько лет веб‑разработка вышла далеко за рамки создания «сайтов по макетам для клиентов». Огромная часть индустрии сегодня — это сложные внутренние экосистемы: ERP‑системы, CRM, админ‑панели и бэк‑офисы. Те инструменты, которые скрыты от глаз обычного пользователя, но на которых держится вся операционная работа бизнеса.

Так произошло и в моем случае. Когда я пришла в финтех‑компанию, на входе мне честно сказали:

Мы пишем бэк‑офис. Проект не публичный, массового трафика и внешней красоты не будет. Но если тебя это не смущает — задачи могут быть интересными.

В итоге решение, которое я разработала, не просто «закрыло задачи», а подтолкнуло меня к написанию этой статьи. Подход, о котором пойдет речь, решает фундаментальную проблему синхронизации фронтенда и бэкенда, высвобождает ресурсы разработки и отвечает на запрос, который актуален для любой растущей системы.

Дисклеймер: так как я задала некий тон повествованию, давайте условимся: данный лайфхак подойдет далеко не всем, но даже если вы не работаете с высокой степенью повторяемости интерфейсов, где, по сути, есть несколько типовых страниц, а в них только меняются данные, то мой опыт также вам поможет в «распиле» монолитов. По факту вы увидите наглядную демонстрацию применения Strangler Fig Pattern (удушающего паттерна), и, возможно, это поможет вам в вашем проекте.

1. Проблема

Ситуация: меня поставили на проект, который представлял собой типичную ERP‑систему. Пользователи — аналитики, бухгалтеры и менеджеры.

По смыслу они должны смотреть на разные модули, искать по ним данные, фильтровать их, вносить отчеты, изменения...

Функционал системы максимально прозаичен:

  • таблицы вывода данных с фильтрами;

  • формы создания и редактирования сущностей;

  • просмотр записей;

  • набор модалок (дублирующих те же таблицы и формы);

  • функционал формирования отчетов.

Что я увидела «под капотом»? Для каждой системы были созданы десятки «седых» папок для вывода каждого отдельного модуля — их было уже полсотни. Для каждой модели существовал стандартный набор: компоненты вывода, API‑слой, Store и «монстр‑роутер» на 2000 строк с генераторами.

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

Как выглядел процесс разработки (TTM):

  1. Менеджер придумывает фичу.

  2. Бэкенд проектирует API.

  3. Фронтенд копипастой и правками рисует интерфейс.

  4. Автоматическое (часто формальное) ревью фронта.

  5. Тесты и ревью на бэкенде.

  6. Выкатка в прод.

Процесс, мягко говоря, не быстрый. Изменение одного поля или связи требовало прохождения всей цепочки заново. В итоге типовые задачи занимали столько же времени, сколько уникальные фичи, а TTM (Time‑to‑Market) стремился в бесконечность.

Логика повторялась, страницы были типовыми, и тут мой Тимлид озвучил запрос:

Я бы хотел убрать из этой цепочки фронтенд‑разработчика почти совсем, свести его работу к минимуму. Как — я не знаю, но цель такая есть.

Я не стала предлагать переписывать всё с нуля (бизнес бы не позволил). Я применила Strangler Fig Pattern: новый движок MDUI начал «прорастать» внутри старой системы, забирая на себя одну фичу за другой.

План действий был такой:

  1. Выявить модули страниц, которые можно быстро «зашаблонить».

  2. Предложить контракт для бэкенда.

  3. Перейти к пересмотру архитектуры в сторону FSD‑like подхода.

  4. Цель: за 3 месяца показать видимый результат и продолжить его развивать при успешном релизе.

2. Разработка

После пары дней настройки проекта, анализа текущей системы и даже выполнения пары текущих задач, я составила план переезда, того самого удушения легаси, переезд в новую архитектуру.

Тут стоит сказать, что так как тимлид был очень заинтересован в таком подходе, дополнительно убеждать бэкендеров не нужно было, хотя подход «работает — не трогай» очевидно процветал.

В наличии было: Vue 3 (но без использования Composables), TS (но часто «для галочки»), Naive UI, Pinia и Vue Router. И очень много топорных шаблонов.

Я видела следующее: данных много, они тяжелые. Есть таблицы по 15 полей, много связей и вложенных структур. С чего начать?

Этап 1. Определение контракта.

За основу была взята страница уведомлений. На нее заходит не так много пользователей, она «дешевая» по времени, но наглядно демонстрирует все киллер‑фичи подхода.

Встал вопрос: как строить фронт? Отдавать всю структуру сразу или разделить на метаданные и чистые данные? Мы выбрали гибридный подход:

  1. Сначала бэкенд отдает общую структуру ERP под конкретного пользователя.

  2. Фронт запрашивает структуру (метаданные) конкретной вкладки.

  3. И только потом — получение чистых данных.

В пункте № 2 кроется причина, почему я назвала это Meta‑Driven UI, а не Server‑Driven. Рисует всё по‑прежнему фронтенд, но по строгой мета‑схеме от бэкенда.

Пример мета‑схемы:

// GET /bff/meta/users
{
  "title": "Пользователи",
  "table": {
    "columns": [
        {
            "attribute": "name",
            "label": "Имя",
            "props": { /* свойства отрисовки */},
            "renderItem": {
                "type": "tagLink", // Компонент для рендера ссылок
                "props": { /* свойства рендера */ }
            }
        },
      ]
    },
  "filter": [
      {
        "attribute": "name",
        "label": "Имя",
        "component": {
            "type": "input",
            "props": {
                "placeholder": ""
            }
        }
      },
  ],
  "_query": {
      "_with": "userRole" // Подсказка для API, какие связи подтянуть
  }
}

Что дает фронтенду такая структура:

  • Понимание, где находится пользователь (заголовок страницы и для хлебных крошек, описания).

  • Полное описание таблицы: какие колонки рисовать и как именно (текст или кастомный компонент через renderItem).

  • Состав фильтров.

  • Параметры для последующего запроса данных (какие relations нужны бэкенду).

Данная структура едина для любых моделей. Поля фильтров часто совпадают с полями в формах, а значит, бэкенд тоже может абстрагировать эти схемы у себя.

Этап 2. Реализация на фронтенде

Самый важный вопрос при внедрении MDUI: когда именно мы должны получать структуру страницы? В стандартных SPA мы привыкли, что компонент монтируется и сам идет за своими данными. Но в системе, где интерфейс диктует бэкенд, нам нужно знать, «что рисовать», еще до того, как пользователь увидит страницу.

Жизненный цикл загрузки страницы

Флоу работы нашего движка выглядит так:

  1. Navigation Guards: Пользователь переходит по ссылке. Вместо простой проверки прав, router.beforeEach делает запрос на получение метаданных страницы (BFF/Meta).

  2. RBAC на стороне бэкенда: Огромный плюс такого подхода — фронтенду больше не нужно хранить логику ролей. Если у пользователя нет доступа, бэкенд просто не отдаст мета-схему или вернет 403. Фронт в этом случае «разворачивает» пользователя на 404 или страницу логина.

  3. Кэширование в Store: Полученная структура сохраняется в Pinia. Это позволяет реализовать систему вкладок и мгновенный переход «назад» без лишних запросов к BFF.

  4. Рендеринг и данные: Когда мета-схема готова и сохранена, мы пускаем пользователя на страницу. Компонент-рендерер видит структуру и инициирует запрос к чистым данным.

Для получения данных я использовала стратегию SWR (Stale-While-Revalidate). Для реализации был взят легковесный swrv. Конечно, с дальнейшим переходом на PiniaColada.

Структура страницы (мета) обычно статична, а сами данные обновляются часто. Такой гибридный подход (Fetch для структуры + SWR для данных) позволил сделать интерфейс визуально очень быстрым: пользователь мгновенно видит каркас страницы, пока данные подгружаются в фоне.

Структура проекта

Чтобы не плодить хаос, я начала внедрять FSD-like структуру. На первом этапе (когда нужно было быстро показать результат) это выглядело как выделение общих шаблонов:

.
└── src/
    ├── app/          # Инициализация приложения
    ├── store/        # Стор
    ├── templates/    # Те самые "Мастер-шаблоны" для MDUI
    │   ├── list-page      # Шаблон для списков
    │   ├── form-page      # Шаблон для создания/редактирования
    │   └── view-page      # Шаблон для детального просмотра
    │   index.ts      # Вся структура хранится в едином файле для удобства доступа
    └── shared/       # Атомарные компоненты (UI-kit на базе Naive UI)

Магия маршрутизации: из 2000 строк в одну

Самое «вкусное» произошло с роутером. Раньше для каждой новой сущности (пользователи, счета, транзакции) приходилось описывать отдельный маршрут с импортом конкретного компонента.

Было:

export const accounts: RouteRecordRaw[] = [
  {
    path: 'users',
    name: RoutesNameEnum.USERS,
    component: () => import('@/views/Users/Users.vue'),
    meta: {
      title: 'Пользователи',
      accessScopes: [`${RESOURCE_ACCOUNT}.${ACTION_VISIT}`]
    }
  },
  // ... и так еще 50 раз для каждого модуля
]

Стало (MDUI): Мы перешли на динамические параметры. Теперь роутеру все равно, какая модель перед ним — он просто передает управление общему шаблону.

// Ниже – вполне обычная структура, не так ли?
const recordRoute: Readonly<RouteRecordRaw[]> = [
  {
    path: 'list',
    redirect: { name: 'dashboard' },
    children: [
      {
        // Это лишь пример того, как это может выглядеть. 
        // Исходно код содержит также и для зависимых путей маршруты, но не только.
        path: ':model/:id?',
        name: 'list',
        component: templates.ListPage,
        meta: {
          baseTemplate: 'Просмотр всех данных'
        },
      },
    ]
  },
  // Похожим образом описаны формы редактирования, просмотра и тд.
];

Теперь, чтобы добавить в систему новый раздел (например, «Справочник валют»), фронтенд-разработчик вообще не нужен. Бэкенд просто регистрирует новый эндпоинт в BFF, а роутер по параметру :model подхватывает нужную мета-схему и отрисовывает страницу.

Хитрый момент: :id мы используем универсально. Если он есть в URL — движок понимает, что нужно открыть форму редактирования или детальный просмотр, подставляя этот ID в фильтры или API-запросы автоматически. Причем просмотр реализуется через query, тут уж на что ваша фантазия горазда.

Самое главное было сохранить визуально предыдущую структуру и ссылки, скрыть от пользователя фильтры или другую meta-информацию.

Этап 3. Рендер "под капотом"

Здесь начинается самое интересное: как сделать систему максимально динамичной и при этом легко расширяемой? Основным инструментом стал стандартный компонент Vue 3 — <component>, предназначенный для динамической отрисовки.

Точка входа в наш движок выглядит следующим образом:

<template>
  <component :is="setComponent" class="create-base__content" />
</template>

<script setup lang="ts">
const setComponent = () => { 
  return renderComponent(
    props?.component?.type || 'input', 
    props?.component || {}, 
    value, 
    // ... пропсы и события
  );
};
</script>

Через функцию setComponent вызывается диспетчер, который по ключу из мета-схемы BFF определяет нужную стратегию отрисовки.

Диспетчер компонентов (The Registry)

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

// renderers/index.ts
export function renderComponent(type: iComponentType, ...) {
  switch (type) {
    case 'date-picker':
      return renderDatepicker({ fieldConfig, model, onUpdate });
    case 'search-select':
      return renderSearchSelect(fieldConfig, fetch, model, onUpdate);
    case 'upload':
      return renderUpload(fieldConfig, model, onUpload);
    // ...
    default:
      return baseRenderComponent(type, fieldConfig, model, onUpdate);
  }
}

Такой подход позволяет передавать для каждого компонента свой специфичный набор параметров, будь то функции загрузки файлов для upload или конфигурация поиска для search-select.

Почему Render-функции (h) лучше шаблонов в MDUI?

Резонный вопрос: «Зачем использовать h(), если есть привычные <template>?». Ответ — абсолютная гибкость.

В MDUI компоненты должны быть не просто визуальными оболочками, а «умными кирпичиками», способными на лету трансформировать данные под нужды бизнеса и API. Идеальный пример — работа с датами. Нам нужно отображать календарь в локальном формате пользователя, но отправлять на бэкенд всегда UTC.

// renderers/datepickerRenderer.ts
return h(NDatePicker, {
  ...fieldConfig.bind,
  type: fieldConfig.props.type,
  format: fnsDisplayFormat.value, // Локальный формат для юзера
  value: timestampValue.value,
  'onUpdate:value': onUpdateValue, // Авто-конвертация в UTC для бэкенда
  // ...
});

Благодаря функциям рендеринга вся эта сложная логика инкапсулирована внутри одной функции. Бэкенд просто говорит: «Хочу поле даты», а движок сам знает, как его отформатировать, валидировать и в каком виде вернуть данные в API.

Контракт и типизация

Для стабильности системы важно строго описать контракт между фронтендом и бэкендом. Я использовала TypeScript для определения типов компонентов и их пропсов, что минимизирует риск падения приложения из-за некорректных данных от BFF.

// component-renderer/entities/rendererTypes.ts

export type iComponentType = 
  | 'date-picker' | 'input' | 'select' | 'search-select' 
  | 'upload' | 'code' | 'checked-input';

export interface iBaseComponentProps {
  [key: string]: any;
}

// Пример типизации для сложного компонента даты
export interface iDatepickerConfig extends iBaseComponentProps {
  format: string;
  valueFormat: string;
  type: 'date' | 'datetime';
}

Вместо громоздких v-if/else в шаблонах, я использовала функциональный подход. Это позволяет динамически выбирать нужную функцию отрисовки для каждого типа компонента из метаданных.

// component-renderer/renderers/index.ts

export function renderComponent(
  type: iComponentType, 
  fieldConfig: iComponentPropsType, 
  model: ModelRef<string>,
  onUpdate: (v: any) => void,
  // ... остальные зависимости (fetch, upload и т.д.)
) {
  switch (type) {
    case 'date-picker':
    case 'datetime-picker':      
      return renderDatepicker(fieldConfig as iDatepickerConfig, model, onUpdate);
    case 'input':
    case 'select':
      // Базовый рендерер для простых компонентов Naive UI
      return baseRenderComponent(type, fieldConfig as iBaseComponentProps, model, onUpdate);
    ...
    default:
      console.warn(`[Component Renderer] Unknown component type: "${type}"`);
      return null; 
  }
}

Дальше можете догадаться: рендер возвращает также h(), рисуя компонент со своей логикой. Очень удобно потом менять логику, если заказчик захотел что-то поменять или изменился контракт.

Архитектура и FSD

Такой подход идеально ложится в FSD-like структуру проекта:

  • Страницы (Pages): Содержат универсальные шаблоны, которые определяют флоу работы с данными.

  • Виджеты (Widgets): Например, w-table или w-forms, которые получают структуру из Store и используют рендереры для отрисовки своих частей.

  • Фичи (Features): Сама логика рендера (component-renderer) разработана как независимая фича, доступная всей системе.

Что это дает на практике?

  1. Разделение ответственности: Фронтенд больше не тратит время на создание однотипных страниц. Работа сводится к развитию ядра системы (рендереров) и созданию сложных UI-виджетов.

  2. Скорость изменений: Если нужно изменить поведение всех текстовых инпутов в системе, достаточно поправить baseRenderComponent.ts или мапинг в formElements.ts. Логика обновится мгновенно на всех 50+ страницах проекта.

  3. Читаемость: Компоненты становятся максимально легкими, так как вся «черная работа» по интерпретации метаданных скрыта за фасадом рендерера.

Этап 4. Удушение legacy

Наглядно
Наглядно

Когда я говорила про паттерн «удушения», это не было просто красивым термином. Переход на MDUI происходил итерационно, позволяя системе эволюционировать, не прерывая поставку новых фич.

От прототипа к архитектуре

Весь процесс занял несколько месяцев. Первым «подопытным» стал модуль уведомлений. На его реализацию ушло около 3–4 двухнедельных спринтов (при наличии других задач).

  • На старте: вся структура компонентов была жестко описана на фронтенде. Мы проверяли саму концепцию рендеринга и то, насколько удобно будет бэкенду готовить такие данные.

  • В процессе: как только прототип доказал свою стабильность, мы приступили к полноценному выносу метаданных на сторону BFF (Backend for Frontend).

Планомерная экспансия

После утверждения контрактов начался масштабный переезд. Чтобы система не превратилась в «генератор пустых форм», были реализованы ключевые инфраструктурные элементы:

  1. Динамические маршруты и Navigation Guards: Мы заменили статический роутер на систему, где путь /list/:model автоматически подтягивает нужный мастер-шаблон.

  2. Система экшенов: Она была уже реализована ранее, но была доработана и также реализована как фича в новой системе. Логика рендера экшенов такая же, как и в фильтрах и таблицах. Позволило не только объединить общие логики взаимодействия с системой на всех страницах, но и реализовать специфичные действия для определенного типа страниц в проекте.

  3. Глобальные виджеты: Появились универсальные модальные окна и всплывающие уведомления, работающие по тем же принципам метаданных. Тут уж выбирайте реализацию самих модалок по себе. :)

Адаптеры и отказоустойчивость

Одной из главных проблем Metadata-Driven подхода является риск получить от бэкенда «битую» или неполную структуру. Чтобы система не падала с ошибкой в рантайме, мы внедрили слой адаптеров и валидаторов.

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

  • queryValidator: Проверяет входящие параметры запросов, предотвращая отправку некорректных данных на сервер.

  • requestAdapter: Нормализует данные из API под формат, который ожидает наш рендерер. Это позволяет фронтенду оставаться независимым от изменений в структурах БД.

  • filterQueryAdapter: Отвечает за преобразование сложных фильтров бэкенда в понятные для UI-компонентов состояния.

Итоги

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

Что мы получили в цифрах и фактах:

  • TTM сократился в 6–7 раз. Если раньше на создание типового модуля уходило несколько дней из-за необходимости синхронной работы фронта и бэка, то теперь бэкенд-разработчик разворачивает новую страницу за 15-20 минут.

  • Бэкенд-автономия. Коллеги из смежного отдела теперь могут самостоятельно изменять интерфейсы и добавлять фичи, не дожидаясь ресурсов фронтенда. Моя помощь требуется только тогда, когда нужна специфическая бизнес-логика или совершенно новый компонент отрисовки.

  • Смерть копипасты. Мы больше не плодим «раздутые папки» с одинаковыми Store и API-слоями. Весь проект держится на переиспользуемых «умных компонентах» — рендерерах.

  • Массовые исправления. Если в интерфейсе находится баг, он правится в одном месте (в соответствующем рендерере или хелпере) и исправление мгновенно раскатывается на все 50+ страниц системы.

Как изменилась роль фронтенда?

Самое важное изменение произошло в самой сути моей работы. Я больше не поставщик бесконечных однотипных форм. Теперь то, чем я занимаюсь, по большей части является инженерией в чистом виде.

  • Вместо верстки страниц я проектирую адаптеры и валидаторы, которые страхуют систему от некорректных данных.

  • Вместо настройки роутов я создаю сложные рендереры, способные обрабатывать динамические запросы и трансформации данных на лету.

Для бизнеса это обернулось колоссальной экономией «человекочасов». Проект стал развиваться кратно быстрее, а фронтенд‑разработчик превратился в архитектора, создающего инструменты для всей команды.

Легаси успешно «задушено», и его полное выпиливание из проекта — лишь вопрос времени и планового рефакторинга.

Да, я все еще буду заниматься разработкой отдельных фич, компонентов и других бизнес‑задач. Да, я буду заниматься оптимизацией и ускорением текущего проекта. Но даже так, это куда более интересная работа, чем можно себе представить. :-)

Комментарии (12)


  1. olku
    26.12.2025 07:24

    Вы сделали свой React Admin. Скаффолд фреймворков довольно много, они приходят и уходят когда пользователям перестает хватать шаблонов грида и формы. С улучшением эргономики растет степень кастомизации. Но для быстрого прототипирования когда у пользователя нет голоса, самое оно


    1. ghaechka Автор
      26.12.2025 07:24

      Согласна, что с React Admin есть схожесть, паттерн может вполне его напоминать, хотя под капотом описан собственный движок, а не сторонняя библиотека.

      В отличие от готовых скаффолдов, наше решение не завязано на ограничениях стороннего фреймворка. Если нам перестанет хватать стандартного грида, я добавлю специфичные кейсы в рендерер, а бэк начнет использовать их в контракте. Бэк сам определяет состав формы, фронт занимается только рендером.

      Вопросы кастомизации решаются slot-based подходом. Более того, компоненты можно настраивать пропсами прямо с бэка.

      Про «пользовательский опыт» — всё проще: бухгалтерам важна предсказуемость и скорость, так что жесткая унификация здесь только в плюс.

      Спасибо за комментарий!


  1. themen2
    26.12.2025 07:24

    Напишите что там будет с этим кодом через полгода или год, если там будете ещё работать;). По опыту разбора json для управления ui на фронте, через некоторое время это становится не поддерживаемым месивом, в которое не хочется заглядывать..

    Там проблема в том ,что этот кастрмный json язык потом все обрастает и обрастает атрибутами и правилами и начинает плохо умещаться в изначальную концепцию - привет месиво...


    1. ghaechka Автор
      26.12.2025 07:24

      Справедливое замечание, я видела подобные проекты.

      но вот в чем суть. Этот проект строится на строгом разделении ответственности. Бэк передает только бизнес сущности, фронт инкапсулирует сложность реализации.

      Плюс тимлид бэка тоже понимает риски и старается не раздувать структуру на бэке, когда мы с ним согласуем контракты.

      За полгода «обрастания» не произошло. Если будет какая-то сложная логика - никто не пытается натягивать сову на глобус, просто рисуем нужное поведение.


      1. themen2
        26.12.2025 07:24

        Ну, если схема не будет расти, то может оно и норм будет... В любом случае интересно куда эволюционирует код через год активного внедрения фич


  1. Atorian
    26.12.2025 07:24

    С незапамтных времен бэк отдавал фрон простым html и все были счастливы. Потом пришли дети с реакт и все свихнулись. Используйте htmx и будете счастливы. Не считая того что "бизнес сущность" это не про json...


    1. ghaechka Автор
      26.12.2025 07:24

      «Дети с реакт»… кхм, даже интересно, в какую именно касту вы меня записали :)

      По существу: HTMX — это лишь инструмент транспорта HTML через AJAX. Он не решает проблему сложной реактивности и состояния на клиенте (валидация на лету, зависимости полей, маски, работа с модалками без перезагрузки контекста). Для ERP-систем это критично.

      Что до «бизнес-сущностей»: согласна, что карта — не есть территория. Однако в описанном подходе MDUI, JSON предоставляет проекцию правил сущности на UI: какие поля доступны, какие readonly, какие действия разрешены. В контексте задачи — это спор о семантике, не более.

      Ну и главное. Возврат HTML (пусть даже через HTMX) означает, что нам снова придется верстать каждую страницу руками, просто теперь на стороне бэкенда (шаблонизаторы). А цель моей архитектуры была ровно обратной — уйти от ручного создания страниц к их генерации из структур данных. Бэкендеру проще отдать JSON, чем верстать <div> с классами.


      1. Atorian
        26.12.2025 07:24

        htmx - это не просто транспорт. Это перенос стейта на бэк, где ему и положено быть. А это очень сильно все упрощает. Да придется чуть больше рутов добавить, но это проще чем решать решать проблему со стейтом на фронте. Simple != Easy.
        Там где нужно посыпать UI сахарком, можно добавить alpine.js или вообще обойтись CSS. А так-то все он решает, было бы желание покопать вглубь.

        Идея то у Вас правильная. Страницы не должны быть захардкожены. Но решение очень спорное.

        Это дополнительный слой, лишняя абстракция, которая только усложняет разработку. Скорее всего еще и не задокументированная. Этот конфиг должел Знания об этой поделке не переносятся на другие проекты. Просто лишняя сложность из ничего.

        Раз уж критикую - буду предлагать. Есть проверенное решение - Микрофронты с виджетами. У каждого микрофронта свой бэк с htmx + alpine. Весь стейт и правила доступа там. Реактивность - через shell app.

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

        Никаких больших JSON, старые добрые проверенные технологии. И да все ваши бэк девелоперы могут и сами собрать работающий html и даже фронт за вас делать. Вам останется только предложить им коллекцию примеров(не компонентов) как это делать. Дизайн гайд бук, так сказать. И помочь где они застрянут. Ваша роль трансформируется в ментора по фронту, а их - в фулстеков. Те кто так сделают - получат отличный буст к мотивации.

        Польза от ваших активностей с JSON может быть в другом. Можно преобразовать эти JSON-ы в приемочные тесты.


        1. ghaechka Автор
          26.12.2025 07:24

          Давайте пойдем с конца, так как это фундамент.

          1. Про мотивацию бэкендеров

          Ваша гипотеза про «буст мотивации» разбивается о реальность. Мой опыт (в компаниях от 50 до 1000 человек) показывает обратное: современные бэкендеры (даже PHP-разработчики, которые исторически ближе к вебу) не хотят заниматься фронтендом — ни версткой, ни UX, ни изучением специфики браузеров.

          В данном кейсе вводная от Тимлида (самого бэкендера) была жесткой: «Мы НЕ хотим писать фронт». Превращать профильных специалистов в фуллстаков поневоле — это прямой путь к выгоранию команды и потере качества на обеих сторонах.

          2. Инфраструктура и стоимость

          Вы предлагаете вместо JSON-контракта (который мы внедрили силами 1 фронта и 1 тимлида) развернуть оркестрацию Микрофронтендов. То есть задействовать DevOps, перестроить CI/CD и переучить всю команду?

          Это колоссальный оверхед ради того, чтобы получить разрозненную логику на Alpine.js без нормальной типизации.

          Для сравнения: онбординг PHP-разработчика в мою структуру JSON занимает 10 минут. Это прозрачный, типизированный контракт, который сразу дает результат.

          3. UX и State на бэке

          Мы строим ERP, аналог 1С. Пользователи требуют мгновенной отзывчивости, сравнимой с Excel.

          Гонять стейт (валидацию, зависимые поля, калькуляцию в таблицах) через сеть на бэкенд — это проигрыш в отзывчивости. Сетевой лаг на каждом клике в высоконагруженном интерфейсе недопустим.

          Есть такое подозрение, что у вас есть убеждение, что фронтенд — это просто «формочки». Но современный фронтенд — это полноценное приложение, работающее в среде браузера (сродни разработке под iOS/Android).

          Вы же не станете предлагать переносить логику рендера нативного мобильного приложения на бэкенд, чтобы оно просто отображало картинки? Здесь то же самое. Мы управляем сложным состоянием клиента, и JSON здесь — это идеальный протокол генерации структуры этого приложения.

          К сожалению, ваши аргументы для меня не просто не убедительны, а скорее маркер того, что в текущей системе все сделано верно и стоит развивать ее, а не пытаться делить ресурсы команды и обучать всех - всему.


          1. Atorian
            26.12.2025 07:24

            1. Про мотивацию бэкендеров

            Ваш опыт это лично ваш опыт в нескольких компаниях - это ошибка выжившего. Вы стали его заложником и не видите проблемы в классической модели управления с распределением ответственности в IT. Не осуждаю, чтобы понять в чем проблема надо целенаправленно интересоваться управлением проектов.

            Это не проблема современных бэкендеров - это проблема индутрии, которая говорит им: "у нас тут дети Реакт, зовут себя фронтендерами - они делают фронт". Конечно никакой мотивации у людей не будет. Так что проблема не в них. Они в первую очередь разработчики. И отлично со всем разберутся.

            Немножко спекуляции - возможно ваш Тимлид имел ввиду, что они не будут лезть в очередную дурно пахнущую кастрюлю с "UI Framework" лапшой. И тут он абсолютно прав. Нет никакого смысла там ковыряться и что-то чинить, да еще и выслушивать от "фронтендеров" что-то. Проще выбросить обычно.

            Средства современного CSS позволяют с минимальными усилиями создавать качесственные интерфейсы. Нет уже той проблемы, что была 10-15 лет назад.

            2. Инфраструктура и стоимость

            Надо считать не 1 день внедрения, а все часы затупов и поиска багов которые последуют после этого. Что там с документацией? Вы сделали себя ботлнеком для этого решения. Теперь если вдруг что-то новое добавится, а вы будете в отпуске - все будут страдать. Новый валидатор не напишется или еще что.

            Между монолитом и Микрофронтами есть достаточно решений не требующих больших изменений. Но то что вы это упомянули говорит о качестве процессов в вашей организации. Не мудрено что вы выбрали JSON боль. Сочувствую.

            Изменения которые в долгосрочной перспективе упрощают работу гораздо важнее сиюминутной метрики. Разве что у вас там где-то бонус привязан?

            3. UX и State на бэке


            Да хоть космический корабль. Я писал что где надо - делается виджет на любимом фреймворке.

            Есть такое подозрение

            Есть встречные подозрения.

            Ваш "Современный фронтенд" - это Теория оправдания системы в действии. Он сложен только по тому что "Дети" не думают, а берут самую сладкую конфету, а не брокколи. Они не видят картину целиком, где на самом деле границы ответственности, и не стараются делать проще. Типичный карго-культ.

            В мобильном приложении конечно существуют ограничения платформы. Вот только там еще есть web-view, который сам покажет картинки с нужной странички. Если уж сильно захотеть - можно дать самому приложению доступ к базе и убрать все прослойки. Есть еще интересные варианты.

            Удачи с развитием поделки. Искренне желаю чтобы у вас все получилось и вас за это не наказали в итоге.


  1. Lucifurry
    26.12.2025 07:24

    Назвать решение МдэЮаем это сильно, конечно)