В современной разработке программного обеспечения есть распространенная болезнь, которую опытные архитекторы называют «ловушкой тяжелого стека». Представь классическую ситуацию: стартап или инновационная лаборатория крупной компании решает запустить сложный цифровой продукт. В проекте запланировано полтора десятка сложных сценариев: цифровые профили, расчет роялти, каталоги аренды, интеграции со спонсорами и аналитика.
Как обычно начинается такой проект? Команда садится и три месяца настраивает инфраструктуру: поднимает кластер Kubernetes, конфигурирует PostgreSQL, подключает Prisma ORM, настраивает Redux Toolkit, спорит о выборе UI-библиотеки и отлаживает пайплайны CI/CD. Проходит полгода, потрачены миллионы рублей бюджета, а конечный инвестор или заказчик все еще не может кликнуть по работающему прототипу.
Разработчик спортивной экосистемы «Цифровой аватар спортсмена» (ЦАС) в подробном материале на Хабре показал радикальный инженерный контрпример: полнофункциональный демонстрационный контур из 14 независимых модулей, полностью написанный всего на 3000 строк чистого Vanilla JavaScript без сторонних npm-зависимостей, фреймворков и бэкенда.
Архитектура 14 функциональных модулей без сервера
Главной целью проекта была мгновенная валидация сложной продуктовой и экономической модели перед спортивными федерациями и спонсорами. Вместо того чтобы рассказывать об архитектуре на слайдах в PowerPoint, автор создал интерактивный стенд, где каждое утверждение бизнес-логики проверяется за пару кликов прямо в браузере.
Система охватывает полный жизненный цикл цифрового актива спортсмена:
- Паспорт аватара: верификация статуса, история спортивных достижений, антропометрические показатели.
- Методическое ядро тренера: формализация авторских методик тренировок в виде графов упражнений.
- Каталог субаренды и каскадный граф роялти: сдача методик в аренду другим клубам с автоматическим расщеплением платежей между тренером, атлетом и клубом.
- ИИ-коучинг: эмуляция адаптации тренировочного плана на основе параметров утомления.
- Кабинеты спонсора и федерации: аудит целевого расходования грантов, контракты и реестры спортсменов.
Все эти 14 модулей открываются в виде единого SPA-приложения со статической флешки или через GitHub Pages.
11 осознанных архитектурных и правовых ограничений
Секрет компактности кодовой базы кроется не в магии сжатия кода, а в том, от чего разработчик осознанно отказался:
- Никаких персональных данных (ПДн): в системе нет фамилий, паспортных данных или телефонов. Все сущности оперируют деперсонализированными идентификаторами (
ath-01,meth-99). Это позволило полностью снять юридические требования 152-ФЗ и GDPR на этапе прототипирования. - Никакого бэкенда и баз данных: все состояние живет в оперативной памяти браузера (
in-memory store) с возможностью быстрого сброса или сохранения снапшота вlocalStorage. - Отказ от фреймворков (React, Vue, Svelte): отсутствие Virtual DOM, Babel и сотен мегабайтов
node_modulesсделало код прозрачным для сквозного аудита. - Чистый CSS Grid и Flexbox: отказ от Tailwind и сторонних UI-китов избавил проект от этапа сборки.
Реактивность на нативных примитивах: EventTarget и CustomEvent
Как управлять состоянием 14 экранов без Redux или Pinia? Разработчик использовал нативный браузерный класс EventTarget, реализовав реактивный Event Bus буквально в тридцать строк кода:
// core-store.js: минималистичный реактивный стор без зависимостей
class AthleteStore extends EventTarget {
constructor() {
super();
this.state = {
athlete: { id: 'ath-01', level: 'Pro', fatigue: 12 },
methodology: { id: 'meth-99', royaltyRate: 0.15, activeRentals: 4 },
wallet: { balance: 142000, currency: 'RUB' }
};
}
getState() {
return this.state;
}
dispatchAction(action, payload) {
switch (action) {
case 'RENT_METHODOLOGY':
this.state.methodology.activeRentals += 1;
this.state.wallet.balance += 25000 * (1 - this.state.methodology.royaltyRate);
break;
case 'UPDATE_FATIGUE':
this.state.athlete.fatigue = payload;
break;
}
// Оповещение подписчиков через нативный CustomEvent
this.dispatchEvent(new CustomEvent('stateChanged', { detail: this.state }));
}
}
export const store = new AthleteStore();
Компоненты пользовательского интерфейса просто подписываются на событие stateChanged и обновляют свои DOM-деревья через нативные шаблонные строки:
// ui-renderer.js: реактивное обновление экрана роялти
import { store } from './core-store.js';
function renderRoyaltyDashboard() {
const container = document.getElementById('royalty-view');
const state = store.getState();
container.innerHTML = `
<div class="card">
<h3>Баланс выплат: ${state.wallet.balance.toLocaleString('ru-RU')} ₽</h3>
<p>Активных аренд методик: ${state.methodology.activeRentals}</p>
<button id="btn-rent" class="btn-primary">Симулировать аренду (+25 000 ₽)</button>
</div>
`;
container.querySelector('#btn-rent').addEventListener('click', () => {
store.dispatchAction('RENT_METHODOLOGY');
});
}
// Подписка на шину событий хранилища
store.addEventListener('stateChanged', renderRoyaltyDashboard);
В контексте разговора о контрактах и декларативных правилах веб-разработки, такой подход возвращает нас к истокам: браузер сам по себе является мощнейшей платформой, не требующей надстроек для базовых задач.
Этот подход идеален для pre-seed этапа стартапа, хакатонов, проверки бизнес-моделей и демонстрации заказчикам. Когда логика валидирована на 3000 строк чистого JS, переписать ее на промышленный стек с микросервисами и Postgres занимает недели, а не месяцы, потому что доменная модель уже полностью очищена от иллюзий.
Инженерные границы
Разумеется, было бы наивно запускать такой прототип в реальный продакшен с миллионом пользователей. Память браузера ограничена, данные не защищены от очистки кэша, а реальные финансовые транзакции требуют строгих ACID-гарантий СУБД.
Но как инструмент быстрой проверки гипотез кейс ЦАС доказывает главное: архитектурная дисциплина и смелость сказать «нет» лишним библиотекам значат для успеха продукта неизмеримо больше, чем погоня за модными фреймворками.