¿Qué es el patrón de diseño "Arreglar todo"?

74

En este artículo de 2003 de Stephen Figgins en linuxdevcenter.com Se describe que BitTorrent de Bram Cohen utiliza el patrón de diseño "Arreglar todo".

  

Un enfoque menos común que hace que BitTorrent sea más difícil de comprender, pero que merece ser estudiado, es el uso de idempotencia de Cohen. Un proceso es idempotente cuando aplicarlo más de una vez no causa más cambios. Cohen dice que usa un patrón de diseño al que llama "Arreglar todo", una función que puede reaccionar a una serie de cambios sin tener en cuenta lo que podría cambiar. Él explica: "usted nota el evento que sucedió, luego llama a la función Arreglar todo lo que está escrito de esta manera tan identiva, y limpia todo lo que pueda estar ocurriendo y lo vuelve a calcular todo desde cero". Mientras que la idempotencia hace que algunos cálculos difíciles sean más fáciles, hace las cosas un poco complicadas. No siempre está claro qué va a cambiar una llamada, en todo caso. No necesitas saber de antemano. Usted es libre de llamar a la función, solo para estar seguro.

Esto suena bastante bien a primera vista.

Sin embargo, me parece que llamar a una función idempotente "arreglar todo" mejoraría la robustez del sistema a costa de la eficiencia y podría arruinar el sistema de contención (que podría preferir procesos que planifican y ejecutan cuidadosamente).

No puedo decir que lo haya usado antes, sin embargo. Tampoco puedo encontrar la fuente de su aplicación en línea (pero sí encontré esta que dice estar basada en ella). Tampoco puedo encontrar referencias a él fuera de este artículo (y considero que mi google-fu es bastante bueno) pero encontré una entrada para " Capacidad idempotente "en SOApatterns.org .

¿Esta idea es más conocida por otro nombre?

¿Qué es el patrón de diseño "Arreglar todo"? ¿Cuáles son sus pros y sus contras?

    
pregunta Aaron Hall 19.04.2017 - 17:32

5 respuestas

100

Supongamos que tiene una página HTML que es bastante complicada: si selecciona algo en un menú desplegable, podría aparecer otro control o podrían cambiar los valores de un tercer control. Hay dos formas de abordar esto:

  1. Escriba un controlador independiente, para cada control, que responda a los eventos en ese control y actualice otros controles según sea necesario.

  2. Escriba un solo controlador que observe el estado de todos los controles en la página y solo solucione todo .

La segunda llamada es "idempotente" porque puedes llamarla una y otra vez y los controles siempre estarán organizados correctamente. Mientras que la primera (s) llamada (s) puede tener problemas si una llamada se pierde o se repite, por ejemplo. si uno de los manejadores realiza una alternancia.

La lógica para la segunda llamada sería un poco más oscura, pero solo tienes que escribir un controlador.

Y siempre puede usar ambas soluciones, llamando a la función "arreglar todo" según sea necesario "solo para estar seguro".

El segundo enfoque es especialmente bueno cuando el estado puede provenir de diferentes fuentes, por ejemplo. desde la entrada del usuario frente al renderizado desde el servidor. En ASP.NET, la técnica funciona muy bien con el concepto de devolución de datos porque simplemente ejecuta la función de corrección de todo cada vez que renderiza la página.

Ahora que mencioné los eventos que se están perdiendo o repitiendo, y que se obtienen de diferentes fuentes, creo que es obvio cómo este enfoque se relaciona bien con un espacio problemático como el de BitTorrent.

Contras? Bueno, el inconveniente obvio es que hay un impacto en el rendimiento porque es menos eficiente repasar todo todo el tiempo. Pero una solución como BitTorrent está optimizada para escalar, no escalar, por lo que es bueno para ese tipo de cosas. Dependiendo del problema que intenta resolver, es posible que no sea adecuado para usted.

    
respondido por el John Wu 19.04.2017 - 17:49
15

Creo que el artículo está un poco anticuado porque, mientras lo leo, esta no es realmente una idea poco ortodoxa o nueva. Esta idea se presenta como un patrón separado cuando en realidad es solo una implementación simple de Observer. Recordando lo que estaba haciendo en ese momento, recuerdo que trabajé en lógica para sentarme detrás de una interfaz algo compleja con varios paneles diferentes con datos que eran interdependientes. El usuario podría cambiar los valores y / o ejecutar una rutina de optimización y, en función de esas acciones, se generaron eventos que la interfaz de usuario escucharía y actualizaría según fuera necesario. Hubo una serie de problemas durante el desarrollo donde ciertos paneles no se actualizaron cuando deberían. La solución (permanecer dentro del diseño) era generar eventos de otros eventos. En última instancia, cuando todo funcionaba bien, casi todos los cambios resultaron en la actualización de todos los paneles. La complejidad de tratar de aislar cuando un panel dado necesitaba actualizarse fue en vano. Y no importaba de todos modos. Fue efectivamente una optimización prematura. Habría ahorrado un montón de tiempo y esfuerzo simplemente al colapsarlo todo en un solo evento que lo actualizó todo.

Hay innumerables sistemas diseñados en "arreglar todo" o actualizar todo. Piense en todas las interfaces CRUD que agregan / actualizan una fila y luego vuelva a consultar la base de datos. Este no es un enfoque exótico, es solo la solución obvia no inteligente. Tienes que darte cuenta de que en 2003, fue la altura de la "fiebre de patrón". Por lo que pude ver, la gente pensó que nombrar nuevos patrones iba a ser su camino hacia la fama y la riqueza. No me malinterpretes, creo que el concepto de patrón es extremadamente útil para describir soluciones en abstracto. Las cosas simplemente se salieron un poco de los rieles. Es desafortunado porque creó mucho cinismo sobre el concepto de patrón en general. Es solo en este contexto que tiene sentido hablar de esto como una solución "poco ortodoxa". Es similar a la ortodoxia alrededor de los ORM o los contenedores DI. No usarlos se considera poco ortodoxo, aunque la gente había estado creando software mucho antes de que existieran estas herramientas y en muchos casos esas herramientas son excesivas.

Así que volvamos a 'arreglar todo'. Un ejemplo simple es calcular los medios. La solución simple es sumar números y dividir por la cardinalidad de los valores. Si agrega o modifica un número, simplemente hágalo nuevamente, desde el principio. Puede hacer un seguimiento de la suma y el recuento de números y cuando alguien agrega un número, aumenta el recuento y lo agrega a la suma. Ahora no estás volviendo a agregar todos los números otra vez. Si alguna vez ha trabajado con Excel con una fórmula que hace referencia a un rango y modificó un solo valor en ese rango, tiene un ejemplo del patrón 'arreglar todo', es decir, cualquier fórmula que tenga una referencia a ese rango se recalculará independientemente de si ese valor era relevante (por ejemplo, usando algo como sumif ()).

Esto no quiere decir que no sea una elección inteligente en un contexto dado. En el ejemplo medio, digamos que ahora necesitamos soportar actualizaciones. Ahora necesito saber el valor antiguo de alguna manera y solo cambiar la suma por el delta. Nada de esto es realmente tan desafiante hasta que considere tratar de hacer esto en un entorno distribuido o concurrente. Ahora tiene que manejar todo tipo de problemas de tiempo espinoso y es probable que termine creando un gran cuello de botella que ralentiza las cosas mucho más que recalcular.

El resultado final aquí es que el enfoque de 'arreglar todo' o 'actualizar todo' es mucho más fácil de hacer. Puede hacer que un enfoque más sofisticado funcione, pero es mucho más complicado y por lo tanto es más probable que sea defectuoso. Además, en muchos contextos, el enfoque de "actualizar todo" puede ser más eficiente. Por ejemplo, los enfoques de copia en escritura son generalmente más lentos para los enfoques de un solo hilo, pero cuando tiene una alta concurrencia, puede permitirle evitar bloqueos y, por lo tanto, proporcionar un mejor rendimiento. En otros casos, puede permitirle realizar cambios por lotes de manera eficiente. Por lo tanto, para la mayoría de los problemas, probablemente desee comenzar con un enfoque de actualización de todo a menos que tenga una razón específica por la que no pueda hacerlo y luego preocuparse por hacer algo más complejo una vez que tenga una necesidad. Una implementación de trabajo contra la que puede realizar una prueba de regresión es valiosa en sí misma, incluso si es lenta.

    
respondido por el JimmyJames 19.04.2017 - 19:12
4

No estoy seguro de que sea un "patrón de diseño", pero clasificaría ese tipo de comportamiento como configuración de estado final o configuración de estado deseada , en la vena de Puppet, Chef o Powershell DSC.

Esas soluciones generalmente funcionan en el nivel de administración de sistemas, no en el nivel de lógica de negocios que la pregunta describe, pero en realidad es el mismo paradigma, y aunque tales herramientas son generalmente de naturaleza declarativa, los mismos principios se pueden aplicar en el código de procedimiento. o scripting.

    
respondido por el Dan1701 19.04.2017 - 19:31
1

Lo he usado principalmente en las interfaces de usuario. Lo bueno es que lo escribes una vez, y maneja todo, desde el caso más simple hasta el más difícil, por igual (por ejemplo, si el usuario gira la pantalla o en una computadora portátil o de escritorio si el usuario cambia el tamaño de una ventana y prácticamente todo cambia ).

No hay muchas razones para preocuparse por la eficiencia. En la interfaz de usuario, las cosas caras son cosas como volver a dibujar un elemento que se ha movido. El cálculo donde va cada elemento y qué tan grande es generalmente es bastante rápido. Todo lo que tiene que asegurarse es que cada vez que encuentre que un elemento debe permanecer exactamente en el lugar al que pertenece, no se ejecuta ningún código para moverlo. Los cambios reales son todas las cosas que tenías que hacer de todos modos.

    
respondido por el gnasher729 29.08.2017 - 01:00
0

Suena como principios de programación reactiva. "Arreglar todo" mira el estado "central" actual y propaga todo lo demás que debería verse afectado: "estados computados". Si optimiza esta derivación, puede alcanzar una alta eficiencia, a-la React, si se hace ingenuamente, el rendimiento puede no ser óptimo, aunque podría ser lo suficientemente rápido.

    
respondido por el orip 28.08.2017 - 21:24

Lea otras preguntas en las etiquetas