为什么MongoDB Java驱动程序在条件中使用随机数生成器?

Mon*_*eur 211 java obfuscation mongodb

我看到下面的代码这次提交MongoDB的Java的连接驱动程序,它首次出现时是某种玩笑.以下代码有什么作用?

if (!((_ok) ? true : (Math.random() > 0.1))) {
    return res;
}
Run Code Online (Sandbox Code Playgroud)

(编辑:发布此问题以来代码已更新)

Mar*_*nik 279

在检查了该线的历史之后,我的主要结论是在工作中出现了一些无能的编程.

  1. 这条线是无偿的错综复杂的.一般形式

    a? true : b
    
    Run Code Online (Sandbox Code Playgroud)

    for boolean a, b等同于简单

    a || b
    
    Run Code Online (Sandbox Code Playgroud)
  2. 周围的否定和过多的括号使事情进一步卷入.记住De Morgan的定律,这段代码相当于一个微不足道的观察

    if (!_ok && Math.random() <= 0.1)
      return res;
    
    Run Code Online (Sandbox Code Playgroud)
  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 );
    }
    
    Run Code Online (Sandbox Code Playgroud)

    - 另一个不称职编码的例子,但请注意相反的逻辑:这里记录的事件是其中一个_ok或10%的其他情况,而2.中的代码返回 10%的时间并记录90%的时间.因此,后来的提交不仅破坏了清晰度,而且破坏了正确性.

    我认为在您发布的代码中,我们实际上可以看到作者打算如何将原始if-then文本转换为早期return条件所需的否定.但后来他搞砸了并通过扭转不平等的标志插入了一个有效的"双重否定".

  4. 抛开编码风格问题,随机日志记录本身就是一个非常可疑的实践,特别是因为日志条目没有记录其自身的特殊行为.显然,目的是减少同一事实的重述:服务器当前已关闭.适当的解决方案是仅记录服务器状态的变化,而不记录每个观察的变化,更不用说随机选择10%这样的观察结果.是的,这需要更多的努力,所以让我们看一些.

我只能希望通过检查三行代码而积累的所有这些无能证据,并不能完全说明整个项目,并且这项工作将尽快清理完毕.

  • 另外,就我所知,这似乎是MongoDB的官方10gen Java驱动程序,所以除了对Java驱动程序有意见之外,我认为它给了我一个关于MongoDB代码的意见 (26认同)
  • 只需几行代码的优秀分析,我可能会把它变成一个面试问题!你的第四点是真正的关键,为什么这个项目存在根本性的错误(其他人可能被解雇为不幸的程序员的错误). (5认同)

msa*_*gel 17

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

11小时前由gareth-rees:

据推测,这个想法只记录了大约1/10的服务器故障(因此避免大量垃圾邮件发送日志),而不会产生维护计数器或计时器的成本.(但肯定维持一个计时器会负担得起吗?)

  • @Supericy这绝对不是挑剔.这只是这个人可怕的编码实践的更多证据. (23认同)
  • 不要挑剔但是:1/10的时间它将返回res,所以它将记录其他9/10次. (13认同)

tpd*_*pdi 7

添加初始化为负1的类成员:

  private int logit = -1;
Run Code Online (Sandbox Code Playgroud)

在try块中,进行测试:

 if( !ok && (logit = (logit + 1 ) % 10)  == 0 ) { //log error
Run Code Online (Sandbox Code Playgroud)

这始终记录第一个错误,然后记录每第十个后续错误.逻辑运算符"短路",因此logit仅在实际错误时递增.

如果您想要所有错误的第一个和第十个,无论连接如何,请使logit类静态而不是成员.

如前所述,这应该是线程安全的:

private synchronized int getLogit() {
   return (logit = (logit + 1 ) % 10);
}
Run Code Online (Sandbox Code Playgroud)

在try块中,进行测试:

 if( !ok && getLogit() == 0 ) { //log error
Run Code Online (Sandbox Code Playgroud)

注意:我不认为抛出90%的错误是个好主意.