Три коммита против хаоса: как я спасал расчёты скоринга

Когда баги в расчётах больнее, чем я думал: история исправления системы скоринга
Вот такой момент: сидишь ты, смотришь на результаты работы своей системы анализа трендов в проекте trend-analysis, и понимаешь — что-то не так с оценками. Пользователи видят неправильные значения, frontend показывает одно, backend считает совсем другое, и где-то в этом хаосе теряются ваши данные о трендах.
Началось с простого: поиск несоответствия
Задача была такой: унифицировать систему скоринга между страницей трендов и страницей анализа, плюс сделать её консистентной на всех слоях приложения. Проблема скрывалась в деталях. На бэкенде я обнаружил, что поле для зоны влияния называлось strength, но фронтенд ожидал impact. Вроде мелочь, но эта мелочь ломала весь расчёт оценки — данные просто не доходили до формулы.
Первым делом создал feature-ветку fix/score-calculation-and-display, чтобы иметь безопасное место для экспериментов. Это правило номер один: никогда не чини критичное на main.
Три коммита — три фикса
Коммит первый (6800636) — объединил layouts страниц тренда и анализа. Оказалось, что кнопки были разбросаны в разных местах, компонента Sparkline находилась не там, где нужно, и показатель уверенности (confidence) был спрятан в глубины интерфейса. Переделал разметку, привёл всё к общему знаменателю.
Коммит второй (08ed4cd) — вот тут засада. Бэкенд API 0.3.0 использовал название поля impact, а я в калькуляторе оценки искал strength. Результат: null вместо числа. Исправил — и вдруг всё заработало. Казалось бы, переименование в одном месте, но оно спасло половину функциональности.
Коммит третий (12cc666) — уже фронтенд. Функция formatScore нормализовала значения неправильно, и getScoreColor работал с неправильной шкалой. Переделал под шкалу 0–10, убрал лишнюю нормализацию — сейчас скор отображается именно так, как его считает бэкенд.
Почему это вообще произошло?
Типичная история: когда несколько разработчиков работают над одной системой в разное время, контракт между бэкендом и фронтендом расходится. Никто не виноват — просто один переименовал поле, другой не знал об этом. Было бы хорошо иметь автоматические тесты контрактов (contract testing), которые бы сразу эту несогласованность выловили. GraphQL был бы удобнее — типизация спасла бы много мук.
Что дальше?
Merge Request готов к созданию. API сервер уже перезапущен и слушает на http://127.0.0.1:8000. Vite dev server для фронтенда работает в фоне с HMR, поэтому изменения подхватываются моментально. Остаётся дождаться review коллег, смёрджить в main и развернуть.
Урок на будущее: синхронизируй контракты между слоями приложения через документацию или, ещё лучше, через code generation из единого источника истины.
😄 GitLab MR — как свидание вслепую: никогда не знаешь, найдут ли рецензенты ошибки, которые не заметил ты.
Метаданные
- Session ID:
- grouped_trend-analisis_20260210_1732
- Branch:
- main
- Dev Joke
- MySQL — как первая любовь: никогда не забудешь, но возвращаться не стоит.
Часть потока:
Разработка: trend-analisis