Was bedeutet der Begriff "Leaky Abstraction"? (Bitte erläutern Sie dies anhand von Beispielen. Es fällt mir oft schwer, eine bloße Theorie zu verstehen.)
programming-languages
functional-programming
memory-leaks
abstraction
leaky-abstraction
Geonne
quelle
quelle
Antworten:
Hier ist ein Meatspace- Beispiel:
Autos haben Abstraktionen für Fahrer. In seiner reinsten Form gibt es ein Lenkrad, ein Gaspedal und eine Bremse. Diese Abstraktion verbirgt viele Details darüber, was sich unter der Motorhaube befindet: Motor, Nocken, Zahnriemen, Zündkerzen, Kühler usw.
Das Schöne an dieser Abstraktion ist, dass wir Teile der Implementierung durch verbesserte Teile ersetzen können, ohne den Benutzer neu zu schulen. Angenommen, wir ersetzen die Verteilerkappe durch eine elektronische Zündung und den festen Nocken durch einen variablen Nocken. Diese Änderungen verbessern die Leistung, aber der Benutzer lenkt immer noch mit dem Rad und verwendet die Pedale zum Starten und Stoppen.
Es ist eigentlich ziemlich bemerkenswert ... ein 16-jähriger oder ein 80-jähriger kann diese komplizierte Maschine bedienen, ohne wirklich viel darüber zu wissen, wie sie im Inneren funktioniert!
Aber es gibt Lecks. Das Getriebe ist ein kleines Leck. In einem Automatikgetriebe spürt man, wie das Auto beim Schalten für einen Moment an Leistung verliert, während man im CVT ein gleichmäßiges Drehmoment spürt.
Es gibt auch größere Lecks. Wenn Sie den Motor zu schnell drehen, können Sie ihn beschädigen. Wenn der Motorblock zu kalt ist, startet das Auto möglicherweise nicht oder hat eine schlechte Leistung. Und wenn Sie gleichzeitig Radio, Scheinwerfer und Klimaanlage ankurbeln, sinkt Ihr Benzinverbrauch.
quelle
Dies bedeutet einfach, dass Ihre Abstraktion einige der Implementierungsdetails verfügbar macht oder dass Sie die Implementierungsdetails kennen müssen, wenn Sie die Abstraktion verwenden. Der Begriff wird Joel Spolsky , circa 2002, zugeschrieben. Weitere Informationen finden Sie im Wikipedia- Artikel .
Ein klassisches Beispiel sind Netzwerkbibliotheken, mit denen Sie entfernte Dateien als lokal behandeln können. Der Entwickler, der diese Abstraktion verwendet, muss sich bewusst sein, dass Netzwerkprobleme dazu führen können, dass dies auf eine Weise fehlschlägt, die lokale Dateien nicht tun. Sie müssen dann Code entwickeln, um bestimmte Fehler außerhalb der von der Netzwerkbibliothek bereitgestellten Abstraktion zu behandeln.
quelle
Wikipedia hat eine ziemlich gute Definition für diese
Mit anderen Worten, für Software können Sie Implementierungsdetails einer Funktion über Einschränkungen oder Nebenwirkungen im Programm beobachten.
Ein schnelles Beispiel wären C # / VB.Net-Schließungen und ihre Unfähigkeit, Ref / Out-Parameter zu erfassen. Der Grund, warum sie nicht erfasst werden können, liegt in einem Implementierungsdetail, wie der Hebevorgang abläuft. Dies bedeutet jedoch nicht, dass es einen besseren Weg gibt, dies zu tun.
quelle
Hier ist ein Beispiel, das .NET-Entwicklern bekannt ist: Die ASP.NET-
Page
Klasse versucht, die Details von HTTP-Vorgängen, insbesondere die Verwaltung von Formulardaten, auszublenden, damit Entwickler sich nicht mit veröffentlichten Werten befassen müssen (da Formulare automatisch dem Server zugeordnet werden Kontrollen).Wenn Sie jedoch über die grundlegendsten Verwendungsszenarien hinausgehen,
Page
beginnt die Abstraktion zu lecken und es wird schwierig, mit Seiten zu arbeiten, es sei denn, Sie verstehen die Implementierungsdetails der Klasse.Ein häufiges Beispiel ist das dynamische Hinzufügen von Steuerelementen zu einer Seite. Der Wert von dynamisch hinzugefügten Steuerelementen wird nur dann für Sie zugeordnet, wenn Sie sie zum richtigen Zeitpunkt hinzufügen : Bevor die zugrunde liegende Engine die eingehenden Formularwerte den entsprechenden Steuerelementen zuordnet. Wenn Sie das lernen müssen, ist die Abstraktion durchgesickert .
quelle
In gewisser Weise ist es eine rein theoretische Sache, wenn auch nicht unwichtig.
Wir verwenden Abstraktionen, um das Verständnis zu erleichtern. Ich kann eine Zeichenfolgenklasse in einer bestimmten Sprache bearbeiten, um die Tatsache zu verbergen, dass es sich um einen geordneten Satz von Zeichen handelt, bei denen es sich um einzelne Elemente handelt. Ich beschäftige mich mit einem geordneten Zeichensatz, um die Tatsache zu verbergen, dass es sich um Zahlen handelt. Ich beschäftige mich mit Zahlen, um die Tatsache zu verbergen, dass ich mit Einsen und Nullen zu tun habe.
Eine undichte Abstraktion ist eine, die die Details, die sie verbergen soll, nicht verbirgt. Wenn Sie string.Length für eine 5-stellige Zeichenfolge in Java oder .NET aufrufen, kann ich aufgrund von Implementierungsdetails, bei denen es sich bei den von diesen Sprachen als Zeichen bezeichneten Zeichen tatsächlich um UTF-16-Datenpunkte handelt, die entweder 1 oder darstellen können, eine Antwort von 5 bis 10 erhalten .5 eines Charakters. Die Abstraktion ist durchgesickert. Wenn Sie es nicht verlieren, bedeutet dies, dass das Ermitteln der Länge entweder mehr Speicherplatz erfordert (um die tatsächliche Länge zu speichern) oder von O (1) zu O (n) wechselt (um die tatsächliche Länge zu ermitteln). Wenn mir die richtige Antwort wichtig ist (oft nicht wirklich), müssen Sie an dem Wissen arbeiten, was wirklich vor sich geht.
Weitere umstrittene Fälle treten in Fällen auf, in denen eine Methode oder Eigenschaft es Ihnen ermöglicht, in das Innenleben einzusteigen, ob es sich um Abstraktionslecks handelt oder ob es sich um genau definierte Wege handelt, um auf eine niedrigere Abstraktionsebene zu gelangen.
quelle
Ich werde weiterhin Beispiele mit RPC nennen.
In der idealen Welt von RPC sollte ein Remote-Prozeduraufruf wie ein lokaler Prozeduraufruf aussehen (so lautet die Geschichte). Es sollte für den Programmierer vollständig transparent sein, damit er beim Aufruf
SomeObject.someFunction()
keine Ahnung hat, obSomeObject
(oder nursomeFunction
für diese Angelegenheit) lokal gespeichert und ausgeführt oder remote gespeichert und ausgeführt werden. Die Theorie besagt, dass dies die Programmierung vereinfacht.Die Realität sieht anders aus, weil es einen RIESIGEN Unterschied gibt zwischen einem lokalen Funktionsaufruf (selbst wenn Sie die am langsamsten interpretierte Sprache der Welt verwenden) und:
Allein in der Zeit sind das drei Größenordnungen (oder mehr!) Der Größenunterschiede. Diese drei Größenordnungen + werden einen großen Unterschied in der Leistung bewirken, der Ihre Abstraktion eines Prozeduraufruflecks ziemlich offensichtlich macht, wenn Sie einen RPC zum ersten Mal fälschlicherweise als echten Funktionsaufruf behandeln. Darüber hinaus weist ein echter Funktionsaufruf, abgesehen von schwerwiegenden Problemen in Ihrem Code, nur sehr wenige Fehlerpunkte außerhalb von Implementierungsfehlern auf. Ein RPC-Anruf weist alle folgenden möglichen Probleme auf, die als Fehlerfälle auftreten und über das hinausgehen, was Sie von einem regulären Ortsgespräch erwarten würden:
Jetzt hat Ihr RPC-Aufruf, der "genau wie ein lokaler Funktionsaufruf" ist, eine ganze Reihe zusätzlicher Fehlerbedingungen, mit denen Sie sich bei lokalen Funktionsaufrufen nicht auseinandersetzen müssen. Die Abstraktion ist wieder durchgesickert, noch härter.
Am Ende ist RPC eine schlechte Abstraktion, weil es auf jeder Ebene wie ein Sieb leckt - wenn es erfolgreich ist und wenn beide fehlschlagen.
quelle
Ein Beispiel im Django ORM Viele-zu-Viele-Beispiel :
Beachten Sie in der Beispiel-API-Verwendung, dass Sie das Basisartikelobjekt a1 speichern müssen, bevor Sie dem Many-to-Many-Attribut Publikationsobjekte hinzufügen können. Beachten Sie, dass das Aktualisieren des Many-to-Many-Attributs sofort in der zugrunde liegenden Datenbank gespeichert wird, während das Aktualisieren eines einzelnen Attributs erst in der Datenbank angezeigt wird, wenn .save () aufgerufen wird.
Die Abstraktion besteht darin, dass wir mit einem Objektdiagramm arbeiten, bei dem Einzelwertattribute und Mehrwertattribute nur Attribute sind. Die Implementierung als relationaler datenbankgestützter Datenspeicher ist jedoch undicht ... da das Integritätssystem des RDBS durch das dünne Furnier einer Objektschnittstelle angezeigt wird.
quelle
Was ist Abstraktion?
Zunächst ist es am besten zu verstehen, was "Abstraktion" ist?
Abstraktion ist ein Weg, die Welt zu vereinfachen. Sie müssen sich also keine Gedanken darüber machen, was tatsächlich unter der Motorhaube / hinter dem Vorhang passiert. Es bedeutet, dass etwas idiotensicher ist. Ok, was bedeutet das? Dies lässt sich am besten anhand eines Beispiels veranschaulichen.
Beispiel für Abstraktion: Die Komplexität des Fliegens einer 737/747 wird "abstrahiert"
Nehmen wir das Beispiel eines Boeing-Passagierflugzeugs. Diese Flugzeuge sind sehr komplizierte Maschinen. Sie haben Düsentriebwerke, Sauerstoffsysteme, elektrische Systeme, Fahrwerkssysteme usw., aber der Pilot muss sich nicht um die Feinheiten des Düsentriebwerks kümmern ... alles, was "weg abstrahiert" ist, was bedeutet: am Ende von An diesem Tag macht sich ein Pilot nur Sorgen um das Rad und eine Kontrollsäule, um das Flugzeug zu steuern. Links nach links und rechts nach rechts, nach oben ziehen, um die Höhe zu erreichen, und nach unten drücken, um abzusteigen. Es ist einfach genug ...... eigentlich habe ich gelogen: Die Steuerung des Lenkrads ist etwas komplizierter. In einer idealen Welt ist das das einzige, was er solltemach dir Sorgen. Im wirklichen Leben ist dies jedoch nicht der Fall: Wenn Sie ein Flugzeug wie einen Affen fliegen, ohne wirklich zu verstehen, wie ein Flugzeug funktioniert oder welche Implementierungsdetails vorliegen, werden Sie wahrscheinlich alle an Bord abstürzen und töten.
Undichte Abstraktionen
In Wirklichkeit muss sich ein Pilot um eine Menge wichtiger Dinge kümmern - nicht alles wurde weg abstrahiert: Piloten müssen sich um Windgeschwindigkeit, Schub, Anstellwinkel, Treibstoff, Höhe, Wetterprobleme, Abstiegswinkel kümmern, ob die Der Pilot geht in die richtige Richtung, wo sich das Flugzeug gerade befindet und so weiter. Computer können dem Piloten bei diesen Aufgaben helfen, aber nicht alles ist automatisiert / vereinfacht.
Beispiel: Wenn der Pilot zu stark an der Säule vorfährt, gehorcht das Flugzeug, aber dann riskiert der Pilot, das Flugzeug zum Stillstand zu bringen. Wenn Sie das Flugzeug zum Stillstand bringen, ist es möglicherweise schwierig, die Kontrolle wiederzugewinnen, bevor es wieder auf den Boden stürzt .
Mit anderen Worten, es reicht nicht aus, dass der Pilot einfach das Lenkrad steuert, ohne etwas anderes zu wissen ......... nooooo ....... sie muss über die zugrunde liegenden Risiken und Einschränkungen des Flugzeugs Bescheid wissen bevor er einen fliegt ....... muss sie wissen, wie das Flugzeug funktioniert und wie das Flugzeug fliegt; Er muss die Implementierungsdetails kennen. Sie muss wissen, dass ein zu starkes Hochziehen zu einem Stillstand führt oder dass eine zu steile Landung das Flugzeug zerstört.
Diese Dinge werden nicht weg abstrahiert. Viele Dinge werden weg abstrahiert, aber nicht alles. Der Pilot muss sich nur um die Lenksäule und vielleicht ein oder zwei andere Dinge kümmern. Die Abstraktion ist "undicht".
...... es ist dasselbe in deinem Code. Wenn Sie die zugrunde liegenden Implementierungsdetails nicht kennen, arbeiten Sie sich meistens selbst in eine Ecke.
Hier ist ein Beispiel für die Codierung:
ORMs abstrahieren viel Ärger beim Umgang mit Datenbankabfragen, aber wenn Sie jemals etwas getan haben wie:
Dann werden Sie feststellen, dass dies eine gute Möglichkeit ist, Ihre App zu beenden, wenn Sie mehr als ein paar Millionen Benutzer haben. Nicht alles wird weg abstrahiert. Sie müssen wissen, dass Anrufe
User.all
mit 25 Millionen Benutzern Ihre Speichernutzung erhöhen und Probleme verursachen werden. Sie müssen einige zugrunde liegende Details kennen. Die Abstraktion ist undicht.quelle
Die Tatsache, dass Sie sich irgendwann , abhängig von Ihrer Größe und Ausführung, mit den Implementierungsdetails Ihres Abstraktionsframeworks vertraut machen müssen, um zu verstehen, warum es sich so verhält, wie es sich verhält.
Betrachten Sie beispielsweise diese
SQL
Abfrage:Und seine Alternative:
Jetzt sehen sie wie logisch äquivalente Lösungen aus, aber die Leistung der ersten Lösung ist aufgrund der Angabe der einzelnen Spaltennamen besser.
Es ist ein triviales Beispiel, aber schließlich kommt es auf Joel Spolsky Zitat zurück:
Wenn Sie irgendwann einen bestimmten Maßstab in Ihrem Betrieb erreichen, möchten Sie die Funktionsweise Ihrer Datenbank (SQL) optimieren. Dazu müssen Sie wissen, wie relationale Datenbanken funktionieren. Es wurde Ihnen am Anfang abstrahiert, aber es ist undicht. Sie müssen es irgendwann lernen.
quelle
Angenommen, wir haben den folgenden Code in einer Bibliothek:
Wenn der Verbraucher die API aufruft, erhält er ein Objekt []. Der Verbraucher muss verstehen, dass das erste Feld des Objektarrays einen Farbwert und das zweite Feld den Modellwert hat. Hier ist die Abstraktion von der Bibliothek zum Consumer-Code durchgesickert.
Eine der Lösungen besteht darin, ein Objekt zurückzugeben, das Modell und Farbe des Geräts kapselt. Der Verbraucher kann dieses Objekt aufrufen, um das Modell und den Farbwert abzurufen.
quelle
Bei einer undichten Abstraktion geht es darum, den Zustand zu kapseln. sehr einfaches Beispiel für eine undichte Abstraktion:
und der richtige Weg (keine undichte Abstraktion):
Weitere Beschreibung hier .
quelle