¿Se considera monkeypatching una buena práctica de programación?

15

He tenido la impresión de que monkeypatching está más en la categoría de pirateo rápido y sucio, en lugar de la práctica de programación estándar y buena. Si bien de vez en cuando solía solucionar problemas menores con bibliotecas de terceros, lo consideraba una solución temporal y enviaba el parche adecuado al proyecto de terceros.

Sin embargo, he visto esta técnica utilizada como "la forma normal" en proyectos convencionales, por ejemplo, en el gevent.monkeymódulo de Gevent .

¿Se ha convertido el mono parche en una práctica de programación convencional, normal y aceptable?

Ver también: "Monkeypatching For Humans" de Jeff Atwood

vartec
fuente
13
Diría que algo llamado parche de mono NO se considera una buena práctica de programación. Sin siquiera saber qué es, solo por el nombre.
littleadv
¿Qué sucede si un tercero no quiere hacer la reparación que necesita?
1
@ Thorbjørn: buena pregunta, por un lado no me gusta el mono parcheado, por otro no me gusta la idea de clonar proyectos y mantener parches locales si es solo un problema menor.
vartec
1
@littleadv: ... entonces llámalo "corrección" / "corrección sobre la marcha" o "corrección de tiempo de ejecución" y suena bien, ¿verdad? ;) Todo es lo mismo.
Dagnelies
3
JavaScript se basa en el concepto
ZJR

Respuestas:

19

No, pero a veces monkeypatch es un mal menor (que tener un código roto :)). Mis reglas generales para parches de mono en rubí son:

  • tiene una muy buena razón para el parche de mono (la revisión crítica temporal es una buena razón. El buen formato del método to_s no lo es, a menos que esté trabajando en ActiveSupport)

  • hágalos lo más transparentes posible: colóquelos en un lugar específico en la base de código y separe los archivos, escriba documentación que describa el motivo de monkeypatch (aquí hay un ejemplo ).

  • fácil de eliminar: la documentación debe incluir información sobre la eliminación y qué ver. Muchos parches de mono son temporales, por lo que deberían ser fáciles de quitar.

Lukas Stejskal
fuente
11

Sí, ¡monkeypatching es muy útil!

De alguna manera, los nombres parecen ser muy influyentes en la percepción de las personas. Llámalo "monkeypatch" y suena mal, llámalo "hot fix" o "sobre la marcha" y suena bien.

Independientemente de eso, creo que la capacidad de alterar métodos / atributos / funciones en tiempo de ejecución es algo muy útil. Incluso la gente de JavaScript lo usa todo el día sin saberlo.

Por ejemplo:

button.onclick = function(e) { ...}

Esta línea simple ilustra el hecho de que altera el comportamiento del botón. Fue diseñado de esa manera. Del mismo modo, podría alterar cualquier otra función, pero sería una tontería hacerlo.

Ahora, para la cuestión de entregar parches de esa manera ... bueno ... por qué no. Solo tiene que descargar un pequeño parche en lugar de un gran lanzamiento. Diablos, incluso podrías parchear un servidor sin detenerlo, ¡genial! Y luego, un día, también podría obtener la última versión para una actualización más grande. Lo suficientemente justo. Entonces sí, yo voto por "parches de tiempo de ejecución" como algo bueno.

Curiosamente, algunos idiomas como Erlang incluso se construyeron alrededor de este concepto. La capacidad de actualizar un servidor sobre la marcha.

Por supuesto, al final, y como con todo lo demás, es cuestión de cómo lo uses. Puedes hacer cosas maravillosas OO y una mierda, todo es lo mismo.

EDITAR:

Permítanme agregar alguna distinción entre mayúsculas y minúsculas, ya sea que estén parcheando su propia biblioteca o una de terceros .

... básicamente, lo que haces con un parche de este tipo es corregir un error de tu propia biblioteca o la de un tercero . En cualquier caso es útil. Por su cuenta, le permite entregar una solución sobre la marcha. Para un tercero, espere (¿varios meses?) Hasta que lo arreglen por sí mismo o lo haga ahora por su cuenta. (aún puede enviarles el parche para que lo arreglen de su lado). Cuando lancen su próxima versión de lib con el problema solucionado, aún puede, si desea actualizar la biblioteca y eliminar el parche de su lado.

Ahora, por supuesto, si usa un parche para alterar el comportamiento de una lib y alienar su propósito / forma de trabajar, entonces obviamente esa es una receta para el desastre. Incluso un mono vería eso ... bueno, espero. ;)

dagnelies
fuente
1
Nadie dice que no es útil. Sin embargo, no es una buena práctica en general. Y "hotfix" y "on-the-fly fix" no me suenan mejor.
Lukas Stejskal
1
Bueno, creo que la capacidad de alterar el comportamiento de una aplicación sobre la marcha es muy útil, incluso más si es grande. ¡Diablos, incluso podría tener el código que almacena el método anterior como copia de seguridad y un comando para revertir automáticamente a pedido! ¡Las posibilidades son tremendas!
Dagnelies
Estoy de acuerdo en que es una característica poderosa y útil. Pero también es muy peligroso (especialmente en Ruby), por lo tanto, debe usarse con extrema precaución (especialmente para modificar bibliotecas estándar y de terceros). ¿Alguna vez ha tratado de mantener la aplicación dependiendo de varias bibliotecas de terceros con parches de mono? Una receta para el desastre cada vez que intente actualizar alguna biblioteca.
Lukas Stejskal
1
Sí, estoy de acuerdo, si usa estos parches descuidadamente, de forma no intencionada o abusa de ellos, puede volverse desordenado rápidamente. Como si pudieras abusar de cualquier concepto o hacer un lío con cualquier cosa. Sin embargo, de lo contrario, si están bien organizados y son transparentes, y todos fluyen en el próximo gran lanzamiento, me parece limpio. ... sin embargo, no tengo experiencia con bibliotecas de rubíes que están muy parcheadas.
Dagnelies
... Agregué algunos comentarios sobre el último caso.
Dagnelies
8

Creo que todos los parches son intrínsecamente riesgosos debido a su naturaleza de tiempo de ejecución e incapacidad para ser detectados en tiempo de diseño.

Aceptan excepciones de tiempo de ejecución y requieren depuradores y relojes complejos solo para seguirlos.

Se usan cuando las personas SEAL clasifican, por lo que la herencia es imposible. Sin embargo, hay mejores formas de extender objetos sin dañarlos.

Mis dos centavos

Mickey Perlstein
fuente
4

Los parches en general deberían ser el último recurso, los parches de mono aún más. El problema es principalmente de mantenibilidad.

Hace mucho tiempo, mi kernel de Linux tenía 3 parches separados, necesarios para mi controlador de tarjeta de video y dos aplicaciones propietarias que tenía. Dos de ellos tuvieron cambios conflictivos, lo que significaba que necesitaba un cuarto parche para resolver las diferencias entre ellos. Ahora, cada vez que se solucionaba un problema de seguridad en el kernel ascendente, tenía que esperar a que los proveedores de esos 3 parches publicaran una actualización de la nueva versión del kernel, que tardó de uno a seis meses, o tenía que mantener manualmente el upstream parches de seguridad hasta que los otros vendedores de parches se pusieron al día.

Después de unos años, los proveedores lograron ser incluidos en la fuente del kernel ascendente, y pude detener el acto de equilibrio, pero se puede ver qué lío fue mientras tanto. No inflijas eso a tus programadores a menos que tengas que hacerlo.

Karl Bielefeldt
fuente
3

No. No es una técnica estándar para el desarrollo de software. Sigue siendo una solución para resolver un problema grave y tiene inconvenientes claros. Me viene a la mente la violación del Principio de sustitución de Liskov . Los parches de mono hacen que sea mucho más difícil razonar sobre los programas. Para sus propios programas, debe colocar el código donde pertenece. Para las bibliotecas de terceros, siempre vivirás en peligro, ya que tu parche no funcionará con la próxima versión de la biblioteca.

Por supuesto, el parche de mono es útil si sabe lo que está haciendo y no tiene tiempo para implementar una solución SÓLIDA . Pero nunca debe considerar esto como una técnica estándar y construir parche de mono sobre parche de mono.

Por cierto, ¿alguna vez escribiste una prueba unitaria para un parche de mono?

Scarfridge
fuente
No creo que puedas aplicar LSP aquí. Tiene una definición muy específica sobre subtipos.
Konrad Rudolph
@KonradRudolph Monkey parchear un objeto cambia su tipo. En los idiomas de tipo dinámico, cada tipo t con la misma interfaz que el tipo u es un subtipo de u. Si camina como un pato ...
scarfridge
"... cambia su tipo" - bastante justo. Tiene sentido.
Konrad Rudolph
RE "No es una técnica estándar para el desarrollo de software.", Parece que hacer * todo el tiempo y en las principales bibliotecas" en Python para la prueba.
Tommy