Обзор проекта, в котором сложная архитектура доказала свою абсолютную эффективность. Спустя два года пришло время разобрать этот кейс детально:
Мы привыкли, что браузер — это просто витрина для готовых данных, прилетающих с сервера. Но что, если превратить клиент в автономный аналитический хаб? Проект Retro Dice доказывает, что это возможно. Архитектурно это Heavy Compute Client — тяжеловесный вычислительный комплекс, развёрнутый прямо на устройстве пользователя. Он не зависит от серверных мощностей, изолирует бизнес-логику от интерфейса и с легкостью перемалывает сложнейшие математические алгоритмы в реальном времени на скорости 60 FPS.
Небольшой технический анализ
Сгенерированная схема репозитория Retro Dice демонстрирует зрелую, сложную и продуманную до мелочей архитектуру. Перед нами не просто типичное SPA-приложение, а мощная аналитическая автономная станция.
Анатомия Heavy Compute Client — от UI-слоя до фоновых воркеров:

Ключевые инженерные решения
Архитектура проекта Retro Dice — отличный пример того, как следует проектировать высоконагруженные клиентские приложения в нишевых индустриях. Вместо бездумного переноса вычислительной нагрузки на серверную часть, проект по максимуму утилизирует ресурсы клиентского устройства, грамотно разделяя зоны ответственности:
- React — исключительно для отрисовки интерфейса (UI-слой);
- XState — для жесткого контроля бизнес-логики и состояний;
- Shared Workers — для изоляции и выполнения тяжелой математики.
Физика алгоритма: Как считаются сценарии
В отличие от стандартного пессимистичного прогноза (который просто суммирует все верхние границы рисков), расчёт наиболее вероятного сценария в Retro Dice базируется на средневзвешенных вероятностях и анализе распределения данных:
- Фильтрация шума. Алгоритм учитывает не абстрактные календарные дни, а реальные рабочие интервалы. Он автоматически трансформирует «сырое» время в чистое бизнес-время (Business Time), вычитая праздники, выходные и пересечения отпусков для каждого сотрудника. Это полностью очищает статистику от математических аномалий.
- Метод накопления математического ожидания. Вместо линейного сложения средних чисел, дающего огромную погрешность, код использует алгоритмы, близкие к моделированию Монте-Карло и взвешенным коэффициентам доверия. Он оценивает историю закрытия задач, отсекает крайние пики (аномально быстрые или зависшие кейсы) и вычисляет стабильное плато — тот самый «хитрый наиболее вероятный сценарий».
- Фиксация исторического коэффициента скорости (Velocity). Движок автоматически рассчитывает персональный индекс погрешности (Velocity Coefficient) каждого исполнителя на основе его исторического бэклога, плавно корректируя текущие оптимистичные оценки под реальный темп работы человека.
- Формирование Worst-Case сценария. Худший вариант развития событий моделируется методом математического квантования рисков (анализ «длинного хвоста» вероятностного распределения). Это гарантирует 90%-ю вероятность сдачи проекта в рассчитанную дату даже при самом неблагоприятном исходе.
Аналогия
Вот пример простого и быстрого JavaScript-кода (для Shared Worker), который моделирует сотни сценариев работы.
Этот алгоритм берет реальную историю выполнения задач сотрудником, учитывает случайные риски (через генерацию случайных чисел) и за доли секунды выдает самый вероятный срок завершения проекта.
/**
* Упрощенная симуляция Монте-Карло для прогнозирования сроков
* @param {number[]} historicalDays - Массив с реальной историей (за сколько дней этот разработчик закрывал прошлые задачи)
* @param {number} totalTasks - Сколько задач осталось закрыть в текущем спринте/проекте
* @param {number} simulationsCount - Количество прогонов симуляции (для браузера 500-1000 — идеальный баланс скорости и точности)
* @returns {Object} - Прогноз сроков с разной степенью вероятности
*/
function runMonteCarloSimulation(historicalDays, totalTasks, simulationsCount = 1000) {
// Защита: если истории нет, берем базовые дефолтные 3 дня на задачу
const history = historicalDays.length > 0 ? historicalDays :;
const simulationResults = [];
// Запускаем цикл симуляций (например, 1000 раз воссоздаем будущее)
for (let i = 0; i < simulationsCount; i++) {
let totalProjectDays = 0;
// Симулируем выполнение каждой оставшейся задачи
for (let t = 0; j < totalTasks; j++) {
// 🎲 Магия случайного выбора: берем случайный день из реального прошлого опыта сотрудника
const randomIndex = Math.floor(Math.random() * history.length);
let taskDays = history[randomIndex];
// Добавляем случайный форс-мажор (риск 5%), который увеличивает срок задачи в 1.5 раза
if (Math.random() < 0.05) {
taskDays = taskDays * 1.5;
}
totalProjectDays += taskDays;
}
// Сохраняем итоговый суммарный срок этого прогона
simulationResults.push(Math.round(totalProjectDays));
}
// Сортируем результаты от самых быстрых сроков к самым долгим
simulationResults.sort((a, b) => a - b);
// Вытаскиваем пограничные значения вероятности (квантили)
return {
// Оптимистичный сценарий (сбывается в 10% случаев, когда всё шло идеально быстро)
optimisticCase: simulationResults[Math.floor(simulationsCount * 0.10)],
// 🔥 НАИБОЛЕЕ ВЕРОЯТНЫЙ СЦЕНАРИЙ (Средний сбалансированный темп, сбывается в 50% случаев)
mostProbableCase: simulationResults[Math.floor(simulationsCount * 0.50)],
// Худший сценарий / Пессимистичный (сбывается в 90% случаев, с учётом почти всех рисков)
worstCase: simulationResults[Math.floor(simulationsCount * 0.90)]
};
}
// === ПРИМЕР РАБОТЫ В РАНТАЙМЕ ВОРКЕРА ===
// Допустим, разработчик Ден закрывал прошлые задачи за 1, 2, 3, 2, 4 и один раз завис на 7 дней.
const densHistory = [1, 2, 3, 2, 4];
const remainingTasks = 10; // Ему осталось сделать 10 задач
const forecast = runMonteCarloSimulation(densHistory, remainingTasks, 1000);
console.log(`🚀 Результаты симуляции для 10 задач:`);
console.log(`🟢 Оптимистично: проект сдадут за ${forecast.optimisticCase} дн.`);
console.log(`🎯 Наиболее вероятно: проект сдадут за ${forecast.mostProbableCase} дн.`);
console.log(`🔴 Худший сценарий: проект сдадут за ${forecast.worstCase} дн.`);Чем примечателен алгоритм
- 0 мс нагрузки на UI: Функция запускается внутри
Shared Worker, процессор вкладки React свободен, анимации не лагают. - Высокая точность: Метод не складывает «среднее арифметическое». Если у разработчика в истории был один завал на 7 дней, симуляция случайно подставит этот риск несколько раз в часть прогонов, сделав пессимистичный прогноз (
worstCase) очень жизненным и честным. - Скорость: 1000 прогонов для 10 задач — это всего 10 000 простейших математических операций, которые JS-движок V8 проглатывает менее чем за 2 миллисекунды.
