MongoDB Java 드라이버가 조건부에서 난수 생성기를 사용하는 이유는 무엇입니까?


211

나는 다음 코드를 보았다 커밋이 를 위해 MongoDB의 자바 연결 드라이버 , 어떤 종류의 농담 먼저 나타납니다. 다음 코드는 무엇을합니까?

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

(편집 : 이 질문을 게시 한 후 코드 가 업데이트되었습니다 )


13
어느 부분이 당신을 혼란스럽게합니까?
Oliver Charlesworth

4
혼란 스럽다고 생각합니다. 이 코드는 catch 블록에서 실행됩니다!
Proviste

11
@MarkoTopolnik : 그렇습니까? 훨씬 더 명확하게 if (!ok || Math.random() < 0.1)(또는 비슷한 것으로) 쓰여질 수 있습니다 .
Oliver Charlesworth

5
github.com/mongodb/mongo-java-driver/commit/… 당신은 처음이 아닙니다. 그 줄에 대한 주석을보십시오
msangel

3
@msangel 저 사람들은 코딩 스타일이 아니라 논리를 비판하는 것 같습니다.
Marko Topolnik

답변:


279

그 라인의 역사를 조사한 후, 나의 주요 결론은 직장에서 무능한 프로그래밍이 있었다는 것입니다.

  1. 그 선은 사실 복잡하다. 일반적인 형태

    a? true : b

    에 대한 boolean a, b간단한

    a || b
  2. 주변 부정과 과도한 괄호는 사물을 더욱 복잡하게 만듭니다. De Morgan의 법칙 을 염두에두면 이 코드가 중요하다는 것은 사소한 관찰입니다.

    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
또한이 나타난다는 지금까지의 내가, MongoDB를 공식 10gen 자바 드라이버가 너무 자바 드라이버에 대하여 의견을 가지고뿐만 아니라, 나는 그것이 나에게 MongoDB를의 코드에 대한 의견이 있습니다 생각 말할 수있는, 할 수
크리스 트래버스

5
몇 줄의 코드 만 분석하면 인터뷰 질문으로 바꿀 수 있습니다! 네 번째 요점은이 프로젝트에 근본적으로 문제가있는 진정한 열쇠입니다 (다른 것은 불행한 프로그래머의 버그로 기각 될 수 있음).
Abel

1
@ChrisTravers 그것은 이다 몽고의 공식 몽고 자바 드라이버.
assylias 2016 년

17

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

11 시간 전 gareth-rees에 의해 :

아마도 카운터 또는 타이머를 유지 관리하는 비용을 발생시키지 않으면 서 서버 장애의 약 1/10 만 기록하므로 대량 스팸을 피하는 것이 좋습니다. (그러나 타이머를 유지하는 것이 합리적입니까?)


13
nitpick이 아니라 res를 반환하는 시간의 1/10이므로 다른 9/10 시간을 기록합니다.
Supericy

23
@Supericy 그것은 확실히 nitpicking이 아닙니다. 그것은이 사람의 끔찍한 코딩 관행에 대한 증거 일뿐입니다.
Anorov

7

음수 1로 초기화 된 클래스 멤버를 추가하십시오.

  private int logit = -1;

try 블록에서 테스트를 수행하십시오.

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

이것은 항상 첫 번째 오류를 기록한 다음 10 번째 후속 오류를 기록합니다. 논리 연산자는 "단락"하므로 실제 오류시에만 로짓이 증가합니다.

연결에 관계없이 모든 오류 중 첫 번째와 열 번째 오류 를 원하면 멤버 대신 로짓 클래스를 정적으로 만드십시오.

언급했듯이 이것은 스레드 안전해야합니다.

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

try 블록에서 테스트를 수행하십시오.

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

참고 : 오류의 90 %를 버리는 것은 좋은 생각이 아닙니다.


1

나는 이런 종류의 것을 전에 보았다.

다른 '블랙 박스'코드 조각에서 온 특정 '질문'에 응답 할 수있는 코드 조각이있었습니다. 응답 할 수없는 경우 실제로 느린 다른 '블랙 박스'코드로 전달합니다.

따라서 때때로 이전에 보지 못한 새로운 '질문'이 나타나고 100 개가 연속으로 배치되는 것처럼 배치로 나타납니다.

프로그래머는 프로그램의 작동 방식에 만족했지만 새로운 질문이있을 경우 향후 소프트웨어를 개선 할 수있는 방법을 원했습니다.

따라서 해결책은 알 수없는 질문을 기록하는 것이었지만 결과적으로 1000 개의 다른 질문이있었습니다. 로그가 너무 커져서 명확한 대답이 없었기 때문에 속도를 높이는 이점이 없었습니다. 그러나 가끔씩 대답 할 수있는 일련의 질문이 나타납니다.

로그가 너무 커지고 로깅이이 솔루션에 얻은 실제 중요한 사항을 로깅하는 방식으로 진행되고 있기 때문에 :

무작위로 5 % 만 기록하면 장기적으로 로그에 추가되는 질문 / 응답이 표시되는 동안 로그가 정리됩니다.

따라서 알 수없는 이벤트가 발생하면 임의의 경우에 기록됩니다.

나는 이것이 당신이보고있는 것과 유사하다고 생각합니다.

나는이 작업 방식이 마음에 들지 않았 으므로이 코드를 제거 하고이 메시지를 다른 파일 에 기록 했으므로 모두 존재했지만 일반 로그 파일을 방해하지는 않았습니다.


3
우리가 여기서 데이터베이스 드라이버에 대해 이야기하고 있다는 것을 제외하고는, 잘못된 문제 공간, IMO!
Steven Schlansker

@StevenSchlansker 나는 이것이 좋은 습관이라고 결코 말하지 않았습니다. 이 코드를 제거하고이 메시지를 다른 파일에 기록했습니다.
Jens Timmerman 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.