2+2=5. Наткнулся сейчас на "исключение"

Столкнулся сейчас с ситуацией, на которую натыкались многие. А уж если довелось рефакторить "монстров" авторства связки джуниор+ИИ... Мда...

Так вот, есть старый прикол.

20−20 = 25−25 4×(5−5) = 5×(5−5) 4 = 5 2+2 = 5

Уже не смешно на самом деле - "затертый до дыр" пример. Ошибка очевидна: нельзя делить на ноль - (5-5). Классика. Забавно, но не страшно потому, что это абстракция. Никто не строит на этом бизнес.

А теперь про легаси. И уже не прикол, а реальность.

Захожу в проект. Статистика, ряд чисел по метрикам в дашборде. Всё как бы выглядит нормально. Но ответ в итоге - на единицу больше, чем должен быть. Надо вылечить. Проверяю, считаю - не сходится. Начинаю сомневаться: то ли я схожу с ума, то ли мои познания в арифметике все-таки не полные.

Само собой не убивался три часа - банально проверяем step-by-step. Ответ виден с первого шага - данные.

Какой-то умник придумал хранить счётчики метрик не в целочисленном, а в дробном значении. И ведь работало же! Пока старые данные округлялись перед записью. Зачем дробное - совершенно не понятный "ход конем". Но затем добавили новую метрику. И вот тут другой уникум (или тот же?), не проверил что получается при расчете и не написал код, который округляет.

А результат-то выводится с округлением.

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

Хотите верьте, хотите нет, но там реально были двойки, из которых получалась пятерка!

В исходных данных - 2.49 и 2.47. В дашборде каждая метрика округляется: 2 и 2. Складываем округлённые: 4. Но складывали исходные: 4.96. Округляем сумму - 5. 2+2=5. В реальном бизнесе. На реальных метриках.

Три ошибки, наложенные друг на друга.

Первая. Счётчик во float. Метрика - это количество. Штук, штук, штук. Целое. Но кто-то решил, что float "универсальнее". Или не подумал, а может скопировал из другого места, где было дробное? История скрыта также, как история славян.

Вторая. Запись с округлением, а не вывод. Каждая метрика округляется отдельно. Пользователю не нужны 2.49, ему нужно 2. Вероятно, столило определиться - строится счетчик количества или процентный показатель.

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

Каждая ошибка по отдельности казалось бы мелочь. Вместе - сломанная арифметика (и мозг того, кто начнет разбираться). Единица в метрике - это деньги, решения, отчёт, по которому кто-то делает выводы для принятия решений и зарабатывания денег.

Этот код кстати на хвалёном Laravel. Не то, что я против него - будем считать, что я не определился. Структура, миграции, Eloquent, очереди. Всё по учебнику. Но проблема вовсе не в нём.

Есть такой анекдот к слову. - У меня программа не работает! - Все в порядке. Просто поменяйте ушастую прокладку. - А где она? - Между монитором и спинкой кресла.

Любой фреймворк регламентирует только как писать: структуру, синтаксис, паттерны. Он не говорит что писать и главное как это делать. Не скажет: "счётчик должен быть целым". Не остановит, если ты положишь количество в float. Не предупредит, что округление до сложения ломает сумму.

Фреймворк это каркас и он не думает за человека. Это только инструмент, а что с ними делают - не его ответственность. Можно построить дом. Можно сарай. Инструменты одни.

И ещё одна деталь.

Комментарии в расчете новой метрики. На каждый чих. Все на русском. "Увеличиваем счётчик", "складываем значения" и т.д. Очевидные вещи, описанные словами. Яркий признак: писал ИИ по русскому промпту.

Это может и не плохо само по себе. Плохо то, что комментарии описывали происходящее, но не проверяли его - это задача человека. ИИ не спросит: "а округлять надо?". Комментарии фиксировали код, но не ставили его под сомнение.

Ни один фреймворк не спасет от ошибки в модели данных. Комментарий не заменит понимания. А 2+2=5 - это не всегда прикол. Иногда это дашборд, по которому принимают решения.

Проверяйте типы. Округляйте с умом и в нужном месте.

И главное - не верьте, что "работает" = "правильно".