70 votes

Que signifie exactement "Monkey Patching" en Ruby?

Selon Wikipedia, un monkey patch est :

un moyen d'étendre ou de modifier le code d'exécution des langages dynamiques [...] sans modifier le code source original.

La déclaration suivante de la même entrée m'a causé de la confusion :

En Ruby, le terme monkey patch a été mal compris comme signifiant toute modification dynamique d'une classe et est souvent utilisé comme synonyme de modification dynamique de n'importe quelle classe à l'exécution.

J'aimerais connaître la signification exacte du monkey patching en Ruby. Est-ce quelque chose comme ce qui suit, ou bien est-ce autre chose?

class String
  def foo
    "foo"
  end

66voto

RSK Points 6428

La meilleure explication que j'ai entendue pour Monkey patching/Duck-punching a été donnée par Patrick Ewing dans RailsConf 2007

...si ça ressemble à un canard et que ça parle comme un canard, c'est un canard, n'est-ce pas? Donc si ce canard ne vous donne pas le bruit que vous voulez, vous devez juste boxer ce canard jusqu'à ce qu'il renvoie ce que vous attendez.

38 votes

"Monkey patching est comme la violence. Si cela ne fonctionne pas, ce n'est pas parce que vous n'en utilisez pas assez."

0 votes

Mise à jour du lien avec la capture d'écran de web.archive.org.

50voto

Joshua Swink Points 1197

La réponse courte est qu'il n'y a pas de signification "exacte", car c'est un terme nouveau, et les gens l'utilisent différemment. Cela peut du moins être discerné à partir de l'article Wikipedia. Certains insistent pour dire que cela s'applique uniquement au code "runtime" (classes intégrées, je suppose), tandis que d'autres l'utiliseraient pour faire référence à la modification en temps d'exécution de n'importe quelle classe.

Personnellement, je préfère la définition plus inclusive. Après tout, si nous devions utiliser le terme uniquement pour la modification des classes intégrées, comment ferions-nous référence à la modification en temps d'exécution de toutes les autres classes? Ce qui est important pour moi, c'est qu'il y a une différence entre le code source et la classe qui s'exécute réellement.

En Ruby, le terme monkey patch a été mal compris pour signifier toute modification dynamique d'une classe et est souvent utilisé comme un synonyme de modification dynamique de n'importe quelle classe en temps d'exécution.

La déclaration ci-dessus affirme que l'utilisation en Ruby est incorrecte - mais les termes évoluent, et ce n'est pas toujours une mauvaise chose.

2 votes

"...différentes personnes l'utilisent différemment." Après avoir lu les réponses ici et sur la liste de diffusion Ruby-Talk, j'ai réalisé que vous avez tout à fait raison. Le terme avait un sens plus spécifique lorsqu'il a été créé pour la première fois, mais - comme vous l'avez dit - "les termes évoluent, et ce n'est pas toujours une mauvaise chose".

22voto

Paul Betts Points 41354

Le patching de monkey est lorsque vous remplacez les méthodes d'une classe à l'exécution (pas en ajoutant de nouvelles méthodes comme d'autres l'ont décrit).

En plus d'être une manière très peu évidente et difficile à déboguer de modifier du code, cela ne s'adapte pas à l'échelle; à mesure que de plus en plus de modules commencent à patcher des méthodes de monkey, la probabilité que les changements se chevauchent augmente.

0 votes

Vrai, cependant ce que j'ai montré était une méthode similaire et non entièrement nouvelle.

3 votes

Alors, quel est le terme qui décrit l'acte d'ajouter de nouvelles méthodes (s'il existe un tel terme) ?

2 votes

Si deux bibliothèques différentes ajoutent la même méthode à la même classe, l'une remplacera toujours l'autre. Peu importe que les deux ajoutent seulement des méthodes. Ajouter reste toujours un "monkey patching". Du moins, c'est ainsi que la communauté Ruby utilise le terme. Python l'utilise différemment.

4voto

davetron5000 Points 9622

Vous avez raison; c'est lorsque vous modifiez ou étendez une classe existante plutôt que de la sous-classer.

4voto

Robert K Points 14893

Ceci est un monkey patching :

class Float
  def self.times(&block)
    self.to_i.times { |i| yield(i) }
    reste = self - self.to_i
    yield(reste) if reste > 0.0
  end
end

Maintenant, j'imagine que cela pourrait être utile parfois, mais imaginez si vous voyiez cela régulièrement.

def my_method(mon_nombre_special)
  somme = 0
  mon_nombre_special.times { |num| somme << certaine_valeur ** num }
  somme
end

Et cela ne casse que de temps en temps lorsqu'il est appelé. Pour ceux qui prêtent attention, vous savez déjà pourquoi, mais imaginez que vous ne saviez pas que le type float avait une méthode de classe .times et que vous assumez automatiquement que mon_nombre_special est un entier. Chaque fois que le paramètre est un nombre entier, entier ou à virgule flottante, cela fonctionnera bien (des entiers entiers sont renvoyés sauf s'il y a un reste flottant). Mais passez un nombre avec quelque chose dans la partie décimale et cela cassera à coup sûr!

Imaginez simplement à quelle fréquence cela pourrait arriver avec vos gemmes, plugins Rails, et même par vos propres collègues dans vos projets. S'il y a un ou deux petits méthodes de ce type là-dedans et cela pourrait prendre du temps pour les trouver et les corriger.

Si vous vous demandez pourquoi cela casse, notez que somme est un entier et un reste à virgule flottante pourrait être renvoyé; de plus, le signe exponentiel ne fonctionne que lorsque les types sont les mêmes. Donc, vous pourriez penser que c'est corrigé, car vous avez converti les deux nombres en flottants ... pour finalement trouver que la somme ne peut pas prendre le résultat en virgule flottante.

1 votes

Tandis qu'il n'est pas toujours une bonne idée de faire du monkey patching, vous ne mettriez certainement pas des mois à trouver l'origine du bug puisqu'il apparaîtrait dans la pile.

1 votes

Oui, mais imaginez-le dans une grande application web Rails, où il fonctionne correctement 99% du temps. Maintenant, vous devez passer au peigne fin les journaux pour découvrir pourquoi il échoue, et cela pourrait prendre beaucoup de travail. ;-)

0 votes

Ceci est un bon exemple concret de pourquoi le "monkey patching" est dangereux

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X