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?
quelle
Antworten:
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.
quelle
Der Sinn von Abstraktionen besteht darin , gemeinsame Eigenschaften aus den spezifischen herauszufiltern , wie in der mathematischen Operation:
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:
zu:
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:
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.)
quelle
Wenn Sie weiterhin routinemäßig mit "Low-Level" -Elementen arbeiten und ständig das Gefühl haben, dies nicht zu tun. Abstrakt sie weg.
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.
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.
quelle
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.
quelle
Theoretisch sollte es sich um eine einfache Mathematik handeln, bei der nur drei (ziemlich einfache) Variablen verwendet werden:
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 .
quelle
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.
quelle
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.)quelle
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.
quelle