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?
quelle
This sounds quite nice on the face of it.
"Ja wirklich?" Es klingt für mich schrecklich!Antworten:
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:
Schreiben Sie für jedes Steuerelement einen eigenen Handler, der auf Ereignisse in diesem Steuerelement reagiert und andere Steuerelemente nach Bedarf aktualisiert.
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle