Was ist das Entwurfsmuster "Alles reparieren"?

74

In diesem Artikel von Stephen Figgins aus dem Jahr 2003 auf linuxdevcenter.com wird Bram Cohens BitTorrent mit dem Entwurfsmuster "Fix Everything" beschrieben.

Ein weniger verbreiteter Ansatz, der es erschwert, BitTorrent zu verstehen, der es jedoch wert ist, untersucht zu werden, ist Cohens Gebrauch von Idempotenz. Ein Prozess ist idempotent, wenn er mehr als einmal angewendet wird und keine weiteren Änderungen hervorruft. Cohen sagt, er benutze ein Entwurfsmuster, das er "Fix Everything" nennt, eine Funktion, die auf eine Reihe von Änderungen reagieren kann, ohne wirklich zu merken, was sich alles ändern könnte. Er erklärt: "Sie notieren das Ereignis, das passiert ist, und rufen dann die Funktion fix everything auf, die auf diese sehr idempotente Weise geschrieben wurde. Bereinigen Sie einfach alle Vorgänge und berechnen Sie alles von Grund auf neu." Während Idempotenz einige schwierige Berechnungen erleichtert, macht es die Dinge ein wenig verworren. Es ist nicht immer klar, was ein Anruf ändern wird, wenn überhaupt. Sie müssen nicht im Voraus wissen. Sie können die Funktion aufrufen,

Das klingt auf den ersten Blick ganz gut.

Es scheint mir jedoch, dass das Aufrufen einer idempotenten Funktion "Alles reparieren" die Robustheit des Systems auf Kosten der Effizienz verbessern und möglicherweise das enthaltene System vermasseln würde (was möglicherweise Prozesse vorziehen würde, die sorgfältig planen und ausführen).

Ich kann aber nicht sagen, dass ich es schon einmal benutzt habe. Ich kann die Quelle für seine Bewerbung auch nicht online finden (aber ich habe diese gefunden , die behauptet, darauf zu basieren.). Ich kann auch keinen Verweis außerhalb dieses Artikels finden (und ich halte mein google-fu für ziemlich gut), aber ich habe auf SOApatterns.org einen Eintrag für "Idempotent Capability" gefunden .

Ist diese Idee besser unter einem anderen Namen bekannt?

Was ist das Entwurfsmuster "Alles reparieren"? Was sind ihre Vor- und Nachteile?

Aaron Hall
quelle
4
Ich vermute, der Name ist auch ein Hinweis auf die Idee des Fixpunkts einer Funktion, x = f (x). Egal wie oft Sie f auf x anwenden , das Ergebnis ist das gleiche. Sobald Sie das richtige Ergebnis erzielt haben, wird bei erneuter Verarbeitung des richtigen Ergebnisses dasselbe richtige Ergebnis zurückgegeben.
9.
7
Beachten Sie, dass jeder beliebige Namen vergeben kann, dies macht es jedoch nicht zu einem bekannten Softwaremuster. Idempotenz ist ein bekanntes Konzept für sich; es sieht einfach so aus, als würde es hier kreativ eingesetzt.
Robert Harvey
1
Dies erinnert mich daran, wie der Main Event Loop unter Mac OS implementiert wurde. Es war eine einzelne Funktion, die auf jedes Ereignis reagierte und im Allgemeinen so strukturiert war, dass sie den Status aller Steuerelemente testete und die gesamte Benutzeroberfläche nach Bedarf aktualisierte. In der Tat idempotent.
Lucas
3
This sounds quite nice on the face of it. "Ja wirklich?" Es klingt für mich schrecklich!
Michael
3
@Michael Du magst keine Paketmanager? Sie funktionieren nach dem gleichen Konzept, nur in kleinerem Maßstab: Markieren Sie, wie das System aussehen soll, führen Sie "Alles reparieren" aus, es installiert / entfernt / aktualisiert je nach Bedarf, hat aber nur dann etwas zu tun, wenn Änderungen vorgenommen wurden.
Izkata

Antworten:

100

Angenommen, Sie haben eine HTML-Seite, die ziemlich kompliziert ist. Wenn Sie in einer Dropdown-Liste etwas auswählen, wird möglicherweise ein anderes Steuerelement angezeigt, oder die Werte in einem dritten Steuerelement ändern sich. Es gibt zwei Möglichkeiten, wie Sie dies angehen können:

  1. Schreiben Sie für jedes Steuerelement einen eigenen Handler, der auf Ereignisse in diesem Steuerelement reagiert und andere Steuerelemente nach Bedarf aktualisiert.

  2. Schreiben Sie einen einzelnen Handler, der den Status aller Steuerelemente auf der Seite überprüft und einfach alles korrigiert .

Der zweite Aufruf ist "idempotent", da Sie ihn immer wieder aufrufen können und die Steuerelemente immer richtig angeordnet sind. Während der erste Anruf Probleme haben kann, wenn ein Anruf verloren geht oder wiederholt wird, z. B. wenn einer der Bearbeiter eine Umschaltung vornimmt.

Die Logik für den zweiten Aufruf wäre etwas unklarer, aber Sie müssen nur einen Handler schreiben.

Und Sie können immer beide Lösungen verwenden und die Funktion "Alles reparieren" nach Bedarf aufrufen, "nur um auf der sicheren Seite zu sein."

Der zweite Ansatz ist besonders nützlich, wenn der Status aus verschiedenen Quellen stammen kann, z. B. aus Benutzereingaben im Vergleich zu vom Server gerenderten. In ASP.NET spielt die Technik sehr gut mit dem Konzept des Postbacks zusammen, da Sie beim Rendern der Seite nur die Funktion "Alles reparieren" ausführen.

Nachdem ich erwähnt habe, dass Ereignisse verloren gehen oder wiederholt werden und aus verschiedenen Quellen einen Status erhalten, ist es meiner Meinung nach offensichtlich, wie sich dieser Ansatz gut auf einen Problembereich wie den von BitTorrent übertragen lässt.

Nachteile? Das offensichtliche Manko ist, dass es einen Performance-Hit gibt, weil es weniger effizient ist, die ganze Zeit über alles zu gehen. Aber eine Lösung wie BitTorrent ist so optimiert, dass sie skaliert und nicht skaliert, also ist es gut für so etwas. Je nachdem, welches Problem Sie lösen möchten, ist es möglicherweise nicht für Sie geeignet.

John Wu
quelle
9
Es scheint mir, dass MVC typisch für "Fix Everything" ist: Wenn Sie das Modell ändern und dann die Ansicht von Grund auf neu zeichnen, wird die Ansicht nur vollständig neu gezeichnet, ohne zu erraten, welche Teile die Aktion möglicherweise beeinflusst haben könnte.
Matthieu M.
3
Dies klingt im Wesentlichen nach dem Prinzip hinter Systemen wie Saltstack, Ansible und Nix. Bei einer gegebenen Beschreibung einer Konfiguration können Sie theoretisch mehrere verschiedene Systeme in den gleichen Endzustand bringen.
Kojiro
1
@MatthieuM. React , das in der Frontend-Entwicklung sehr beliebt ist, ist ähnlich, außer dass es sich um ein anderes virtuelles Doming handelt, sodass nur das reale
Doming
2
@ Izkata Noch mehr als Reagieren, diese Antwort ließ mich an Redux denken.
Kevin
2
Es kann nützlich sein, darauf hinzuweisen, dass "alles reparieren" und "idempotent" verschiedene Dinge sind: "alles reparieren" ist normalerweise idempotent (muss es aber nicht sein), und idempotente Operationen müssen nicht alles reparieren oder sogar eine Leistung erbringen Penalty - Gib nur das gleiche Ergebnis, wenn du es zweimal ausführst.
Hans-Peter Störr
15

Ich denke, der Artikel ist ein bisschen veraltet, da dies beim Lesen keine wirklich unorthodoxe oder neue Idee ist. Diese Idee wird als separates Muster dargestellt, wenn es sich tatsächlich nur um eine einfache Observer-Implementierung handelt. Wenn ich an meine damaligen Aktivitäten zurückdenke, erinnere ich mich, dass ich an der Logik gearbeitet habe, um hinter einer etwas komplexen Schnittstelle mit einer Reihe verschiedener Panels mit Daten zu sitzen, die voneinander abhängig waren. Der Benutzer konnte Werte ändern und / oder eine Optimierungsroutine ausführen, und basierend auf diesen Aktionen wurden Ereignisse generiert, die die Benutzeroberfläche abhören und bei Bedarf aktualisieren würde. Während der Entwicklung gab es eine Reihe von Problemen, bei denen bestimmte Panels nicht aktualisiert wurden, wenn sie sollten. Der Fix bestand darin, Ereignisse aus anderen Ereignissen zu generieren. Letztendlich funktionierte zu der Zeit alles richtig, Fast jede Änderung führte dazu, dass alle Bereiche aktualisiert wurden. Die ganze Komplexität des Versuchs zu isolieren, wann ein bestimmtes Panel aktualisiert werden musste, war umsonst. Und es war sowieso egal. Es war effektiv eine vorzeitige Optimierung. Ich hätte eine Menge Zeit und Mühe gespart, indem ich alles zu einem einzigen Ereignis zusammengefasst hätte, das alles auffrischt.

Es gibt unzählige Systeme, die entwickelt wurden, um "alles zu reparieren" oder alles aufzufrischen. Denken Sie an alle CRUD-Schnittstellen, die eine Zeile hinzufügen / aktualisieren und dann die Datenbank erneut abfragen. Dies ist kein exotischer Ansatz, sondern nur die offensichtliche, nicht clevere Lösung. Man muss erkennen, dass es 2003 die Höhe des "Musterfiebers" war. Soweit ich es beurteilen konnte, dachten die Leute, dass das Benennen neuer Muster ihr Weg zu Ruhm und Reichtum sein würde. Verstehen Sie mich nicht falsch, ich denke, das Konzept eines Musters ist äußerst nützlich, um abstrakte Lösungen zu beschreiben. Die Dinge sind ein bisschen von den Schienen gerutscht. Es ist bedauerlich, weil es eine Menge Zynismus in Bezug auf das Musterkonzept im Allgemeinen ausgelöst hat. Nur in diesem Zusammenhang ist es sinnvoll, von einer „unorthodoxen“ Lösung zu sprechen. Es' s ähnlich der Orthodoxie um ORMs oder DI-Container. Sie nicht zu verwenden, wird als unorthodox angesehen, obwohl die Leute schon lange vor der Existenz dieser Tools Software entwickelt haben und in vielen Fällen sind diese Tools übertrieben.

Also zurück zu "alles reparieren". Ein einfaches Beispiel sind Rechenmittel. Die einfache Lösung besteht darin, Zahlen zu summieren und durch die Kardinalität der Werte zu dividieren. Wenn Sie eine Nummer hinzufügen oder ändern, wiederholen Sie dies einfach von Anfang an. Sie können die Summe und die Anzahl der Zahlen verfolgen. Wenn jemand eine Zahl hinzufügt, erhöhen Sie die Anzahl und fügen sie der Summe hinzu. Jetzt fügen Sie nicht alle Nummern erneut hinzu. Wenn Sie jemals mit Excel mit einer Formel gearbeitet haben, die auf einen Bereich verweist, und einen einzelnen Wert in diesem Bereich geändert haben, haben Sie ein Beispiel für das Muster "Alles reparieren", dh jede Formel, die auf diesen Bereich verweist, wird neu berechnet, unabhängig davon, ob Dieser Wert war relevant (z. B. mit etwas wie sumif ()).

Das soll nicht heißen, dass dies in einem gegebenen Kontext keine kluge Wahl ist. Nehmen wir im mittleren Beispiel an, wir müssen jetzt Updates unterstützen. Jetzt muss ich den alten Wert irgendwie kennen und nur die Summe um das Delta ändern. Nichts davon ist wirklich herausfordernd, bis Sie in Betracht ziehen, dies in einer verteilten oder gleichzeitigen Umgebung zu tun. Sie müssen sich jetzt mit allen möglichen heiklen Timing-Problemen auseinandersetzen und es kommt wahrscheinlich zu einem großen Engpass, der die Dinge weitaus langsamer macht als eine Neuberechnung.

Das Fazit hier ist, dass es viel einfacher ist, alles zu reparieren oder alles zu aktualisieren, um es richtig zu machen. Sie können eine ausgefeiltere Herangehensweise verwenden, diese ist jedoch viel komplizierter und daher mit größerer Wahrscheinlichkeit fehlerhaft. Darüber hinaus kann in vielen Kontexten der Ansatz "Alles auffrischen" effizienter sein. Copy-on-Write-Ansätze sind beispielsweise bei Single-Thread-Ansätzen im Allgemeinen langsamer. Wenn Sie jedoch eine hohe Parallelität haben, können Sie Sperren vermeiden und somit eine bessere Leistung erzielen. In anderen Fällen können Sie Änderungen auf effiziente Weise stapeln. Bei den meisten Problemen möchten Sie wahrscheinlich mit dem Ansatz "Alles aktualisieren" beginnen, es sei denn, Sie haben einen bestimmten Grund, warum Sie dies nicht tun können, und sich dann darum kümmern, etwas Komplexeres zu tun, sobald Sie einen Bedarf haben.

JimmyJames
quelle
2
Ich bin mir ziemlich sicher, dass Excel nur Zellen neu berechnen möchte , die von Änderungen abhängig sind. Aus diesem Grund gibt es eine Möglichkeit, die Neuberechnung aller Zellen auszulösen: superuser.com/questions/448376/… )
Aaron Hall
@AaronHall Wenn ja, ist es eine wirklich schlechte Implementierung. Ich beobachte regelmäßig, wie es 15-30 Minuten lang 100% von 7 CPUs verbraucht, um zB 60.000 Zellen zu berechnen. Die Berechnungen sind nicht kompliziert. Ich habe oft Python-Programme geschrieben, die in wenigen Sekunden alles im Blatt erledigen können, einschließlich des Startens von Python. Dies war meine beste Vermutung, wie lange es dauern könnte. Es könnte etwas anderes sein, nehme ich an. Es gibt auch eine Reihe von wirklich alten Fehlern in Excel, die der Grund für diese Funktion sein könnten.
JimmyJames
1
@AaronHall Mit diesem Benutzer ist es auch möglich, dass die automatische Berechnung auf dem Blatt deaktiviert wurde. Ich mache das oft bei großen Arbeitsmappen, weil ich nicht jedes Mal 15 Minuten Zeit habe, wenn ich die Eingabetaste drücke.
JimmyJames
@ AaronHall Ich dachte ein bisschen mehr und du hast einen Punkt. Meine Annahmen waren wahrscheinlich zu weit gefasst. Ich habe die Antwort aktualisiert und mich mehr auf etwas konzentriert, in das ich selbstbewusster bin.
JimmyJames,
2
@JimmyJames: Der Punkt, den ich ansprechen wollte, ist, dass der beste Ansatz je nach den Umständen sehr unterschiedlich sein kann und "alles reparieren" unterteilt werden kann in "alles eifrig bei jeder einzelnen Änderung reparieren" und "alles träge reparieren, nachdem alle Änderungen abgeschlossen sind ".
Supercat
4

Ich bin nicht sicher, ob es sich um ein "Entwurfsmuster" handelt, aber ich würde diese Art von Verhalten als Endzustandskonfiguration oder gewünschte Zustandskonfiguration klassifizieren , im Sinne von Puppet, Chef oder Powershell DSC.

Diese Lösungen werden in der Regel auf der Ebene des Systemmanagements ausgeführt, nicht auf der Ebene der Geschäftslogik, wie in der Frage beschrieben, aber es handelt sich im Grunde genommen um dasselbe Paradigma. Obwohl solche Tools in der Regel deklarativer Natur sind, können dieselben Prinzipien in prozeduralen Codes oder Skripten angewendet werden.

Dan1701
quelle
1

Ich habe dies meistens in Benutzeroberflächen verwendet. Das Schöne ist, dass Sie es einmal schreiben und es alles vom einfachsten bis zum schwierigsten Fall gleich gut handhabt (zum Beispiel, wenn der Benutzer den Bildschirm dreht, oder auf einem Laptop / Desktop, wenn der Benutzer die Größe eines Fensters ändert, und praktisch alles ändert sich ).

Es gibt nicht viel Grund, sich um die Effizienz Sorgen zu machen. In der Benutzeroberfläche handelt es sich bei den teuren Dingen um das Neuzeichnen eines verschobenen Elements. Die Berechnung, wohin jedes Element geht und wie groß es ist, ist normalerweise recht schnell. Alles, worauf Sie achten müssen, ist, dass immer, wenn Sie feststellen, dass ein Objekt genau dort bleiben soll, wo es hingehört, kein Code ausgeführt wird, um es zu verschieben. Die wirklichen Veränderungen sind alles Dinge, die Sie sowieso tun mussten.

gnasher729
quelle
0

Klingt nach reaktiven Programmierprinzipien. "Fix everything" betrachtet den aktuellen "Core" -Zustand und überträgt alles, was betroffen sein sollte - "Computed States". Wenn Sie diese Ableitung optimieren, kann sie eine hohe Effizienz erreichen, a-la-React, wenn sie naiv durchgeführt wird, ist die Leistung möglicherweise nicht optimal, obwohl sie immer noch schnell genug sein kann.

orip
quelle