Tại sao trình điều khiển Java MongoDB sử dụng trình tạo số ngẫu nhiên trong một điều kiện?


211

Tôi đã thấy đoạn mã sau trong cam kết này cho trình điều khiển Kết nối Java của MongoDB và lúc đầu nó xuất hiện như một trò đùa. Mã sau đây làm gì?

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

(EDIT: mã đã được cập nhật kể từ khi đăng câu hỏi này)


13
Phần nào của nó làm bạn bối rối?
Oliver Charlesworth

4
Tôi nghĩ nó khó hiểu. mã này được thực thi trong một khối bắt!
Cung cấp

11
@MarkoTopolnik: Phải không? Nó có thể được viết rõ ràng hơn nhiều như if (!ok || Math.random() < 0.1)(hoặc một cái gì đó tương tự).
Oliver Charlesworth

5
github.com/mongodb/mongo-java-do/commit/ nam bạn không phải là người đầu tiên, xem bình luận cho dòng đó
msangel

3
@msangel Những kẻ đó dường như đang chỉ trích logic, không phải phong cách mã hóa.
Marko Topolnik

Câu trả lời:


279

Sau khi kiểm tra lịch sử của dòng đó, kết luận chính của tôi là đã có một số chương trình không đủ năng lực trong công việc.

  1. Dòng đó là vô cớ. Hình thức chung

    a? true : b

    cho boolean a, btương đương với đơn giản

    a || b
  2. Các phủ định xung quanh và dấu ngoặc đơn quá mức làm cho mọi thứ thêm phức tạp. Hãy ghi nhớ luật của De Morgan, đó là một quan sát tầm thường rằng đoạn mã này có giá trị

    if (!_ok && Math.random() <= 0.1)
      return res;
  3. Cam kết ban đầu giới thiệu logic này

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

    Ví dụ đơn giản về mã hóa không đủ năng lực, nhưng chú ý logic đảo ngược : ở đây sự kiện được ghi lại nếu _okhoặc trong 10% các trường hợp khác, trong khi mã trong 2. trả về 10% số lần và ghi lại 90% số lần. Vì vậy, các cam kết sau này hủy hoại không chỉ rõ ràng, mà còn chính xác.

    Tôi nghĩ rằng trong đoạn mã bạn đã đăng, chúng ta thực sự có thể thấy tác giả dự định chuyển đổi bản gốc theo if-thencách nào đó theo nghĩa đen thành sự phủ định cần thiết cho returnđiều kiện ban đầu . Nhưng sau đó anh ấy đã làm rối và chèn một "tiêu cực kép" hiệu quả bằng cách đảo ngược dấu hiệu bất bình đẳng.

  4. Các vấn đề về phong cách mã hóa sang một bên, việc ghi nhật ký ngẫu nhiên hoàn toàn là một thực tế đáng ngờ, đặc biệt là vì mục nhập nhật ký không ghi lại hành vi kỳ dị của chính nó. Rõ ràng, ý định là làm giảm sự phục hồi của cùng một thực tế: rằng máy chủ hiện đang ngừng hoạt động. Giải pháp thích hợp là chỉ ghi nhật ký các thay đổi của trạng thái máy chủ, chứ không phải mỗi quan sát của nó, chứ chưa nói đến việc lựa chọn ngẫu nhiên 10% các quan sát như vậy. Vâng, điều đó chỉ cần nỗ lực hơn một chút, vì vậy hãy xem một số.

Tôi chỉ có thể hy vọng rằng tất cả bằng chứng về sự bất tài này, được tích lũy từ việc kiểm tra chỉ ba dòng mã , không nói lên toàn bộ dự án và toàn bộ công việc này sẽ được dọn sạch càng sớm càng tốt.


26
Ngoài ra, điều này dường như là, theo như tôi có thể nói, trình điều khiển Java 10gen chính thức cho MongoDB, ngoài việc có ý kiến ​​về trình điều khiển Java, tôi nghĩ rằng nó cho tôi ý kiến ​​về mã của MongoDB
Chris Travers

5
Phân tích tuyệt vời chỉ một vài dòng mã, tôi có thể biến nó thành một câu hỏi phỏng vấn! Điểm thứ tư của bạn là chìa khóa thực sự tại sao có một cái gì đó sai về cơ bản với dự án này (những cái khác có thể được coi là lỗi của lập trình viên không may).
Abel

1
@ChrisTravers Đây trình điều khiển java mongo chính thức cho mongo.
assylias

17

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

11 giờ trước bởi gareth-rees:

Có lẽ ý tưởng là chỉ đăng nhập khoảng 1/10 lỗi máy chủ (và do đó tránh spam ồ ạt nhật ký), mà không phải chịu chi phí duy trì bộ đếm hoặc bộ đếm thời gian. (Nhưng chắc chắn duy trì một bộ đếm thời gian sẽ có giá phải chăng?)


13
Không phải cho nitpick nhưng: 1/10 thời gian nó sẽ trả về res, vì vậy nó sẽ đăng nhập 9/10 lần khác.
Siêu âm

23
@Supericy Điều đó chắc chắn không gây nghiện. Đó chỉ là nhiều bằng chứng về thực hành mã hóa khủng khiếp của người này.
Anorov

7

Thêm một thành viên lớp được khởi tạo thành âm 1:

  private int logit = -1;

Trong khối thử, hãy thực hiện bài kiểm tra:

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

Điều này luôn ghi lại lỗi đầu tiên, sau đó là lỗi thứ mười tiếp theo. Toán tử logic "ngắn mạch", vì vậy logit chỉ được tăng lên trên một lỗi thực tế.

Nếu bạn muốn lỗi đầu tiên và thứ mười của tất cả các lỗi, bất kể kết nối, hãy tạo lớp logit tĩnh thay vì thành viên aa.

Như đã lưu ý đây nên là chủ đề an toàn:

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

Trong khối thử, hãy thực hiện bài kiểm tra:

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

Lưu ý: Tôi không nghĩ rằng việc loại bỏ 90% lỗi là một ý kiến ​​hay.


1

Tôi đã thấy loại điều này trước đây.

Có một đoạn mã có thể trả lời một số 'câu hỏi' nhất định xuất phát từ một đoạn mã 'hộp đen' khác. Trong trường hợp nó không thể trả lời họ, nó sẽ chuyển tiếp họ đến một đoạn mã 'hộp đen' khác rất chậm.

Vì vậy, đôi khi trước đây chưa thấy "câu hỏi" mới xuất hiện và chúng sẽ xuất hiện theo một đợt, giống như 100 câu hỏi liên tiếp.

Lập trình viên hài lòng với cách chương trình hoạt động, nhưng anh ta muốn một số cách có thể cải thiện phần mềm trong tương lai, nếu có thể có những câu hỏi mới được phát hiện.

Vì vậy, giải pháp là ghi nhật ký những câu hỏi chưa biết, nhưng khi nó bật ra, có 1000 câu hỏi khác nhau. Các bản ghi đã trở nên quá lớn, và không có lợi ích gì trong việc tăng tốc những thứ này, vì chúng không có câu trả lời rõ ràng. Nhưng thỉnh thoảng, một loạt các câu hỏi sẽ xuất hiện có thể được trả lời.

Vì các bản ghi đã trở nên quá lớn, và việc ghi nhật ký đang cản trở việc ghi nhật ký những điều quan trọng thực sự mà anh ấy có được cho giải pháp này:

Chỉ đăng nhập ngẫu nhiên 5%, điều này sẽ dọn sạch các bản ghi, trong khi về lâu dài vẫn hiển thị những câu hỏi / câu trả lời có thể được thêm vào.

Vì vậy, nếu một sự kiện không xác định xảy ra, trong một số lượng ngẫu nhiên các trường hợp này, nó sẽ được ghi lại.

Tôi nghĩ rằng điều này tương tự như những gì bạn đang thấy ở đây.

Tôi không thích cách làm việc này, vì vậy tôi đã xóa đoạn mã này và chỉ đăng nhập các tin nhắn này vào một tệp khác , vì vậy tất cả chúng đều có mặt, nhưng không ghi đè lên tệp logfile chung.


3
Ngoại trừ việc chúng ta đang nói về một trình điều khiển cơ sở dữ liệu ở đây ... sai không gian vấn đề, IMO!
Steven Schlansker

@StevenSchlansker Tôi chưa bao giờ nói đây là một thực hành tốt. Tôi đã xóa đoạn mã này và chỉ ghi lại những tin nhắn này vào một tệp khác.
Jens Timmerman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.