Was meinte Rich Hickey, als er sagte: "All diese Spezifität [von Schnittstellen / Klassen / Typen] tötet Ihre Wiederverwendung!"

41

In Rich Hickeys zum Nachdenken anregendem Hauptvortrag " The Value of Values " (29 Minuten) spricht er über den Overhead einer Sprache wie Java und erklärt: "Alle diese Schnittstellen töten Ihre Wiederverwendung." Was meint er? Ist das wahr?

Auf meiner Suche nach Antworten bin ich auf folgendes gestoßen:

  • Das Prinzip des geringsten Wissens AKA Das Gesetz von Demeter, das luftdichte API-Schnittstellen fördert. Wikipedia listet auch einige Nachteile auf.

  • Kevlin Henneys Imperial Clothing Crisis, die argumentiert, dass die Verwendung, nicht die Wiederverwendung, das angemessene Ziel ist.

  • Jack Diederichs " Stop Writing Classes " -Rede spricht sich generell gegen Überentwicklung aus.

Offensichtlich ist alles, was schlecht genug geschrieben wurde, nutzlos. Aber wie würde die Schnittstelle einer gut geschriebenen API verhindern, dass dieser Code verwendet wird? Es gibt in der Geschichte Beispiele dafür, dass etwas, das für einen bestimmten Zweck gemacht wurde, mehr für etwas anderes verwendet wird . Aber in der Softwarewelt bricht es normalerweise zusammen, wenn Sie etwas für einen Zweck verwenden, für den es nicht vorgesehen war.

Ich suche ein gutes Beispiel für eine gute Schnittstelle, die eine legitime, aber unbeabsichtigte Verwendung von Code verhindert. Existiert das? Ich kann es mir nicht vorstellen.

GlenPeterson
quelle
1
Sie haben das Zeug nicht gesehen / gelesen (ich habe "Stop Writing Classes" zu meiner To-Watch-Liste hinzugefügt :)), aber vielleicht streiten sie sich aus einem dynamischen oder statischen Tippwinkel? ...nochmal?
Andres F.
oO Application Programming Interface-Schnittstellen
Thomas Eding
Danke für die Links! Ich fand Jack Diederichs Vortrag nicht besonders aufschlussreich (sehen Sie, wie er die echten Fragen des Publikums nicht überzeugend beantwortet ... "äh, ja, vielleicht in diesem Fall ..." Mir gefiel es, als würde er für funktionale Programmierung ohne argumentieren Ich habe es sogar bemerkt;)), aber die "Imperial Clothing Crisis" ist sehr gut und aufschlussreich.
Andres F.
1
MPO ist, dass Leute, die nicht an Wiederverwendung glauben, die Dinge nicht in ausreichend kleine Einheiten aufteilen. Eine große Sache, die für einen bestimmten Zweck gebaut wurde, kann nicht wiederverwendet werden. Kleine Dinge haben jedoch normalerweise einen Zweck, der klein genug ist, damit der kleine Zweck in mehr als einem Kontext nützlich ist.
Amy Blankenship
1
@AmyBlankenship Ich fand die oben verlinkte "Imperial Clothing Crisis" aufschlussreich. Der Autor betrachtet die "Wiederverwendung" als falsches Idol (etwas, das sich in der Praxis nicht als nützlich erwiesen hat, und auch die meisten Leute verstehen es nicht einmal, obwohl sie das Wort verwenden). Er betrachtet Bibliotheken auch nicht als "Wiederverwendung"; Sie verwenden eine Bibliothek, die Sie nicht wieder verwenden es. Er denkt auch darüber nach, etwas für die Wiederverwendung "ein zweischneidiges Schwert" zu entwerfen. Etwas, das die Leute normalerweise als Win-Win-Situation betrachten, das es aber nicht ist: Wenn Sie etwas zur Wiederverwendung entwerfen, ist es immer ein Kompromiss (z. B. verlieren Sie möglicherweise an Einfachheit)
Andres F.

Antworten:

32

Ich habe die vollständige Präsentation von Rich Hickey noch nicht gesehen, aber wenn ich ihn richtig verstehe und nach seinen Aussagen zur 29-Minuten-Marke urteile, scheint er über Typen zu streiten , die die Wiederverwendung töten. Er verwendet den Begriff "Schnittstelle" lose als Synonym für "benannten Typ", was Sinn macht.

Wenn Sie zwei Entitäten { "name":"John" }vom Typ Personund { "name": "Rover" }vom Typ Dogin Java-Land haben, können sie wahrscheinlich nicht zusammenarbeiten, es sei denn, sie teilen sich eine gemeinsame Schnittstelle oder einen gemeinsamen Vorfahren (wie z. B. Mammaldas Schreiben von mehr Code). So die Schnittstellen / hier Typen sind „Tötung Ihre Wiederverwendung“: obwohl Personund Doggleich aussehen, kann man nicht austauschbar mit anderen verwendet werden, es sei denn , Sie zusätzlichen Code schreiben, zu unterstützen. Hinweis: Hickey macht auch Witze über Projekte in Java, die viele Klassen benötigen ("Wer hat hier eine Java-Anwendung mit nur 20 Klassen geschrieben?"), Was eine Konsequenz des oben Gesagten zu sein scheint.

In "wertorientierten" Sprachen weisen Sie diesen Strukturen jedoch keine Typen zu. Es handelt sich nur um Werte, die zufällig dieselbe Struktur haben (in meinem Beispiel haben beide ein nameFeld mit einem String-Wert) und können daher problemlos zusammenarbeiten, z. B. können sie derselben Sammlung hinzugefügt, denselben Methoden übergeben usw. werden.

Zusammenfassend scheint dies alles etwas über strukturelle Gleichheit im Vergleich zu expliziter Typ / Schnittstellen-Gleichheit zu sein . Es sei denn, ich habe etwas aus den Teilen des Videos verpasst, die ich noch nicht gesehen habe :)

Andres F.
quelle
2
Übrigens scheint Jack Diederichs Vortrag "Stop Writing Classes" nichts mit diesem Thema zu tun zu haben. Er handelt eher von YAGNI und "Schreiben Sie Code erst, wenn Sie ihn brauchen, und schreiben Sie dann nur einfachen Code".
Andres F.
9
ERROR: Object doesn't have a property called "name"ist oft das Ergebnis von value-orientedSprachen, und das andere Problem ist, wenn Sie diese Eigenschaft nicht mehr aufrufen möchten name. Viel Glück beim Refactoring, denn es gibt wahrscheinlich Hunderte von Objekten mit einer Immobilie, nameaber nicht alle sind Personoder Dog.
Reactgular
2
@MathewFoscarini Ja, dem stimme ich nicht unbedingt zu, es ist nur meine Interpretation dessen, was Hickey gesagt hat :) Ich mag Typen und statisches Tippen; Ich fange gerade an, Java nicht zu mögen. Und meine Abneigung hat nichts mit interfaces zu tun, sondern mit dem Durcheinander, das ein typisches Java-Projekt ist.
Andres F.
1
Java ist die Programmiersprache für diejenigen, die lieber zu viel nachdenken. Es ist eine der wenigen Sprachen, die es einem Entwickler ermöglicht, seine Versuche, ein Projekt zu überplanen, einfach zu verbergen.
Reactgular
"In 'wertorientierten' Sprachen werden Sie diesen Strukturen keine Typen zuweisen" - ich denke, Sie müssen sagen "In dynamischen 'wertorientierten' ..." Haskell und Scala sind wertorientiert, aber ihr statisches Typensystem gibt ihnen das genaue Problem, das Sie beschreiben. Ich denke, dass die Lösung für dieses Problem weniger Werte sind als die Verwendung von Maps, um Parameter an Funktionen zu übergeben. Die Verwendung unveränderlicher Karten (Werte) ist nur sicherer.
GlenPeterson
28

Er bezieht sich wahrscheinlich auf die grundlegende Tatsache, dass eine Schnittstelle nicht instanziiert werden kann. Sie können keine reuseSchnittstelle. Sie können nur Code implementieren, der dies unterstützt, und wenn Sie Code für eine Schnittstelle schreiben, erfolgt keine erneute Verwendung.

Java hat in der Vergangenheit Frameworks für viele APIs bereitgestellt, die eine Schnittstelle als Argumente verwenden. Das Team, das die API entwickelt hat, implementiert jedoch niemals eine Vielzahl von Klassen, die Sie mit diesen Schnittstellen wiederverwenden können.

Es ist wie ein GUI-Framework, das eine IWindowSchnittstelle für ein Dialogfeld hat, und dann können Sie IButtonSchnittstellen für Steuerelemente hinzufügen . Außer, sie haben dir nie eine gute ButtonKlasse gegeben, die implementiert IButton. Sie müssen also Ihre eigenen erstellen.

Abstrahierte Frameworks mit einer Vielzahl von Basisklassen, die Kernfunktionalitäten bereitstellen, sind wiederverwendbarer und funktionieren am besten, wenn diese abstrahierten Klassen für Benutzer des Frameworks zugänglich sind.

Java-Entwickler haben damit begonnen, dass ihre API-Ebenen nur verfügbar gemacht wurden interfaces. Sie könnten diese Schnittstellen implementieren, aber Sie könnten niemals Klassen des Entwicklers wiederverwenden, der diese Schnittstellen implementiert hat. Es ist eine Art Umhang und Dolch für die API-Entwicklung.

Reactgular
quelle
4
Vielen Dank für diese Antwort. Ich habe jetzt das Gefühl, dass ich die Frage und die Antwort verstehe :)
MetaFight
2
+1 Ich freue mich sehr über Ihre Antwort und füge dieser Frage eine faszinierende Schicht interessanter Informationen hinzu. Aber ich denke, die Antwort von Andreas F. entspricht wahrscheinlich eher dem, was Mr. Hickey meinte, also habe ich stattdessen seine akzeptiert.
GlenPeterson
@ GlenPeterson kein Problem, ich denke, er könnte auch auf dem richtigen Weg sein.
Reactgular
1
Nun, diese und die akzeptierte Antwort heben zwei leicht unterschiedliche, aber gleichermaßen interessante Interpretationen hervor. Ich bin gespannt, an wen Mr. Hickey gedacht hat, als er darüber gesprochen hat.
David Cowden,
Sie können eine Schnittstelle nicht wiederverwenden, aber Sie können sie erweitern (und eine wertvolle Versionsnummer angeben), ohne alte Klassen zu ändern. Sie können auch von vielen Schnittstellen erben, um neuen Job für neue Klassen hinzuzufügen, oder neue Vererbung in alten neu kompilierten Klassen hinzufügen. Sie können auch die Klasse erweitern, die diese Schnittstelle für neue Jobs implementiert.
Cl-R
14

Ich denke, Folie 13 bei seiner Präsentation ( Der Wert der Werte ) hilft, dies zu verstehen:

http://i.stack.imgur.com/LVMne.png


Werte

  • Nicht brauchen Methoden
    • Ich kann Ihnen Werte ohne Code senden
      und es geht Ihnen gut

Nach meinem Verständnis schlägt Hickey vor, dass ich, wenn ich beispielsweise den Wert, den Sie mir gesendet haben , verdoppeln muss, einfach Code schreibe, der so aussieht

    MyValue = Double(YourValue)

Sie sehen, obiger Code ist derselbe, egal welchen Wert Sie gesendet haben - eine Art perfekte Wiederverwendung .

Wie würde dies nun in der Sprache mit Objekten und Schnittstellen aussehen?

    Doublable MyValue = YourValue.Double()

Oh, Moment mal! Was ist, wenn YourValuenicht implementiert Doublable? nicht, dass es nicht verdoppelt werden kann, es mag perfekt sein, aber ... was ist, wenn es nur keine Methode gibt Double ? (Was ist, wenn es eine Methode namens say gibt TwiceAsMuch?)

Oh, wir haben ein Problem. YourValue.Doublefunktioniert nicht mehr , kann nicht mehr wiederverwendet werden. Nach meiner Lektüre der obigen Folie hat Hickey damit gemeint: "All diese Schnittstellen töten Ihre Wiederverwendung!"

Sie sehen, Interfaces setzen voraus, dass Objekte "zusammen mit ihren Methoden" und Code, der mit diesen arbeitet, weitergegeben werden. Um Objekte zu verwenden, muss man wissen, wie man diesen Code aufruft und welche Methode man aufruft .

Wenn die erwartete Methode fehlt, liegt ein Problem vor, obwohl die gewünschte Operation semantisch für ein Objekt durchaus sinnvoll ist. Wie in der Präsentation angegeben, benötigen Werte keine Methoden ("Ich kann Ihnen Werte ohne Code senden, und es geht Ihnen gut"), sodass Sie Code schreiben können, der sich allgemein mit ihnen befasst.


Randnotiz: Der Gedanke, codelose Werte weiterzugeben, erinnert mich irgendwie an ein Flyweight-Muster in OOP.

ein Objekt, das die Speichernutzung minimiert, indem so viele Daten wie möglich mit anderen ähnlichen Objekten geteilt werden; Es ist eine Möglichkeit, Objekte in großer Anzahl zu verwenden, wenn eine einfache wiederholte Darstellung eine nicht akzeptable Menge an Speicher benötigt ... Fliegengewichtobjekte sind per Definition Wertobjekte . Die Identität der Objektinstanz spielt keine Rolle, daher werden zwei Fliegengewicht-Instanzen mit demselben Wert als gleich angesehen ...

Ich habe gesehen, dass die Verwendung von Fliegengewichten in der Regel denselben Ansatz verfolgt, bei dem der Code (Methoden, Schnittstellen) von Objekten gestrippt und Dinge herumgereicht wurden, und zwar auch Werte ohne Code.

Das fühlt sich ziemlich ähnlich an wie auf der Folie: "Werte brauchen keine Methoden. Ich kann Ihnen Werte ohne Code senden und es geht Ihnen gut."

Mücke
quelle
5
Generika würden sich so ziemlich um dieses Problem kümmern. Das Verdoppeln ist bei einigen Objekten sinnvoll, bei anderen jedoch nicht. In der Sprache Go gibt es eine implizite Schnittstellenimplementierung (eine Form der Duck-Typisierung), sodass Sie sich nicht um all diese Schnittstellen sorgen müssen. Andererseits müssen Sie sorta wissen, welches Objekt von Ihrer Methodensignatur getroffen wird; Andernfalls erhalten Sie möglicherweise unerwartete Ergebnisse. Es gibt immer Kompromisse.
Robert Harvey
1
Eine interessante Einstellung. Gute Antwort!
maple_shaft
2
Das Fliegengewichtmuster ist nicht das, wovon Rich spricht. Wie der zweite Satz des Artikels besagt, besteht der Zweck des Fliegengewichtmusters darin, Gedächtnis zu bewahren. Richs Ansatz versucht das nicht.
5
MyValue = Double(YourValue)ist nicht sinnvoll, wenn YourValue eine Zeichenfolge, eine Adresse, ein Benutzer, eine Funktion oder eine Datenbank ist. Andernfalls ist das Argument für die fehlende Methode stark. Mit den OTOH-Zugriffsmethoden können Sie verschiedene Einschränkungen erzwingen, sodass Ihre Werte gültig sind und nur sinnvolle Operationen zum Erstellen neuer Werte verwendet werden. Wenn Sie sich später dazu entschließen, die Adresse von Ihrem Benutzer und Ihrer Firma zu trennen, führen Accessormethoden dazu, dass Sie nicht alle Clients Ihres Codes auflösen. So können sie langfristig zur Wiederverwendung beitragen, auch wenn sie diese manchmal kurzfristig behindern.
GlenPeterson
4
(Andererseits stimme ich zu, dass die Explosion von Klassen, Interfaces und Frameworks in Java ein Albtraum ist. Die einfachste "Enterprisey" -Lösung in Java ist ein Durcheinander von Code. Ich nehme also eine wertvolle Lektion daraus frage & antwort (ohne unbedingt mit dem dynamischen tippen einverstanden zu sein)
Andres F.
2

In einer (dh meiner) idealen Welt beschreiben Klassen und Schnittstellen immer das Verhalten, aber Tatsache ist, dass sie allzu oft wirklich nur Daten beschreiben. Erst gestern habe ich mir ein Video von jemandem angeschaut, der eine sogenannte BankAccountKlasse gebaut hat, die nichts weiter als eine verherrlichte Klasse war int(in der Tat war es viel weniger nützlich als eine int, also die Wiederverwendung "töten", die ich gehabt hätte, wenn sie einfach als eine verlassen worden wäre int). Alles im Namen von "gutem" Design. Die Menge an Code, Schweiß und Tränen, die verschwendet wird, um verschlungene Darstellungen von Daten immer wieder neu zu erfinden, ist erstaunlich. Wenn Sie die Daten nicht sinnvoll verwenden, lassen Sie es bitte einfach sein.

Nun, dies ist die Phase, in der Rich Hickey damit zufrieden ist, das Baby mit dem Badewasser hinauszuwerfen und zu sagen, dass wir alle im Land der Werte (einem Nachbarn des Reiches der Nomen) leben sollen. Ich denke andererseits, dass OOP die Wiederverwendung (und vor allem die Auffindbarkeit, die mir bei der funktionalen Programmierung fehlt) fördern kann und tut, wenn es mit Bedacht eingesetzt wird. Wenn Sie nach einem OOP-Prinzip suchen, das diese Spannung am besten aufnimmt, dann könnte es http://c2.com/cgi/wiki?TellDontAsk sein (was natürlich ein enger Verwandter von Demeter ist).

CurtainDog
quelle
Was meinst du mit Auffindbarkeit? Ist es ähnlich wie diese ?
1
Ja, ich denke, das berührt viele der Hauptpunkte. Es ist ein subtiler Punkt, aber Auffindbarkeit ist ein Balanceakt, und es ist auch unerwünscht, Dinge zu transparent zu machen, da Sie ein schlechtes Signal-Rausch-Verhältnis erhalten.
CurtainDog