Mengapa driver Java MongoDB menggunakan generator angka acak dalam kondisi?

211

Saya melihat kode berikut dalam komit ini untuk driver Java Connection MongoDB , dan tampaknya pada awalnya menjadi semacam lelucon. Apa yang dilakukan kode berikut?

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

(EDIT: kode telah diperbarui sejak memposting pertanyaan ini)

Monstieur
sumber
13
Bagian mana yang membingungkan Anda?
Oliver Charlesworth
4
Saya pikir itu membingungkan. kode ini dieksekusi di blok tangkapan!
Proviste
11
@MarkoTopolnik: Benarkah? Itu bisa ditulis lebih jelas sebagai if (!ok || Math.random() < 0.1)(atau sesuatu yang serupa).
Oliver Charlesworth
5
github.com/mongodb/mongo-java-driver/commit/… Anda tidak pertama, lihat komentar di baris itu
msangel
3
@msangel Orang-orang itu tampaknya mengkritik logika, bukan gaya pengkodean.
Marko Topolnik

Jawaban:

279

Setelah memeriksa sejarah baris itu, kesimpulan utama saya adalah bahwa ada beberapa pemrograman yang tidak kompeten di tempat kerja.

  1. Garis itu berbelit-belit tak berbelit-belit. Bentuk umum

    a? true : b

    untuk boolean a, bsetara dengan yang sederhana

    a || b
  2. Negasi di sekitarnya dan tanda kurung yang berlebihan membelit berbagai hal lebih lanjut. Dengan mengingat hukum De Morgan, ini adalah pengamatan sepele bahwa bagian kode ini berjumlah

    if (!_ok && Math.random() <= 0.1)
      return res;
  3. Komit yang awalnya memperkenalkan logika ini telah

    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 );
    }

    —Sebuah contoh lain dari pengkodean yang tidak kompeten, tetapi perhatikan logika yang dibalik : di sini acara dicatat jika salah satu _okatau dalam 10% dari kasus lain, sedangkan kode dalam 2. kembali 10% dari waktu dan mencatat 90% dari waktu. Jadi komit yang kemudian hancur tidak hanya kejelasan, tetapi juga kebenaran itu sendiri.

    Saya pikir dalam kode yang telah Anda posting kita benar-benar dapat melihat bagaimana penulis bermaksud untuk mengubah aslinya if-thenentah bagaimana menjadi negasi yang diperlukan untuk returnkondisi awal . Tapi kemudian dia mengacaukan dan memasukkan "double negative" yang efektif dengan membalik tanda ketimpangan.

  4. Mengesampingkan masalah gaya, penebangan stokastik merupakan praktik yang cukup meragukan, terutama karena entri log tidak mendokumentasikan perilaku anehnya sendiri. Maksudnya, jelas, mengurangi penyajian kembali fakta yang sama: bahwa server saat ini sedang down. Solusi yang tepat adalah hanya mencatat perubahan status server, dan tidak setiap pengamatannya, apalagi pemilihan acak 10% pengamatan tersebut. Ya, itu hanya membutuhkan sedikit usaha, jadi mari kita lihat.

Saya hanya bisa berharap bahwa semua bukti ketidakmampuan ini, terakumulasi dari hanya memeriksa tiga baris kode , tidak berbicara adil tentang proyek secara keseluruhan, dan bahwa pekerjaan ini akan dibersihkan secepat mungkin.

Marko Topolnik
sumber
26
Selain itu, tampaknya, sejauh yang saya tahu, driver Java 10gen resmi untuk MongoDB sehingga selain memiliki pendapat tentang driver Java, saya pikir itu memberi saya pendapat tentang kode MongoDB
Chris Travers
5
Analisis yang luar biasa dari hanya beberapa baris kode, saya mungkin mengubahnya menjadi pertanyaan wawancara! Poin keempat Anda adalah kunci sebenarnya mengapa ada sesuatu yang secara fundamental salah dengan proyek ini (yang lain dapat dianggap sebagai bug programmer yang malang).
Abel
1
@ChrisTravers Ini adalah driver mongo java resmi untuk mongo.
assylias
17

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

11 jam yang lalu oleh gareth-rees:

Agaknya idenya adalah untuk mencatat hanya sekitar 1/10 dari kegagalan server (dan jadi hindari membuat spam log secara besar-besaran), tanpa mengeluarkan biaya untuk mempertahankan penghitung atau penghitung waktu. (Tapi tentunya mempertahankan timer akan terjangkau?)

msangel
sumber
13
Bukan untuk nitpick tetapi: 1/10 dari waktu itu akan mengembalikan res, sehingga akan mencatat 9/10 kali lainnya.
Supericy
23
@Supericy Itu jelas tidak mengacaukan. Itu hanya lebih banyak bukti dari praktik pengkodean orang ini yang mengerikan.
Anorov
7

Tambahkan anggota kelas yang diinisialisasi ke negatif 1:

  private int logit = -1;

Di blok coba, buat tes:

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

Ini selalu mencatat kesalahan pertama, lalu setiap sepuluh kesalahan berikutnya. Operator logis "korsleting", jadi logit hanya bertambah pada kesalahan aktual.

Jika Anda menginginkan kesalahan pertama dan kesepuluh dari semua kesalahan, terlepas dari koneksinya, buat kelas logit menjadi statis dan bukan anggota.

Seperti yang telah dicatat, ini harus aman utas:

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

Di blok coba, buat tes:

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

Catatan: Saya rasa membuang 90% kesalahan adalah ide yang bagus.

tpdi
sumber
1

Saya pernah melihat hal semacam ini sebelumnya.

Ada sepotong kode yang bisa menjawab 'pertanyaan' tertentu yang datang dari sepotong kode 'kotak hitam' lainnya. Jika tidak bisa menjawabnya, itu akan meneruskannya ke kode 'kotak hitam' yang sangat lambat.

Jadi kadang-kadang 'pertanyaan' baru yang sebelumnya tidak terlihat akan muncul, dan mereka akan muncul dalam batch, seperti 100 dari mereka berturut-turut.

Si programmer senang dengan bagaimana program itu bekerja, tetapi dia ingin beberapa cara untuk meningkatkan perangkat lunak di masa depan, jika mungkin pertanyaan baru ditemukan.

Jadi, solusinya adalah mencatat pertanyaan yang tidak diketahui, tetapi ternyata, ada 1000 pertanyaan yang berbeda. Log menjadi terlalu besar, dan tidak ada gunanya mempercepat ini, karena mereka tidak punya jawaban yang jelas. Tetapi sesekali, sejumlah pertanyaan akan muncul yang bisa dijawab.

Karena log menjadi terlalu besar, dan logging menghalangi cara penting hal-hal penting yang dia dapatkan untuk solusi ini:

Hanya mencatat 5% secara acak, ini akan membersihkan log, sementara dalam jangka panjang masih menunjukkan pertanyaan / jawaban apa yang bisa ditambahkan.

Jadi, jika peristiwa yang tidak diketahui terjadi, dalam jumlah acak dari kasus-kasus ini, itu akan dicatat.

Saya pikir ini mirip dengan apa yang Anda lihat di sini.

Saya tidak suka cara kerja ini, jadi saya menghapus potongan kode ini, dan hanya mencatat pesan-pesan ini ke file yang berbeda , jadi semuanya ada, tetapi tidak mengalahkan logfile umum.

Jens Timmerman
sumber
3
Kecuali bahwa kita berbicara tentang driver basis data di sini ... ruang masalah salah, IMO!
Steven Schlansker
@ SvenvenSchlansker Saya tidak pernah mengatakan ini adalah praktik yang baik. Saya menghapus kode ini, dan baru saja mencatat pesan-pesan ini ke file yang berbeda.
Jens Timmerman