Чому драйвер Java MongoDB використовує генератор випадкових чисел умовно?


211

У цьому комітеті я побачив наступний код для драйвера MongoDB Java Connection , і спочатку, здається, це якийсь жарт. Що робить наступний код?

if (!((_ok) ? true : (Math.random() > 0.1))) {
    return res;
}

(EDIT: код було оновлено після публікації цього питання)


13
Яка його частина вас бентежить?
Олівер Чарльзворт

4
я думаю, що це заплутано. цей код виконується в блоці лову!
Забронювати

11
@MarkoTopolnik: Це? Це можна було б написати набагато чіткіше if (!ok || Math.random() < 0.1)(або щось подібне).
Олівер Чарльворт

5
github.com/mongodb/mongo-java-driver/commit/… ви не перший, дивіться коментар до цього рядка
msangel

3
@msangel Ці хлопці, здається, критикують логіку, а не стиль кодування.
Марко Топольник

Відповіді:


279

Перевіривши історію цього рядка, головний мій висновок полягає в тому, що в роботі були деякі некомпетентні програми.

  1. Ця лінія безперечно закручена. Загальна форма

    a? true : b

    бо boolean a, bеквівалентно простому

    a || b
  2. Навколишні заперечення та надмірні дужки перекручують речі далі. Маючи на увазі закони Де Моргана , цей фрагмент коду дорівнює

    if (!_ok && Math.random() <= 0.1)
      return res;
    
  3. Прихильність, яка спочатку ввела цю логіку, мала

    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стану. Але потім він переплутав і вставив ефективний "подвійний негатив", повернувши знак нерівності.

  4. Сторінка стилю кодування відхиляється, стохастичний журнал - це досить сумнівна практика сама по собі, тим більше, що запис журналу не документує власну особливу поведінку. Очевидно, намір полягає в тому, щоб зменшити перерахунки того самого факту: що сервер зараз не працює. Відповідне рішення - реєструвати лише зміни стану сервера, а не кожне його спостереження, не кажучи вже про випадковий вибір 10% таких спостережень. Так, це забирає трохи більше зусиль, тому давайте подивимося.

Я можу лише сподіватися, що всі ці докази некомпетентності, накопичені під час перевірки лише трьох рядків коду , не говорять справедливо про проект в цілому, і що ця робота буде очищена якнайшвидше.


26
Крім того, це, наскільки я можу сказати, є офіційним драйвером Java на 10 мов для MongoDB, тому, крім того, що я маю думку про драйвер Java, я думаю, що це дає мені думку щодо коду MongoDB
Кріс Траверс

5
Чудовий аналіз лише кількох рядків коду, я можу просто перетворити його на питання інтерв'ю! Ваш четвертий пункт - це справжній ключ, чому з цим проектом щось принципово не так (інші можуть бути відхилені як помилки програмового програміста).
Абель

1
@ChrisTravers Це є офіційним драйвером Монго Java для Монго.
assylias

17

https://github.com/mongodb/mongo-java-driver/commit/d51b3648a8e1bf1a7b7886b7ceb343064c9e2225#commitcomment-3315694

11 годин тому автор: gareth-rees:

Імовірно, ідея полягає в реєстрації лише близько 1/10 відмов сервера (і так уникайте масового спаму журналу), не несучи витрат на підтримку лічильника або таймера. (Але, безумовно, підтримка таймера буде доступною?)


13
Не для нитпика, але: 1/10 числа часу він поверне res, тому він запише інші 9/10 разів.
Суперсит

23
@Supericy Це, безумовно, не заполоняє. Це лише ще одне свідчення жахливої ​​практики кодування цієї людини.
Аноров

7

Додайте члена класу, ініціалізованого до мінус 1:

  private int logit = -1;

У блоці спробуйте зробити тест:

 if( !ok && (logit = (logit + 1 ) % 10)  == 0 ) { //log error

Це завжди реєструє першу помилку, а потім кожну десяту наступну помилку. Логічні оператори "коротке замикання", тому logit збільшується лише на фактичну помилку.

Якщо ви хочете першу та десяту всіх помилок, незалежно від з'єднання, зробіть клас logit статичним замість aa.

Як було зазначено, це повинно бути безпечно для потоків:

private synchronized int getLogit() {
   return (logit = (logit + 1 ) % 10);
}

У блоці спробуйте зробити тест:

 if( !ok && getLogit() == 0 ) { //log error

Примітка. Я не думаю, що викидати 90% помилок - це гарна ідея.


1

Я бачив подібні речі раніше.

Був фрагмент коду, який міг відповісти на певні «запитання», що надходили від іншого «чорного ящика». У випадку, якщо він не може відповісти на них, він пересилатиме їх до іншого фрагмента коду "чорної скриньки", який був дуже повільним.

Тому іноді раніше з'являлися невидимі нові "запитання", і вони з'являлися б партією, як 100 підряд.

Програміст був задоволений тим, як програма працює, але він хотів певним чином вдосконалити програмне забезпечення в майбутньому, якщо будуть можливі нові питання.

Отже, рішення полягало в тому, щоб записувати невідомі питання, але, як виявилось, було 1000 різних. Журнали стали надто великими, і не було користі прискорити їх, оскільки вони не мали очевидних відповідей. Але раз у раз з’являється група запитань, на які можна відповісти.

Оскільки журнали ставали занадто великими, і ведення журналу перешкоджало веденню реальних важливих речей, які він отримав до цього рішення:

Запишіть лише випадкові 5%, це очистить журнали, хоча в перспективі все ще буде показано, які питання / відповіді можна додати.

Отже, якби сталася невідома подія, у випадковій кількості цих випадків вона буде реєструватися.

Я думаю, це схоже на те, що ви бачите тут.

Мені такий спосіб роботи мені не сподобався, тому я видалив цей фрагмент коду і просто записав ці повідомлення до іншого файлу , щоб вони були всіма присутніми, але не загадували загальний журнал.


3
За винятком того, що ми тут говоримо про драйвер бази даних ... неправильний простір, IMO!
Стівен Шланскер

@StevenSchlansker Я ніколи не говорив, що це була хороша практика. Я видалив цей фрагмент коду і просто записав ці повідомлення в інший файл.
Єнс Тіммерман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.