web-dev-qa-db-fra.com

Pourquoi le pilote MongoDB Java utilise-t-il un générateur de nombres aléatoires dans une condition?

J'ai vu le code suivant dans ce commit pour MongoDB Java Pilote de connexion , et il semble au début que ce soit une blague. Quel est le rôle du code suivant?

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

(EDIT: le code a été mis à jour depuis le affichage de cette question)

207
Monstieur

Après avoir examiné l'historique de cette ligne, ma principale conclusion est qu'il y a eu des programmes incompétents au travail.

  1. Cette ligne est gratuitement compliquée. La forme générale

    a? true : b
    

    pour boolean a, b est équivalent au simple

    a || b
    
  2. La négation environnante et les parenthèses excessives compliquent davantage les choses. Gardant à l'esprit lois de De Morgan c'est une observation triviale que ce morceau de code équivaut à

    if (!_ok && Math.random() <= 0.1)
      return res;
    
  3. Le commit que à l'origine de cette logique avait

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

    —Un autre exemple de codage incompétent, mais notez la logique inversée : ici l'événement est enregistré si _ok Ou dans 10% des autres cas, alors que le code dans 2. renvoie 10% du temps et enregistre 90% des temps. Ainsi, le dernier engagement a gâché non seulement la clarté, mais la correction elle-même.

    Je pense que dans le code que vous avez posté, vous pouvez réellement voir comment l'auteur avait l'intention de transformer littéralement le if-then Original en une négation requise pour la condition précoce return. Mais ensuite, il s'est trompé et a inséré un "double négatif" efficace en inversant le signe d'inégalité.

  4. Mis à part le style de codage, la journalisation stochastique est une pratique douteuse, d'autant plus que l'entrée de journal ne documente pas son propre comportement. L’intention est évidemment de réduire les reformulations du même fait: le serveur est actuellement en panne. La solution appropriée consiste à ne consigner que les modifications de l'état du serveur, et non chacune de ses observations, encore moins une sélection aléatoire de 10% de ces observations. Oui, cela demande un peu plus d'effort, alors voyons-en.

Je ne peux que souhaiter que toutes ces preuves d'incompétence, accumulées en inspectant seulement trois lignes de code , ne parlent pas fidèlement du projet dans son ensemble, et que ce travail sera nettoyé dès que possible.

273
Marko Topolnik

https://github.com/mongodb/mongo-Java-driver/commit/d51b3648a8e1b7a7b7886b7ceb343064c9e2225#commitcomment-3315694

Il y a 11 heures par gareth-rees:

Il est vraisemblable que l’idée est de ne consigner que 1/10 des pannes de serveur (et d’éviter ainsi d’envoyer des spams massivement dans le journal), sans que cela coûte cher de maintenir un compteur ou une minuterie. (Mais maintenir une minuterie serait sûrement abordable?)

16
msangel

Ajoutez un membre de classe initialisé au négatif 1:

  private int logit = -1;

Dans le bloc try, faites le test:

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

Ceci enregistre toujours la première erreur, puis toutes les dix erreurs suivantes. Les opérateurs logiques "court-circuitent", donc logit n'est incrémenté que sur une erreur réelle.

Si vous voulez le premier et le dixième des tous erreurs, quelle que soit la connexion, rendez la classe logit statique au lieu d'un membre.

Comme il a été noté, cela devrait être thread-safe:

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

Dans le bloc try, faites le test:

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

Note: Je ne pense pas que jeter 90% des erreurs soit une bonne idée.

7
tpdi

J'ai déjà vu ce genre de chose.

Il y avait un morceau de code qui pouvait répondre à certaines "questions" provenant d'un autre morceau de code "boîte noire". Dans le cas où il ne pourrait pas y répondre, il les transmettrait à un autre morceau de code "boîte noire" très lent.

Ainsi, parfois, de nouvelles "questions" auparavant inconnues apparaissaient, et elles apparaissaient par lot, comme 100 par la suite.

Le programmeur était satisfait du fonctionnement du programme, mais il souhaitait pouvoir éventuellement améliorer le logiciel à l'avenir, si de nouvelles questions étaient découvertes.

La solution consistait donc à enregistrer des questions inconnues, mais il s'est avéré qu'il y avait des milliers de questions différentes. Les grumes devenaient trop volumineuses et il n’y avait aucun avantage à les accélérer, car elles n’avaient pas de réponses évidentes. Mais de temps en temps, une série de questions apparaissaient auxquelles il était possible de répondre.

Comme les grumes devenaient trop volumineuses et que la journalisation empêchait de journaliser les choses vraiment importantes qu'il avait dans cette solution:

Ne consignez que 5% au hasard, cela nettoiera les journaux, tout en indiquant à long terme quelles questions/réponses pourraient être ajoutées.

Ainsi, si un événement inconnu se produisait, dans un nombre aléatoire de ces cas, il serait enregistré.

Je pense que cela ressemble à ce que vous voyez ici.

Je n’aimais pas cette façon de travailler, j’ai donc supprimé ce morceau de code et juste a consigné ces messages dans un fichier différent, ils étaient donc tous présents, sans toutefois surcharger le fichier journal général.

1
Jens Timmerman