Wie viel Abstraktion ist zu viel?

73

In einem objektorientierten Programm: Wie viel Abstraktion ist zu viel? Wie viel ist genau richtig?

Ich war schon immer ein verrückter Typ. Ich verstand das Konzept hinter einem hohen Maß an Kapselung und Abstraktion, hatte aber immer instinktiv das Gefühl, dass zu viel Hinzufügen das Programm nur verwirren würde.

Ich habe immer versucht, nach einer Menge Abstraktion zu suchen, die keine leeren Klassen oder Ebenen hinterlässt. Und wo im Zweifel, anstatt der Hierarchie eine neue Ebene hinzuzufügen, würde ich versuchen, etwas in die vorhandenen Ebenen einzupassen.

In letzter Zeit bin ich jedoch auf stärker abstrahierte Systeme gestoßen. Systeme, bei denen alles, was später in der Hierarchie eine Darstellung erfordern könnte, eine im Voraus erhält. Dies führt zu vielen leeren Schichten, was auf den ersten Blick als schlechtes Design erscheint. Beim zweiten Gedanken wurde mir jedoch klar, dass das Verlassen dieser leeren Ebenen Ihnen in Zukunft mehr Orte bietet, an denen Sie sich ohne viel Umgestaltung einhaken können. Sie haben die Möglichkeit, neue Funktionen zusätzlich zu den alten hinzuzufügen, ohne fast genauso viel Arbeit für die Anpassung der alten zu leisten.

Die beiden Risiken scheinen darin zu bestehen, dass Sie die Schichten, die Sie benötigen, falsch machen könnten. In diesem Fall müsste man immer noch ein umfangreiches Refactoring durchführen, um den Code zu erweitern, und hätte immer noch eine Menge nie verwendeter Ebenen. Aber je nachdem, wie viel Zeit Sie damit verbringen, die ersten Abstraktionen zu erstellen, die Möglichkeit, sie zu vermasseln, und die Zeit, die später gespart werden könnte, wenn Sie es richtig machen, lohnt es sich möglicherweise immer noch, es zu versuchen.

Das andere Risiko, an das ich denken kann, ist das Risiko, es zu übertreiben und niemals alle zusätzlichen Schichten zu benötigen. Aber ist das wirklich so schlimm? Sind zusätzliche Klassenebenen wirklich so teuer, dass es ein großer Verlust ist, wenn sie nie verwendet werden? Der größte Aufwand und Verlust wäre hier die Zeit, die im Vorfeld der Schichten verloren geht. Ein Großteil dieser Zeit könnte jedoch später noch gespart werden, wenn man mit dem abstrahierten Code arbeiten kann, anstatt mit Code auf niedrigerer Ebene.

Wann ist es zu viel? Ab wann werden die leeren Ebenen und zusätzlichen "möglicherweise benötigten" Abstraktionen übertrieben? Wie wenig ist zu wenig? Wo ist der Sweet Spot?

Gibt es verlässliche Faustregeln, die Sie im Laufe Ihrer Karriere gefunden haben und die Ihnen helfen, den Umfang der erforderlichen Abstraktion zu beurteilen?

Daniel Bingham
quelle
6
Wie lang ist ein Stück Schnur ??? ;)
Goz
2
Sollte CW IMHO sein, da sie nicht haben eine Antwort
Binary Worrier
4
Warum haben Java-Apps im Vergleich zu C # tendenziell mehr Abstraktionen?
Linquize
@Goz hängt von der Sprache ab, z. B. sagt Pascal, dass es eine maximale Länge hat, aber intelligente (c) Leute wissen, dass dies nicht der Fall ist.
jave.web
Zu viel Abstraktion ist das Zeug für Todesmärsche. Ich arbeite an einer großen Legacy-Anwendung, die so abstrahiert ist, dass es buchstäblich Stunden dauert, den Code zu finden, der ausgeführt wird, wenn auf eine Schaltfläche auf einer Oberfläche geklickt wird. Diese Anwendung kombiniert WPF, Dependency Injection und Mocking auf sehr nachteilige Weise. Zu viel Abstraktion ist ein Hindernis für die Aufrechterhaltung einer Codebasis. Dies ist ein wichtiges Thema und sollte diskutiert werden. Zu viel Abstraktion kann buchstäblich gute Unternehmen und Organisationen in Trümmern liegen lassen. Das ist keine Übertreibung.
Doug Kimzey vor

Antworten:

23

Wann ist es zu viel? Ab wann werden die leeren Ebenen und zusätzlichen "möglicherweise benötigten" Abstraktionen übertrieben? Wie wenig ist zu wenig? Wo ist der Sweet Spot?

Ich glaube nicht, dass es eine endgültige Antwort auf diese Fragen gibt. Erfahrung ist erforderlich, um ein Gefühl dafür zu entwickeln, was "zu viel" und "zu wenig" ist. Vielleicht kann die Verwendung einiger Metrik- oder Qualitätskontrollwerkzeuge helfen, aber es ist schwer zu verallgemeinern. Es kommt meistens auf jeden Fall an.

Hier sind einige Links, die Sie bei der Suche nach Antworten inspirieren könnten:

Bei der Entwicklung geht es darum, das richtige Gleichgewicht zwischen den verschiedenen Spannungen zu finden, die bei jeder Softwareentwicklung auftreten.

ewernli
quelle
7
+1 Berücksichtigen Sie jedes Mal, wenn Sie eine Abstraktionsebene hinzufügen möchten, die Vorteile. Es macht keinen Sinn, nur um der Abstraktion willen.
CiscoIPPhone
1
Dies ist eine beliebte Frage zu den Gefahren, Frameworks zu allgemein zu gestalten. Witziges Zeug! diskutieren.joelonsoftware.com/default.asp?joel.3.219431.12
Ben Power
30

Der Sinn von Abstraktionen besteht darin , gemeinsame Eigenschaften aus den spezifischen herauszufiltern , wie in der mathematischen Operation:

ab + ac => a(b + c)

Jetzt machen Sie dasselbe mit zwei Operationen anstelle von drei. Dieses Factoring machte unseren Ausdruck einfacher.

Ein typisches Beispiel für eine Abstraktion ist das Dateisystem. Sie möchten beispielsweise, dass Ihr Programm auf viele Arten von Speichergeräten schreiben kann: USB-Sticks, SD-Karten, Festplatten usw.

Wenn wir kein Dateisystem hätten, müssten wir die direkte Schreiblogik für die Festplatte, die Schreiblogik für das USB-Stick und die Schreiblogik für die SD-Karte implementieren. Alle diese Logiken haben jedoch etwas gemeinsam: Sie erstellen Dateien und Verzeichnisse, sodass diese gemeinsamen Dinge abstrahiert werden können, indem eine Abstraktionsschicht erstellt und dem Hardwareanbieter eine Schnittstelle zur Verfügung gestellt wird, um die spezifischen Aufgaben zu erledigen.

Je mehr die Dinge eine gemeinsame Eigenschaft haben. Je vorteilhafter eine Abstraktion sein kann:

ab + ac + ad + ae + af

zu:

a(b + c + d + e + f)

Dies würde die 9 Operationen auf 5 reduzieren.

Grundsätzlich halbiert jede gute Abstraktion ungefähr die Komplexität eines Systems.

Sie benötigen immer mindestens zwei Dinge, die eine gemeinsame Eigenschaft gemeinsam haben, um eine Abstraktion nützlich zu machen. Natürlich zerreißt man eine einzelne Sache, so dass sie wie eine Abstraktion aussieht, aber das bedeutet nicht, dass sie nützlich ist:

10 => 5 * 2

Sie können das Wort "common" nicht definieren, wenn Sie nur eine Entität haben.

Also, um deine Frage zu beantworten. Sie haben genug Abstraktionen, wenn sie Ihr System so einfach wie möglich machen.

(In meinen Beispielen verbindet Addition die Teile des Systems, während Multiplikation eine abstrakt-konkrete Beziehung definiert.)

Calmarius
quelle
Diese Antwort beschreibt die Verwendung von Abstraktionen, um den Code trocken zu halten, berührt jedoch nicht andere wichtige / sinnvolle Verwendungszwecke der Abstraktion - z. B. SOLID- oder GRASP-Muster und Metaprogrammierverträge, die die Trennung von Bedenken oder die Konsistenz der Verwendung erzwingen.
Jchook
das ist völlig falsch. Wenn Sie einen Code schreiben, der sich nicht in einer einzigen Zeile wiederholt, werden Sie ungefähr 1 Jahr damit verbringen, und der Typ, der ihn nach dem Verlassen des Jobs warten wird, wird ein weiteres halbes Jahr damit verbringen, Ihren Code zu verstehen. Es ist also genau das Gegenteil: Jede Abstraktion, die Sie hinzufügen -> trägt zu mehr Komplexität des Systems bei.
Nulik
27

Wie wenig ist zu wenig?

Wenn Sie weiterhin routinemäßig mit "Low-Level" -Elementen arbeiten und ständig das Gefühl haben, dies nicht zu tun. Abstrakt sie weg.

Wann ist es zu viel?

Wenn Sie einige Code-Teile nicht regelmäßig erstellen können und sie bis zur vorherigen Ebene debuggen müssen. Sie haben das Gefühl, dass diese bestimmte Schicht nichts beiträgt, nur ein Hindernis. Lass es fallen.

Wo ist der Sweet Spot?

Ich wende gerne den pragmatischen Ansatz an. Wenn Sie die Notwendigkeit einer Abstraktion sehen und verstehen, wie sie Ihr Leben verbessern wird, entscheiden Sie sich dafür. Wenn Sie gehört haben, dass es "offiziell" eine zusätzliche Abstraktionsebene geben sollte, Ihnen aber nicht klar ist, warum, tun Sie dies nicht, sondern recherchieren Sie zuerst. Wenn jemand darauf besteht, etwas zu abstrahieren, aber nicht klar erklären kann, was wenn bringt, sagen Sie ihm, er soll gehen.

user151323
quelle
11

Einfach ausgedrückt, es gibt zu viel Abstraktion, wenn der Code schwer zu verstehen ist.

Das soll nicht heißen, dass Sie alles hart codieren sollten, denn das ist der am einfachsten zu schreibende und zu lesende Code.

Der einfachste Test besteht darin, ihn entweder einige Tage lang abzulegen, wieder aufzunehmen und sich zu fragen, ob dies sinnvoll ist. Ein besserer Ansatz ist es, es jemand anderem zu geben und zu sehen, ob er Kopf oder Zahl daraus machen kann.

kemiller2002
quelle
2
"Es gibt zu viel Abstraktion, wenn der Code schwer zu verstehen ist" für wen zu verstehen? Ich habe angefangen, an schrecklich komplizierten Codebasen zu arbeiten, und kann mich dann nach ein paar Monaten / Jahren leicht zurechtfinden. Außerdem habe ich mit hartcodierten Dingen gearbeitet, die ohne ein paar aussagekräftige Abstraktionen nicht zu verstehen waren.
Binary Worrier
2
Ich meine, wenn der Code aufgrund der Abstraktion schwierig ist, gibt es zu viel. Ich sage nicht, dass Code ohne Abstraktion schwer zu lesen ist, aber Sie sollten in der Lage sein, sich den Code anzusehen und zu sagen: "Ok, Punkt A geht zu Punkt B. Das macht Sinn."
kemiller2002
Ich stimme Kevin zu. Zum Beispiel erstelle ich manchmal ein Shell-Skript, um sich wiederholende Arbeiten auszuführen, aber dann vergesse ich, wie GENAU das Skript funktioniert, sodass ich am Ende nur die zugrunde liegenden Befehle verwende. Beispiel: Bei 'du'-Skripten: In welchem ​​Verzeichnis muss ich mich befinden, um das Skript auszuführen? Wird die Ausgabedatei im aktuellen Verzeichnis abgelegt? Ist das Skript asynchron oder blockiert? (Das genaue Skript, das ich habe und das disk_usage heißt, lautet im Grunde "nohup du> disk_usage_recursive.txt &", aber am Ende tippe ich diesen Befehl einfach bei jedem Typ ein).
Sridhar Sarnobat
Genau. Ich habe Code gesehen, der eine Abstraktion (Klasse) mit 2 Funktionen und 2 Variablen erstellt. Dies könnte mit Parametern geschehen, aber nein, der Entwickler hat es mit einer Schnittstelle abstrahiert, nur um einige boolesche Werte zu ändern.
Nulik
9

Theoretisch sollte es sich um eine einfache Mathematik handeln, bei der nur drei (ziemlich einfache) Variablen verwendet werden:

  • S = Einsparungen durch Nutzung
  • C = Kosten der zusätzlichen Abstraktionen
  • P = Nutzungswahrscheinlichkeit

Wenn S * P> C ist, ist der Code gut. Wenn S * P <C ist, ist es schlecht.

Der rein theoretische Grund ist jedoch, dass Sie die Nutzungswahrscheinlichkeit oder die Einsparungen, die Sie durch die Verwendung erzielen, im Allgemeinen nicht erraten können. Schlimmer noch, Sie können die Kosten seiner Anwesenheit nicht erraten oder sogar messen .

Zumindest einige Leute haben daraus eine Schlussfolgerung gezogen. In TDD lautet das Standard-Mantra "Du wirst es nicht brauchen" (YAGNI). Einfach ausgedrückt, alles, was nicht direkt dazu beiträgt, dass der Code die aktuellen Anforderungen erfüllt, wird als schlecht angesehen. Im Wesentlichen sind sie zu dem Schluss gekommen, dass die Nutzungswahrscheinlichkeit so gering ist, dass die Aufnahme eines solchen zusätzlichen Codes niemals gerechtfertigt ist.

Ein Teil davon geht auf die Entwicklung von "Bottom-Up" gegenüber "Top-Down" zurück. Ich neige dazu, Bottom-up-Entwicklung als "Bibliotheksentwicklung" zu betrachten - dh anstatt eine bestimmte Anwendung zu entwickeln, entwickeln Sie wirklich Bibliotheken für die Art von Dingen, die Sie in der Anwendung benötigen. Der Gedanke ist, dass Sie mit einer ausreichend guten Bibliothek fast jede Anwendung dieses allgemeinen Typs relativ einfach entwickeln können.

Ein bisschen hängt auch von der Größe des Projekts ab. Riesige Projekte, die jahrzehntelang in Gebrauch bleiben, rechtfertigen viel mehr langfristige Investitionen als kleinere Projekte, die viel schneller verworfen und ersetzt werden. Dies hat auch im wirklichen Leben offensichtliche Analogien. Sie sorgen sich nicht annähernd so sehr um die Passform, das Finish oder die Verarbeitung eines Einwegrasierers, den Sie in weniger als einer Woche wegwerfen werden, wie bei einem neuen Auto, das Sie in den nächsten Jahren verwenden werden .

Jerry Coffin
quelle
2

Die Realität ist, dass es davon abhängt, wie gut Sie in die Zukunft schauen können. Sie möchten Änderungen planen, die Sie vorhersehen können, ohne zu viele zusätzliche Ebenen zu erstellen. Wenn Sie ein Design haben, das Daten zwischen Systemen überträgt, erstellen Sie eine Schnittstelle und verwenden Sie die geplante Implementierung als Standard. Sie verwenden beispielsweise FTP, um Dateien zu verschieben, wissen jedoch, dass der Standard im nächsten Jahr auf Nachrichten basiert (oder was auch immer).

Bei Ebenen innerhalb des Entwurfs erleichtern manchmal die hinzugefügten Ebenen das Schreiben kleinerer Klassen. Es ist in Ordnung, konzeptionelle Ebenen hinzuzufügen, wenn dies bedeutet, dass die konkreten Klassen einfach werden.

Kelly S. Französisch
quelle
1

Siehe Punkt (6a)von RFC 1925 und wissen, dass es tatsächlich wahr ist. Die einzigen Probleme, die Sie durch Hinzufügen von Abstraktionsschichten nicht beheben können, sind die, die durch zu viele Abstraktionsschichten verursacht werden. (Insbesondere macht jede Abstraktion das Ganze schwieriger zu verstehen.)

Donal Fellows
quelle
1

Jede Abstraktion, die nicht tatsächlich verwendet wird, ist zu viel. Je einfacher ein System ist, desto einfacher ist es zu ändern. Abstraktionsschichten machen Systeme fast immer komplizierter.

OTOH, es ist sicherlich möglich, ein komplexes, nicht wartbares Durcheinander ohne jede Art von Abstraktion zu programmieren, und manchmal können "standardisierte" Abstraktionsschichten dazu beitragen, ein System besser zu strukturieren, als es die meisten Menschen alleine tun könnten.

Michael Borgwardt
quelle