javascript ruby oop language-design monkeypatching

javascript - ¿Es realmente tan malo "parchar el mono"?



ruby oop (5)

Algunos lenguajes como Ruby y JavaScript tienen clases abiertas que le permiten modificar interfaces de clases básicas como números, cadenas, matrices, etc. Obviamente, hacerlo podría confundir a otros que están familiarizados con la API, pero hay una buena razón para evitarlo de otra manera. ¿Suponiendo que está agregando a la interfaz y no está cambiando el comportamiento existente?

Por ejemplo, podría ser bueno agregar una implementación de Array.map a los navegadores web que no implementan la 5ª edición de ECMAScript (y si no necesita todo jQuery). O sus matrices de Ruby podrían beneficiarse de un método de conveniencia de "suma" que usa "inyectar". Siempre que los cambios estén aislados en sus sistemas (por ejemplo, que no formen parte de un paquete de software que libere para su distribución), ¿hay alguna buena razón para no aprovechar esta función de idioma?


Siempre que los cambios estén aislados en sus sistemas (por ejemplo, que no formen parte de un paquete de software que libere para su distribución), ¿hay alguna buena razón para no aprovechar esta función de idioma?

Como un desarrollador solitario en un problema aislado, no hay problemas con la extensión o alteración de objetos nativos. También en proyectos más grandes, esta es una elección de equipo que debe hacerse.

Personalmente, no me gusta que se modifiquen los objetos nativos en JavaScript, pero es una práctica común y es una elección válida. Si va a escribir una biblioteca o un código que está destinado a ser utilizado por otros, lo evitaría en gran medida.

Sin embargo, es una opción de diseño válida que le permite al usuario establecer un indicador de configuración que indica que sobrescribe los objetos nativos con sus métodos de conveniencia porque es muy conveniente.

Para ilustrar un error específico de JavaScript.

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

Este problema se puede evitar utilizando ES5, que le permite inyectar propiedades no enumerables en un objeto.

Esto es principalmente una opción de diseño de alto nivel y todos deben estar conscientes / acordar esto.


El parcheo de monos, como muchas otras herramientas en la caja de herramientas de programación, puede usarse tanto para bien como para mal. La pregunta es dónde, en general, estas herramientas tienden a ser las más utilizadas. En mi experiencia con Ruby, el balance pesa mucho en el lado "malo".

Entonces, ¿qué es un uso "malo" de parches de monos? Bueno, el parche de monos en general te deja abierto a enfrentamientos importantes, potencialmente imposibles de diagnosticar. Tengo una clase A Tengo algún tipo de módulo de parcheo de monos MB que parchea A para incluir method1 , method2 y method3 . Tengo otro módulo MC parcheo de monos que también parchea A para incluir un method2 , method4 y method4 . Ahora estoy en un aprieto. Llamo a instance_of_A.method2 : ¿a quién se llama el método? La respuesta a eso puede depender de muchos factores:

  1. ¿En qué orden introduje los módulos de parcheo?
  2. ¿Se aplican los parches de inmediato o en algún tipo de circunstancia condicional?
  3. AAAAAAARGH! ¡LAS ARAÑAS ESTÁN COMIENDO MIS OJOS FUERA DEL INTERIOR!

OK, entonces # 3 es quizás un poco demasiado melodramático ...

De todos modos, ese es el problema con los parches de los monos: horribles problemas de conflicto. Dada la naturaleza altamente dinámica de los lenguajes que normalmente lo soportan, ya se enfrenta a muchos problemas potenciales de "acción espeluznante a distancia"; parches de mono simplemente se suma a estos.

Tener un parche disponible es bueno si eres un desarrollador responsable. Desafortunadamente, IME, lo que suele suceder es que alguien ve parches en los monos y dice: "¡Cariño! Solo lo parchearé en lugar de verificar si otros mecanismos podrían no ser más apropiados". Esta es una situación más o menos análoga a las bases de código Lisp creadas por personas que utilizan macros antes de pensar en hacerlo simplemente como una función.


Es perfectamente razonable usar el "parche de mono" para corregir un problema específico conocido donde la alternativa sería esperar a que un parche lo arregle. Eso significa asumir temporalmente la responsabilidad de arreglar algo hasta que haya una solución "adecuada", lanzada formalmente, que pueda implementar.

Una opinión considerada por Gilad Bracha sobre Monkey Patching: http://gbracha.blogspot.com/2008/03/monkey-patching.html


Las condiciones que describe (agregar (no cambiar) el comportamiento existente y no liberar su código al mundo exterior) parecen relativamente seguras. Sin embargo, podrían surgir problemas si la próxima versión de Ruby o JavaScript o Rails cambia su API. Por ejemplo, ¿qué sucede si alguna versión futura de jQuery verifica si Array.map ya está definida y asume que es la versión de mapa EMCA5Script cuando en realidad es su parche de mono?

Del mismo modo, si define "suma" en Ruby, y un día decide que quiere usar ese código de Ruby en Rails o agregue la gema de Soporte Activo a su proyecto. El soporte activo también define un método de suma (en Enumerable), por lo que hay un conflicto.


Wikipedia tiene un breve resumen de los escollos de parches de monos:

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

Hay un momento y un lugar para todo, también para parches de monos. Los desarrolladores experimentados tienen muchas técnicas en la manga y aprenden cuándo usarlas. Rara vez es una técnica per se que es "malvada", simplemente desconsiderada su uso.