Почему драйвер MongoDB Java использует генератор случайных чисел в условном выражении?
Я видел следующий код в this commit для MongoDB Java Connection driver, и он появляется сначала быть какой-то шуткой. Что делает следующий код?
if (!((_ok) ? true : (Math.random() > 0.1))) {
return res;
}
(EDIT: код был обновлен с публикации этого вопроса)
Ответы
Ответ 1
После проверки истории этой линии мой основной вывод заключается в том, что на работе было проведено некомпетентное программирование.
-
Эта строка безвозвратно запутана. Общий вид
a? true : b
для boolean a, b
эквивалентно простому
a || b
-
Окружающее отрицание и чрезмерные круглые скобки свертывают все дальше. Имея в виду законы Де Моргана, это тривиальное замечание, что этот фрагмент кода составляет
if (!_ok && Math.random() <= 0.1)
return res;
-
Признак, который изначально представил эту логику, имел
if (_ok == true) {
_logger.log( Level.WARNING , "Server seen down: " + _addr, e );
} else if (Math.random() < 0.1) {
_logger.log( Level.WARNING , "Server seen down: " + _addr );
}
— еще один пример некомпетентного кодирования, но обратите внимание на обратную логику: здесь событие регистрируется, если либо _ok
, либо в 10% других случаев, тогда как код в 2. возвращает 10% времени и журналов 90 % времени. Таким образом, позднее совершение разрушило не только ясность, но и правильность.
Я думаю, что в коде, который вы опубликовали, мы можем увидеть, как автор намеревался каким-то образом преобразовать оригинальный if-then
в свое отрицание, требуемое для раннего условия return
. Но затем он испортил и ввел эффективный "двойной отрицательный", изменив знак неравенства.
-
Проблемы с кодированием в сторону, стохастическая регистрация - довольно сомнительная практика сама по себе, тем более, что запись в журнале не документирует свое собственное своеобразное поведение. Очевидно, что целью является сокращение повторений одного и того же факта: сервер в настоящее время недоступен. Соответствующим решением является регистрация только изменений состояния сервера, а не каждого его наблюдения, не говоря уже о случайном выборе 10% таких наблюдений. Да, это требует немного больше усилий, поэтому давайте посмотрим некоторые.
Я могу только надеяться, что все эти доказательства некомпетентности, накопленные при проверке только трех строк кода, не говорят справедливо о проекте в целом и что эта часть работы будет очищена как можно скорее.
Ответ 2
https://github.com/mongodb/mongo-java-driver/commit/d51b3648a8e1bf1a7b7886b7ceb343064c9e2225#commitcomment-3315694
11 часов назад от gareth-rees:
Предположительно, идея состоит в том, чтобы регистрировать только около 1/10 сбоев сервера (и, следовательно, избегать массового рассылки спама), не прибегая к расходам на поддержание счетчика или таймера. (Но верно ли сохранение таймера было бы доступно?)
Ответ 3
Добавить член класса, инициализированный на отрицательный 1:
private int logit = -1;
В блоке try выполните тест:
if( !ok && (logit = (logit + 1 ) % 10) == 0 ) { //log error
Это всегда регистрирует первую ошибку, затем каждую десятую последующую ошибку. Логические операторы "короткого замыкания", поэтому логит только увеличивается на фактическую ошибку.
Если вы хотите получить первую и десятую часть всех ошибок, независимо от подключения, сделайте статический класс logit вместо члена.
Как было отмечено, это должно быть потокобезопасным:
private synchronized int getLogit() {
return (logit = (logit + 1 ) % 10);
}
В блоке try выполните тест:
if( !ok && getLogit() == 0 ) { //log error
Примечание. Я не думаю, что 90% ошибок - это хорошая идея.
Ответ 4
Я видел это раньше.
Был фрагмент кода, который мог бы ответить на определенные "вопросы", которые исходили из другого кода "черного ящика". В случае, если он не мог ответить на них, он отправил бы их другому фрагменту кода "черного ящика", который был очень медленным.
Поэтому иногда появлялись ранее невидимые новые "вопросы", и они появлялись в пакете, например, 100 из них подряд.
Программист был доволен тем, как работает программа, но он хотел каким-то образом улучшить программное обеспечение в будущем, по возможности открыли новые вопросы.
Таким образом, решение заключалось в регистрации неизвестных вопросов, но, как оказалось, было 1000 разных. Журналы стали слишком большими, и не было никакой возможности ускорить их, поскольку у них не было очевидных ответов. Но каждый раз время от времени появлялась партия вопросов, на которые можно было ответить.
Поскольку журналы становились слишком большими, и ведение журнала мешало регистрировать реальные важные вещи, которые он получил для этого решения:
Зарегистрировать только случайные 5%, это очистит журналы, в то время как в долгосрочной перспективе все еще покажет, какие вопросы/ответы могут быть добавлены.
Итак, если произошло неизвестное событие в случайном количестве этих случаев, оно будет записано в журнал.
Я думаю, что это похоже на то, что вы видите здесь.
Мне не понравился этот способ работы, поэтому я удалил этот фрагмент кода, и просто зарегистрировал эти
сообщения в другой файл, поэтому они все присутствовали, но не сбивали общий файл журнала.