2013-05-30 22 views
198

Tôi thấy mã sau đây trong this commit cho MongoDB's Java Connection driver, và nó xuất hiện lúc đầu là một trò đùa của một số loại. Mã sau làm gì?Tại sao trình điều khiển Java MongoDB sử dụng trình tạo số ngẫu nhiên trong điều kiện?

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

(EDIT: mã has been updated since đăng câu hỏi này)

+13

Phần nào của bạn gây nhầm lẫn cho bạn? –

+0

đọc http://stackoverflow.com/questions/10336899/java-what-is-a-question-mark-and-colon-within-the-parentheses-of-a-prin – lakshman

+4

tôi nghĩ điều này thật khó hiểu. mã này được thực hiện trong một khối catch! – Proviste

Trả lời

264

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 đó được biến đổi một cách vô cớ. Dạng tổng quát

    a? true : b 
    

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

    a || b 
    
  2. các xung quanh phủ và quá ngoặc cuốn lại điều hơn nữa. Giữ trong tâm trí De Morgan's laws nó là một quan sát tầm thường rằng đoạn mã này số tiền

    if (!_ok && Math.random() <= 0.1) 
        return res; 
    
  3. cam kết rằng originally introduced this logic

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

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

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

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

Tôi chỉ có thể hy vọng rằng tất cả các bằng chứng này thiếu năng lực, tích lũy từ kiểm tra chỉ ba dòng mã, không nói một cách công bằng của dự án như một toàn thể, và rằng công việc này sẽ được làm sạch lên CÀNG SỚM CÀNG TỐT.

+24

Ngoài ra, điều này dường như, theo như tôi có thể nói, trình điều khiển Java 10gen chính thức cho MongoDB vì vậy ngoài việc có ý kiến ​​về trình điều khiển Java, tôi nghĩ nó mang lại cho tôi một ý kiến ​​về mã MongoDB –

+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ó cái gì đó về cơ bản sai với dự án này (những người khác có thể được miễn nhiệm như lỗi của lập trình viên không may). – Abel

+1

@ChrisTravers Nó * là trình điều khiển java mongo chính thức cho mongo. – assylias

15

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

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

Có lẽ ý tưởng là để đăng nhập chỉ khoảng 1/10 các lỗi máy chủ (và do đó tránh gửi thư rác quá mức), 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ẽ là giá cả phải chăng?)

+13

Không để nitpick nhưng: 1/10th của thời gian nó sẽ trở lại res, vì vậy nó sẽ đăng nhập 9/10 lần khác. – Supericy

+22

@Supericy Đó là chắc chắn không nitpicking. Đó chỉ là thêm 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 khởi tạo âm 1:

private int logit = -1; 

Trong khối try, hãy kiểm tra:

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

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

Nếu bạn muốn đầ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ì một thành viên.

Như đã được ghi nhận này nên được thread an toàn:

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

Trong khối try, hãy kiểm tra:

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

Lưu ý: Tôi không nghĩ rằng ném ra 90% lỗi là một ý tưởng hay.

+0

Đây không phải là chủ đề an toàn ... –

+0

Đúng, nó sẽ được tạo thành an toàn chỉ. – tpdi

1

Tôi đã từng 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 đến từ một đoạn mã 'hộp đen' khác. Trong trường hợp nó không thể trả lời chúng, nó sẽ chuyển tiếp chúng đến một đoạn mã 'hộp đen' khác thực sự chậm chạp.

Vì vậy, đôi khi các câu hỏi 'mới' chưa được nhìn thấy trước đó sẽ hiển thị và chúng sẽ hiển thị theo lô, như 100 hàng trong một hàng.

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

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

Kể từ khi các bản ghi đã nhận được quá lớn, và khai thác gỗ đã nhận được trong cách đăng những điều quan trọng thực ông đã đến giải pháp này:

Chỉ đăng nhập một ngẫu nhiên 5%, điều này sẽ làm 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ĩ điều này tương tự như những gì bạn thấy ở đây.

Tôi không thích cách làm việc này, vì vậy tôi lấy đoạn mã này, và chỉ cần đăng nhập những thông điệp vào một tập tin khác nhau, vì vậy họ đều có mặt, nhưng không clobbering 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 ... không gian vấn đề sai, IMO! –

+0

@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ỉ cần ghi lại các thư này vào một tệp khác. –