Le «patch de singe» est-il vraiment aussi mauvais?

Certaines langues comme Ruby et JavaScript ont des classes ouvertes qui vous permettent de modifier les interfaces même des classes de base comme les nombres, les chaînes, les tableaux, etc. Évidemment, cela pourrait confondre les autres qui connaissent bien l'API, mais il y a une bonne raison de l'éviter autrement , En supposant que vous ajoutez à l'interface et que vous ne modifiez pas les comportements existants?

Par exemple, il pourrait être judicieux d' ajouter une implémentation Array.map aux navigateurs Web qui ne mettent pas en œuvre ECMAScript 5ème édition (et si vous n'avez pas besoin de tous les jQuery). Ou vos tableaux Ruby pourraient bénéficier d'une méthode de «somme» de commodité qui utilise «injecter». Tant que les modifications sont isolées dans vos systèmes (p. Ex., Pas partie d'un logiciel que vous communiquez pour la distribution), il est bon de ne pas profiter de cette fonctionnalité linguistique?

Wikipedia présente un bref résumé des pièges du patch de singe:

http://fr.wikipedia.org/wiki/Monkey_patch#Pitfalls

Il y a un moment et un lieu pour tout, aussi pour les patchs de singes. Les développeurs expérimentés ont de nombreuses techniques dans leurs manches et apprennent à les utiliser. C'est rarement une technique en soi qui est «méchante», juste une utilisation inconsidérée de celle-ci.

Le patch de singe, comme beaucoup d'outils dans la boîte à outils de programmation, peut être utilisé à la fois pour le bien et pour le mal. La question est de savoir où, dans l'ensemble, ces outils sont plus utilisés. Dans mon expérience avec Ruby, l'équilibre pèse lourdement sur le côté «maléfique».

Alors, quel est l'utilisation «maléfique» des patches de singes? Eh bien, les patchs de singe en général vous laissent largement ouverts aux affrontements majeurs, potentiellement non diagnostiqués. J'ai une classe A J'ai une sorte de module de patch de singes MB qui method1 A pour inclure method1 , method2 et method3 . J'ai un autre module de correctifs de singes MC qui method2 également A pour inclure une method2 , une method3 et une method4 . Maintenant, je suis dans un lien. J'appelle instance_of_A.method2 : à qui s'appelle la méthode? La réponse à cela peut dépendre de nombreux facteurs:

  1. Dans quel ordre ai-je apporté les modules de correctifs?
  2. Les patchs sont-ils appliqués immédiatement ou dans une sorte de situation conditionnelle?
  3. AAAAAAARGH! LES SPIANTS COMPRENENT CES EYEBALLS DE L'INTERIEUR!

OK, donc # 3 est peut-être un peu trop mélodramatique ….

Quoi qu'il en soit, c'est le problème avec les patchs de singes: des problèmes horribles d'entraves. Compte tenu de la nature hautement dynamique des langues qui l'accompagnent, vous êtes déjà confronté à de nombreux problèmes potentiels d'action effrayante à distance; Le patch de singe ajoute à ceux-ci.

Le fait de disposer de monkey-patch est agréable si vous êtes un développeur responsable. Malheureusement, IME, ce qui a tendance à se produire, c'est que quelqu'un voit des patchs de singes et dit: "Dommage! Je vais juste mettre le monkey dans le lieu de vérifier si d'autres mécanismes pourraient ne pas être plus appropriés". Il s'agit d'une situation analogue aux bases de code Lisp créées par des personnes qui recherchent des macros avant de penser qu'elles fonctionnent comme une fonction.

Tant que les modifications sont isolées dans vos systèmes (p. Ex., Pas partie d'un logiciel que vous communiquez pour la distribution), il est bon de ne pas profiter de cette fonctionnalité linguistique?

En tant que développeur isolé sur un problème isolé, il n'y a aucun problème avec l'extension ou la modification d'objets natifs. De plus, dans les grands projets, il s'agit d'un choix d'équipe qui devrait être fait.

Personnellement, je n'aime pas avoir des objets natifs dans javascript altérés mais c'est une pratique courante et c'est un choix valable à faire. Si vous allez écrire une bibliothèque ou un code qui est destiné à être utilisé par d'autres, je l'éviterais fortement.

Il s'agit cependant d'un choix de conception valide pour permettre à l'utilisateur de définir un indicateur de configuration indiquant s'il vous plaît écraser les objets natifs avec vos méthodes de commodité car il est si pratique.

Pour illustrer un piège spécifique au JavaScript.

 Array.protoype.map = function map() { ... }; var a = [2]; for (var k in a) { console.log(a[k]); } // 2, function map() { ... } 

Ce problème peut être évité en utilisant ES5 qui vous permet d'injecter des propriétés non énumérées dans un objet.

C'est principalement un choix de conception de haut niveau et tout le monde doit être conscient / accepter cela.

Il est parfaitement raisonnable d'utiliser "patchs de singes" pour corriger un problème spécifique et connu où l'alternative serait d'attendre un patch pour le réparer. Cela implique d'assumer temporairement la responsabilité de réparer quelque chose jusqu'à ce qu'il existe une solution corrective "correcte" que vous pouvez déployer.

Une opinion considérée par Gilad Bracha sur Monkey Patching: http://gbracha.blogspot.com/2008/03/monkey-patching.html

Les conditions que vous décrivez – ajoutant (ne modifiant pas) le comportement existant, et ne libère pas votre code au monde extérieur – semblent relativement sécuritaires. Cependant, des problèmes pourraient surgir si la prochaine version de Ruby ou JavaScript ou Rails change son API. Par exemple, que faire si une future version de jQuery vérifie si Array.map est déjà définie et suppose que c'est la version EMCA5Script de la carte quand, en réalité, c'est votre patch monkey?

De même, que se passe-t-il si vous définissez "sum" dans Ruby, et un jour vous décidez d'utiliser ce code ruby ​​dans Rails ou d'ajouter le joystick Active Support à votre projet. Active Support définit également une méthode de somme (sur Enumerable), donc il y a un conflit.