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 entender, pero digno de estudio, es el uso de la idempotencia por parte 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 que llama "Arreglar todo", una función que puede reaccionar a una serie de cambios sin notar realmente todo lo que podría cambiar. Él explica, "usted nota el evento que sucedió, luego llama a la función arreglar todo que está escrita de esta manera tan idempotente, y simplemente limpia lo que pueda estar pasando y lo recalcula todo desde cero". Si bien la idempotencia facilita algunos cálculos difíciles, hace que las cosas sean un poco complicadas. No siempre está claro qué va a cambiar una llamada, en todo caso. No necesita saber de antemano. Eres libre de llamar a la función,
Esto suena bastante bien a primera vista.
Sin embargo, me parece que llamar a una función idempotente de "arreglar todo" mejoraría la robustez del sistema a costa de la eficiencia y potencialmente arruinaría el sistema contenedor (que podría preferir procesos que planifiquen y ejecuten cuidadosamente).
Sin embargo, no puedo decir que lo haya usado antes. Tampoco puedo encontrar la fuente de su solicitud en línea (pero 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 .
¿Es esta idea mejor conocida por otro nombre?
¿Qué es el patrón de diseño "Arreglar todo"? ¿Cuáles son sus pros y sus contras?
fuente
This sounds quite nice on the face of it.
De Verdad? ¡Suena horrible para mí!Respuestas:
Supongamos que tiene una página HTML que es bastante complicada: si elige algo en un menú desplegable, puede aparecer otro control o los valores en un tercer control pueden cambiar. Hay dos formas de abordar esto:
Escriba un controlador separado, para cada control, que responda a eventos en ese control y actualice otros controles según sea necesario.
Escriba un solo controlador que observe el estado de todos los controles en la página y simplemente arregle todo .
La segunda llamada es "idempotente" porque puede llamarla una y otra vez y los controles siempre se organizarán correctamente. Mientras que la (s) primera (s) llamada (s) pueden tener problemas si una llamada se pierde o se repite, por ejemplo, si uno de los manejadores realiza un cambio.
La lógica para la segunda llamada sería un poco más oscura, pero solo tiene 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, de la entrada del usuario frente a la del servidor. En ASP.NET, la técnica juega muy bien con el concepto de devolución de datos porque solo ejecuta la función arreglar todo cada vez que renderiza la página.
Ahora que mencioné que los eventos se perdieron o se repitieron y obtuvieron estados de diferentes fuentes, creo que es obvio cómo este enfoque se asigna bien a un espacio problemático como el de BitTorrent.
¿Contras? Bueno, la desventaja obvia es que hay un impacto en el rendimiento porque es menos eficiente revisar 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 intente resolver, puede que no sea adecuado para usted.
fuente
Creo que el artículo está un poco anticuado porque, al leerlo, no es una idea poco ortodoxa o nueva. Esta idea se presenta como un patrón separado cuando realmente es solo una implementación simple de Observer. Pensando en lo que estaba haciendo en ese momento, recuerdo trabajar en la 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 en los que ciertos paneles no se actualizaron cuando deberían. La solución (permanecer dentro del diseño) fue generar eventos a partir de otros eventos. Finalmente, para cuando todo funcionaba bien, Casi todos los cambios dieron como resultado la actualización de todos los paneles. Toda la complejidad de tratar de aislar cuando un panel determinado necesitaba actualizarse fue en vano. Y no importó de todos modos. Fue efectivamente una optimización prematura. Hubiera ahorrado un montón de tiempo y esfuerzo simplemente colapsando todo en un solo evento que refrescó todo.
Hay innumerables sistemas diseñados en el "arreglar todo" o actualizar todo. Piense en todas las interfaces CRUD que agregan / actualizan una fila y luego solicitan la base de datos. Este no es un enfoque exótico, es solo la obvia solución no inteligente. Tienes que darte cuenta de que en 2003, era el colmo de la "fiebre del patrón". Por lo que pude ver, la gente pensó que nombrar nuevos patrones sería su camino hacia la fama y la riqueza. No me malinterpreten, creo que el concepto de un patrón es extremadamente útil para describir soluciones en abstracto. Las cosas se salieron un poco de los rieles. Es lamentable 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'. Eso' s similar a la ortodoxia alrededor de los ORM o contenedores DI. No usarlos se considera poco ortodoxo a pesar de que las personas habían estado construyendo 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 medios. La solución simple es sumar números y dividirlos por la cardinalidad de los valores. Si agrega o modifica un número, simplemente vuelva a hacerlo, desde el principio. Puede realizar 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á volviendo a agregar todos los números nuevamente. Si alguna vez trabajó 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 volverá a calcular 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, digamos que ahora necesitamos admitir actualizaciones. Ahora necesito saber el valor anterior de alguna manera y solo cambiar la suma por el delta. Nada de esto es realmente tan desafiante hasta que considere intentar hacer esto en un entorno distribuido o concurrente. Ahora tiene que manejar todo tipo de problemas de tiempo espinoso y probablemente terminará creando un cuello de botella importante que ralentiza las cosas mucho más que volver a calcular.
El resultado aquí es que es mucho más fácil acertar con el enfoque de "arreglar todo" o "actualizar todo". Puede hacer que un enfoque más sofisticado funcione, pero es mucho más complicado y, por lo tanto, es más probable que tenga fallas. 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 subproceso único, pero cuando tiene una alta concurrencia, puede permitirle evitar bloqueos y, por lo tanto, proporcionar un mejor rendimiento. En otros casos, puede permitirle agrupar cambios de manera eficiente. Entonces, para la mayoría de los problemas, es probable que desee comenzar con un enfoque de actualización de todo, a menos que tenga una razón específica por la que no puede hacerlo y luego se preocupe por hacer algo más complejo una vez que lo necesite.
fuente
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 línea de Puppet, Chef o Powershell DSC.
Esas soluciones generalmente operan a nivel de administración de sistemas, no a nivel de lógica de negocios como se describe en la pregunta, pero es efectivamente el mismo paradigma, y aunque tales herramientas son generalmente de naturaleza declarativa, los mismos principios se pueden aplicar en código de procedimiento o secuencias de comandos.
fuente
Lo he usado principalmente en las interfaces de usuario. Lo bueno es que lo escribe una vez, y maneja todo, desde el caso más simple hasta el más difícil, igualmente bien (por ejemplo, si el usuario gira la pantalla, o en una computadora portátil / 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 de dónde va cada elemento y qué tan grande es generalmente es bastante rápido. Todo lo que debe asegurarse es que cada vez que encuentre que un elemento debe permanecer exactamente en el lugar donde pertenece, no se ejecuta ningún código para moverlo. Los cambios reales son todas las cosas que tenía que hacer de todos modos.
fuente
Suena como principios de programación reactiva. "Arreglar todo" examina el estado "núcleo" actual y propaga todo lo demás que debería verse afectado: "estados calculados". 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.
fuente