И даже привел пару примеров из личной практики
Инженер Microsoft с 30-летним стажем Рэймонд Чен, автор блога The Old New Thing, рассказал забавный, но поучительный случай из практики внутреннего ревью API.
Команда разрабатывала интерфейс, в котором набор допустимых значений задавался тремя числами: минимум, максимум и шаг (increment).
Пример: если минимум = 5, шаг = 10, максимум = 30, то допустимые значения — 5, 15, 25 и 30.
Разработчики решили, что если шаг равен нулю, то можно просто считать допустимыми только минимум и максимум. Казалось бы, логично — пока кто-то не написал функцию:
int closestSupportedValue(int desired) { int nearest = minimum + ((desired - minimum + increment/2) / increment) * increment; return std::clamp(nearest, minimum, maximum); }
Все работает — пока increment ≠ 0. При нуле код просто падает на делении.
Разработчик может никогда не заметить этого, если его оборудование всегда возвращает ненулевые значения. Но стоит попасть на устройство с «нулевым шагом», и вы получите классическую «divide by zero».Рэймонд Ченэкс-Microsoft
Как избежать ошибки
Рэймонд предложил простое правило:
- если диапазон состоит из двух значений, шаг нужно задать равным max − min;
- если значение одно — просто поставить 1, а не ноль.
Ноль в API — это ловушка. Он всегда приглашает кого-то поделить на него.Рэймонд Ченэкс-Microsoft
«Ноль» в реальной разработке
В качестве бонуса Чен вспомнил, как похожая ошибка возникла у команды, разрабатывавшей систему прогнозов энергосети (PowerGridForecast).
Там решили, что при отсутствии данных, длительность блока (BlockDuration
) можно ставить равной нулю. Ведь «все равно данных нет».
Результат тот же: деление на ноль при расчете индекса прогнозного блока. Решение оказалось тривиальным — использовать не ноль, а типичное ненулевое значение, например один час.
Почему это важно
История Чена напоминает: даже если API «работает» с нулем, он может внезапно обрушить систему в продакшене. Такие кейсы не ловятся автотестами, если у команды нет «нулевых» данных в окружении.