Wie viele Entwurfsmuster und Abstraktionsebenen sind notwendig? [geschlossen]

29

Wie kann ich feststellen, dass meine Software zu viel Abstraktion und zu viele Entwurfsmuster aufweist, oder umgekehrt, woher weiß ich, ob es mehr davon geben sollte?

Entwickler, mit denen ich zusammenarbeite, programmieren in diesen Punkten unterschiedlich.

Einige abstrahieren jede kleine Funktion, verwenden Designmuster, wo immer dies möglich ist, und vermeiden Redundanzen um jeden Preis.

Die anderen, einschließlich mir, versuchen pragmatischer zu sein und Code zu schreiben, der nicht perfekt zu jedem Designmuster passt, aber viel schneller zu verstehen ist, weil weniger Abstraktion angewendet wird.

Ich weiß, das ist ein Kompromiss. Woran erkenne ich, wann das Projekt ausreichend abstrahiert ist und woher weiß ich, dass es mehr benötigt?

Beispiel, wenn eine generische Caching-Ebene mit Memcache geschrieben wird. Haben wir wirklich brauchen Memcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector, ... , oder ist dies einfacher zu warten und immer noch guter Code bei der Verwendung von nur die Hälfte dieser Klassen?

Fand dies in Twitter:

Bildbeschreibung hier eingeben

( https://twitter.com/rawkode/status/875318003306565633 )

Daniel W.
quelle
58
Wenn Sie Entwurfsmuster als Dinge behandeln, die Sie aus einem Eimer ziehen und zum Zusammenstellen von Programmen verwenden, verwenden Sie zu viele.
Blrfl
5
Man könnte sich vorstellen, Muster wie Sprachmuster zu entwerfen, die von Menschen verwendet werden. Denn in gewissem Sinne sind Redewendungen, Metaphern usw. alle Entwurfsmuster. Wenn Sie in jedem Satz eine Redewendung verwenden ... ist das wahrscheinlich zu oft. Aber sie können helfen, Gedanken zu klären und das Verständnis für eine lange Prosawand zu fördern. Es gibt nicht wirklich einen richtigen Weg, um zu antworten: "Wie oft sollte ich Metaphern verwenden?" - es liegt im Ermessen des Autors.
Prime
8
Es gibt keine Möglichkeit, mit einer einzigen SE-Antwort dieses Thema angemessen zu behandeln. Dies erfordert im wahrsten Sinne des Wortes jahrelange Erfahrung und Mentoring, um es in den Griff zu bekommen. Dies ist eindeutig zu breit.
jpmc26
5
Befolgen Sie das grundlegende Konstruktionsprinzip in der Luftfahrtindustrie: "Einfacher und leichter". Wenn Sie feststellen, dass der beste Weg, einen Fehler zu beheben, darin besteht, den Code zu löschen, der den Fehler enthält, da er selbst dann noch nichts Nützliches bewirkt, wenn er fehlerfrei ist, beginnen Sie, das Design richtig zu gestalten!
Alephzero

Antworten:

52

Wie viele Zutaten sind für eine Mahlzeit notwendig? Wie viele Teile benötigen Sie, um ein Fahrzeug zu bauen?

Sie wissen, dass Sie zu wenig Abstraktion haben, wenn eine kleine Implementierungsänderung zu einer Kaskade von Änderungen im gesamten Code führt. Richtige Abstraktionen würden helfen, den Teil des Codes zu isolieren, der geändert werden muss.

Sie wissen, dass Sie zu viel Abstraktion haben, wenn eine kleine Änderung der Benutzeroberfläche zu einer Kaskade von Änderungen im gesamten Code auf verschiedenen Ebenen führt. Anstatt die Schnittstelle zwischen zwei Klassen zu ändern, müssen Sie Dutzende von Klassen und Schnittstellen ändern, um eine Eigenschaft hinzuzufügen oder den Typ eines Methodenarguments zu ändern.

Abgesehen davon gibt es wirklich keine Möglichkeit, die Frage mit einer Zahl zu beantworten. Die Anzahl der Abstraktionen ist von Projekt zu Projekt, von Sprache zu Sprache und sogar von Entwickler zu Entwickler unterschiedlich.

Arseni Mourzenko
quelle
28
Wenn Sie nur zwei Schnittstellen und Hunderte von Klassen haben, die diese implementieren, würde das Ändern der Schnittstellen zu einer Kaskade von Änderungen führen, aber das bedeutet nicht, dass es zu viel Abstraktion gibt, da Sie nur zwei Schnittstellen haben.
Tulains Córdova
Die Anzahl der Abstraktionen wird nicht einmal für verschiedene Teile desselben Projekts gleich sein!
T. Sar - Reinstate Monica
Hinweis: Der Wechsel von Memcache zu einem anderen Caching-Mechanismus (Redis?) Ist eine Implementierungsänderung .
Ogre Psalm33
Ihre beiden Regeln (Richtlinien, wie auch immer Sie sie nennen möchten) funktionieren nicht, wie Tulains demonstriert. Sie sind auch kläglich unvollständig, selbst wenn sie es taten. Der Rest des Beitrags ist eine nicht beantwortete Frage, die kaum mehr aussagt, als dass wir keine vernünftige Antwort geben können. -1
jpmc26
Ich würde argumentieren, dass Sie im Fall von zwei Schnittstellen und Hunderten von Klassen, die diese implementieren, Ihre Abstraktionen möglicherweise überstrapaziert haben . Ich habe dies sicherlich in Projekten gesehen, die an vielen Stellen eine sehr vage Abstraktion wiederverwenden ( interface Doer {void prepare(); void doIt();}), und es wird schmerzhaft, eine Umgestaltung vorzunehmen, wenn diese Abstraktion nicht mehr passt. Der entscheidende Teil der Antwort ist, dass der Test angewendet wird, wenn sich eine Abstraktion ändern muss - wenn dies niemals der Fall ist, verursacht dies niemals Schmerzen.
James_pic
24

Das Problem mit Designmustern lässt sich mit dem Sprichwort "Wenn man einen Hammer hält, sieht alles aus wie ein Nagel" zusammenfassen. Das Anwenden eines Entwurfsmusters verbessert Ihr Programm in keiner Weise. Tatsächlich würde ich argumentieren, dass Sie ein komplizierteres Programm erstellen, wenn Sie ein Entwurfsmuster hinzufügen. Es bleibt die Frage, ob Sie das Entwurfsmuster gut gebrauchen oder nicht, und dies ist der Kern der Frage: "Wann haben wir zu viel Abstraktion?"

Wenn Sie eine Schnittstelle und eine abstrakte Superklasse für eine einzelne Implementierung erstellen, haben Sie Ihrem Projekt zwei zusätzliche Komponenten hinzugefügt, die überflüssig und unnötig sind. Der Sinn der Bereitstellung einer Schnittstelle besteht darin, dass Sie in der Lage sind, sie im gesamten Programm gleichermaßen zu verarbeiten, ohne zu wissen, wie sie funktioniert. Der Sinn einer abstrakten Superklasse besteht darin, ein zugrunde liegendes Verhalten für Implementierungen bereitzustellen. Wenn Sie nur eine Implementierung haben, erhalten Sie alle Komplikationsschnittstellen und Abstact-Klassen und keinen der Vorteile.

Wenn Sie ein Factory-Muster verwenden und eine Klasse umwandeln, um Funktionen zu nutzen, die nur in der Superklasse verfügbar sind, bietet das Factory-Muster keine Vorteile für Ihren Code. Sie haben Ihrem Projekt nur eine zusätzliche Klasse hinzugefügt, die vermieden werden konnte.

TL; DR Mein Punkt ist, dass das Ziel der Abstraktion nicht an sich abstrakt ist. Es erfüllt einen sehr praktischen Zweck in Ihrem Programm, und bevor Sie sich für die Verwendung eines Entwurfsmusters oder die Erstellung einer Schnittstelle entscheiden, sollten Sie sich fragen, ob das Programm auf diese Weise trotz der zusätzlichen Komplexität einfacher zu verstehen ist oder ob das Programm robuster ist trotz der zusätzlichen Komplexität (vorzugsweise beides). Wenn die Antwort "Nein" oder "Vielleicht" ist, nehmen Sie sich ein paar Minuten Zeit, um zu überlegen, warum Sie dies tun wollten, und wenn dies möglicherweise besser möglich ist, ohne dass Sie Ihrem Code unbedingt eine Abstraktion hinzufügen müssen.

Neil
quelle
Die Hammer-Analogie wäre das Problem, nur ein Entwurfsmuster zu kennen. Entwurfsmuster sollten ein vollständiges Toolkit erstellen, aus dem Sie gegebenenfalls auswählen und anwenden können. Sie wählen keinen Vorschlaghammer, um eine Nuss zu knacken.
Pete Kirkham
@PeteKirkham Richtig, aber selbst eine ganze Reihe von Designmustern, die Ihnen zur Verfügung stehen, sind möglicherweise nicht für ein bestimmtes Problem geeignet. Wenn ein Vorschlaghammer nicht zum Knacken einer Mutter geeignet ist und weder ein Schraubenzieher noch ein Maßband, weil Ihnen der Hammer fehlt, ist ein Vorschlaghammer nicht die richtige Wahl für den Job es ist das am besten geeignete der Werkzeuge zu Ihrer Verfügung. Das bedeutet jedoch nicht, dass Sie einen Vorschlaghammer verwenden sollten, um eine Nuss zu knacken. Zum Teufel, wenn wir ehrlich sind, brauchen Sie wirklich einen Nussknacker, keinen Hammer.
Neil
Ich möchte eine Armee trainierter Eichhörnchen, damit meine Nüsse knacken.
ICC97
6

TL: DR;

Ich glaube nicht, dass es eine "notwendige" Anzahl von Abstrationsstufen gibt, unterhalb derer es zu wenig gibt oder oberhalb derer es zu viel gibt. Wie beim Grafikdesign sollte gutes OOP-Design unsichtbar und selbstverständlich sein. Schlechtes Design ragt immer wie ein Daumen heraus.

Lange Antwort

Höchstwahrscheinlich werden Sie nie erfahren, auf wie vielen Abstraktionsebenen Sie aufbauen.

Die meisten Abstraktionsebenen sind für uns unsichtbar und für uns selbstverständlich.

Diese Überlegung führt mich zu dieser Schlussfolgerung:

Einer der Hauptzwecke der Abstraktion besteht darin, dem Programmierer die Notwendigkeit zu ersparen, die gesamte Funktionsweise des Systems ständig im Auge zu behalten. Wenn Sie aufgrund des Designs zu viel über das System wissen müssen, um etwas hinzuzufügen, ist die Abstraktion wahrscheinlich zu gering. Ich denke, eine schlechte Abstraktion (schlechtes Design, anämisches Design oder Überentwicklung) kann Sie auch dazu zwingen, zu viel zu wissen, um etwas hinzuzufügen. In einem Extrem haben wir ein Design, das auf einer Gottklasse oder einem Haufen DTO basiert, im anderen Extrem haben wir einige OR / Persistenz-Frameworks, mit denen Sie durch unzählige Reifen springen können, um eine Hallo-Welt zu erreichen. Beide Fälle zwingen auch Sie, zu viel zu wissen.

Eine schlechte Abstraktion hängt mit einer Gauß-Glocke zusammen, die einem, sobald man einen Sweet Spot hinter sich gelassen hat, im Weg steht. Andererseits ist eine gute Abstraktion unsichtbar und es kann nicht zu viel davon geben, weil man nicht merkt, dass sie da ist. Überlegen Sie, auf wie vielen Ebenen von APIs, Netzwerkprotokollen, Bibliotheken, Betriebssystembibliotheken, Dateisystemen, Harware-Ebenen usw. Ihre Anwendung aufgebaut ist und wie selbstverständlich dies ist.

Ein weiterer Hauptzweck der Abstraktion ist die Unterteilung, damit Fehler nicht über einen bestimmten Bereich hinausgehen, ähnlich wie beim Doppelrumpf, und separate Tanks verhindern, dass ein Schiff vollständig überflutet wird, wenn ein Teil des Rumpfs ein Loch hat. Wenn Änderungen am Code zu Fehlern in scheinbar nicht zusammenhängenden Bereichen führen, ist die Wahrscheinlichkeit groß, dass zu wenig Abstraktion vorhanden ist.

Tulains Córdova
quelle
2
"Höchstwahrscheinlich werden Sie nie erfahren, auf wie vielen Abstraktionsebenen Sie aufbauen." - Tatsächlich ist der springende Punkt einer Abstraktion, dass Sie nicht wissen, wie sie implementiert wird, und dass Sie nicht wissen (und nicht wissen können ), wie viele Abstraktionsebenen sie verbirgt.
Jörg W Mittag
4

Entwurfsmuster sind einfach übliche Problemlösungen. Es ist wichtig, Entwurfsmuster zu kennen, aber sie sind nur Symptome von gut entworfenem Code (guter Code kann immer noch die Gruppe von vier Entwurfsmustern außer Kraft setzen), nicht die Ursache.

Abstraktionen sind wie Zäune. Sie helfen dabei, Bereiche Ihres Programms in testbare und austauschbare Chunks zu unterteilen (Voraussetzungen für die Erstellung von nicht fragilem, nicht starrem Code). Und ähnlich wie Zäune:

  • Sie möchten Abstraktionen an natürlichen Schnittstellenpunkten, um deren Größe zu minimieren.

  • Du willst sie nicht ändern.

  • Sie möchten, dass sie Dinge trennen, die unabhängig sein können.

  • Es ist schlimmer, einen am falschen Ort zu haben, als ihn nicht zu haben.

  • Sie sollten keine großen Lecks haben .

dlasalle
quelle
4

Refactoring

Ich habe das Wort "Refactoring" noch kein einziges Mal gesehen. Auf geht's:

Fühlen Sie sich frei, eine neue Funktion so direkt wie möglich zu implementieren. Wenn Sie nur eine einzige, einfache Klasse haben, benötigen Sie wahrscheinlich keine Schnittstelle, Superklasse, Factory usw. dafür.

Wenn Sie feststellen, dass Sie die Klasse so erweitern, dass sie zu fett wird, ist es an der Zeit, sie zu zerreißen. Zu diesem Zeitpunkt ist es sehr sinnvoll darüber nachzudenken, wie Sie das eigentlich tun sollten.

Muster sind ein Werkzeug des Denkens

Patterns, oder genauer gesagt das Buch "Design Patterns" der vierköpfigen Bande, sind unter anderem deshalb großartig, weil sie eine Sprache zum Nachdenken und Reden für Entwickler bilden "Fassade" und jeder weiß sofort genau, was es bedeutet.

Meiner Meinung nach sollte jeder Entwickler zumindest über die Muster im ursprünglichen Buch verfügen, um über OO-Konzepte sprechen zu können, ohne immer die Grundlagen erklären zu müssen. Sollten Sie die Muster tatsächlich jedes Mal verwenden , wenn eine Möglichkeit dazu erscheint? Höchst wahrscheinlich nicht.

Bibliotheken

Bibliotheken sind wahrscheinlich derjenige Bereich, in dem es möglich ist, auf der Seite zu vieler musterbasierter Entscheidungen zu irren, anstatt zu wenig. Wenn Sie etwas von einer "fetten" Klasse in etwas mit mehr Mustern ändern (normalerweise bedeutet dies, dass mehr und kleinere Klassen vorhanden sind), ändert sich die Schnittstelle radikal. und das ist die einzige Sache, die Sie normalerweise in einer Bibliothek nicht ändern möchten, weil es die einzige Sache ist, die für den Benutzer Ihrer Bibliothek von echtem Interesse ist. Sie kümmern sich nicht weniger darum, wie Sie intern mit Ihrer Funktionalität umgehen, aber sie kümmern sich sehr darum, ob sie ihr Programm ständig ändern müssen, wenn Sie eine neue Version mit einer neuen API erstellen.

AnoE
quelle
2

Der Punkt der Abstraktion sollte in erster Linie der Wert sein, der dem Verbraucher der Abstraktion, dh dem Client der Abstraktion, den anderen Programmierern und häufig Ihnen selbst, gebracht wird.

Wenn Sie als Client, der die Abstraktion (en) verbraucht, feststellen, dass Sie viele verschiedene Abstraktionen mischen und zuordnen müssen, um Ihre Programmieraufgabe zu erledigen, gibt es möglicherweise zu viele Abstraktionen.

Im Idealfall sollte die Schichtung eine Reihe niedrigerer Abstraktionen zusammenführen und diese durch eine einfache und übergeordnete Abstraktion ersetzen, die die Verbraucher verwenden können, ohne sich mit einer dieser zugrunde liegenden Abstraktionen befassen zu müssen. Wenn sie sich mit den zugrunde liegenden Abstraktionen befassen müssen, ist die Ebene undicht (weil sie unvollständig ist). Wenn der Verbraucher mit zu vielen verschiedenen Abstraktionen zu tun hat, fehlt möglicherweise die Schichtung.

Nachdem wir den Wert der Abstraktionen für die konsumierenden Programmierer bedacht haben, können wir uns der Bewertung und Implementierung widmen, beispielsweise der der Trockenheit.

Ja, es geht nur darum, die Wartung zu vereinfachen, aber wir sollten zuerst das Problem der Wartung durch unsere Verbraucher in Betracht ziehen, indem wir qualitativ hochwertige Abstraktionen und Schichten bereitstellen, und dann unsere eigene Wartung in Bezug auf Implementierungsaspekte wie die Vermeidung von Redundanz vereinfachen.


Beispiel, wenn eine generische Caching-Ebene mit Memcache geschrieben wird. Brauchen wir wirklich Memcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector, ... oder ist dies einfacher zu pflegen und trotzdem guter Code, wenn nur die Hälfte dieser Klassen verwendet wird?

Wir müssen die Perspektive des Klienten betrachten, und wenn ihr Leben erleichtert wird, ist es gut. Wenn ihr Leben komplexer ist, ist es schlecht. Es kann jedoch vorkommen, dass eine Ebene fehlt, die diese Dinge zu etwas Einfachem zusammenfügt. Intern kann dies die Wartung der Implementierung erheblich verbessern. Wie Sie vermuten, ist es jedoch auch möglich, dass es nur überentwickelt ist.

Erik Eidt
quelle
2

Abstraktion soll das Verständnis von Code erleichtern. Wenn eine Abstraktionsebene die Dinge verwirrender macht, tun Sie es nicht.

Ziel ist es, die richtige Anzahl von Abstraktionen und Schnittstellen zu verwenden, um:

  • Entwicklungszeit minimieren
  • Maximieren Sie die Wartbarkeit des Codes

Abstract nur bei Bedarf

  1. Wenn Sie entdecken, dass Sie eine Superklasse schreiben
  2. Wann wird es erhebliche Code-Wiederverwendung ermöglichen
  3. Wenn die Zusammenfassung dazu führt, dass der Code deutlich klarer und besser lesbar wird

Nicht abstrahieren wenn

  1. Dies hat keinen Vorteil in Bezug auf die Wiederverwendung von Code oder die Klarheit
  2. Dadurch wird der Code erheblich länger / komplexer, ohne dass dies von Vorteil ist

Einige Beispiele

  • Wenn Sie nur einen Cache in Ihrem gesamten Programm haben, extrahieren Sie nicht, es sei denn, Sie glauben, dass Sie wahrscheinlich mit einer Superklasse enden werden
  • Wenn Sie drei verschiedene Arten von Puffern haben, verwenden Sie eine gemeinsame Schnittstellenabstraktion für alle
sdfgeoff
quelle
2

Ich denke, das ist eine kontroverse Meta-Antwort, und ich bin ein bisschen spät dran, aber ich denke, es ist sehr wichtig, dies hier zu erwähnen, weil ich glaube, ich weiß, woher du kommst.

Das Problem bei der Verwendung von Entwurfsmustern besteht darin, dass sie beim Lernen einen Fall wie den folgenden darstellen:

Sie haben dieses spezielle Szenario. Organisieren Sie Ihren Code auf diese Weise. Hier ist ein schickes, aber etwas ausgeklügeltes Beispiel.

Das Problem ist, dass die Dinge, wenn Sie anfangen, echtes Engineering zu betreiben, nicht ganz so einfach sind. Das Designmuster, über das Sie gelesen haben, passt nicht genau zu dem Problem, das Sie lösen möchten. Ganz zu schweigen davon, dass die von Ihnen verwendeten Bibliotheken gegen alle im Text enthaltenen Erklärungen zu diesen Mustern verstoßen, die jeweils auf ihre eigene Art und Weise erstellt wurden. Infolgedessen fühlt sich der von Ihnen geschriebene Code "falsch an" und Sie stellen Fragen wie diese.

Darüber hinaus möchte ich Andrei Alexandrescu zitieren, wenn er über Software-Engineering spricht, der sagt:

Das Software-Engineering weist, vielleicht mehr als jede andere technische Disziplin, eine große Vielfalt auf: Sie können dasselbe auf so viele korrekte Arten tun, und es gibt unendlich viele Nuancen zwischen richtig und falsch.

Vielleicht ist dies etwas übertrieben, aber ich denke, dies erklärt perfekt einen weiteren Grund, warum Sie sich in Ihrem Code möglicherweise weniger sicher fühlen.

In Zeiten wie diesen schreit mir die prophetische Stimme von Mike Acton, Game Engine Lead bei Insomniac, in den Kopf:

KENNEN SIE IHRE DATEN

Er spricht über die Eingaben in Ihr Programm und die gewünschten Ausgaben. Und dann ist da noch dieses Juwel von Fred Brooks aus dem Mythical Man Month:

Zeigen Sie mir Ihre Flussdiagramme und verbergen Sie Ihre Tabellen, und ich werde weiterhin mystifiziert sein. Zeigen Sie mir Ihre Tabellen, und ich benötige normalerweise nicht Ihre Flussdiagramme; Sie werden offensichtlich sein.

Wenn ich Sie wäre, würde ich anhand meines typischen Eingabefalls über mein Problem nachdenken und feststellen, ob es die gewünschte korrekte Ausgabe liefert. Und stell Fragen wie diese:

  • Sind die Ausgabedaten meines Programms korrekt?
  • Wird es für meinen häufigsten Eingabefall effizient / schnell erstellt?
  • Ist mein Code für mich und meine Teamkollegen so einfach, dass ich vor Ort darüber nachdenken kann? Wenn nicht, kann ich es dann einfacher machen?

Wenn Sie dies tun, ist die Frage "Wie viele Ebenen von Abstraktions- oder Entwurfsmustern werden benötigt?" Viel einfacher zu beantworten. Wie viele Abstraktionsebenen benötigen Sie? So viele wie nötig, um diese Ziele zu erreichen, und nicht mehr. "Was ist mit Designmustern? Ich habe keine verwendet!" Nun, wenn die oben genannten Ziele ohne direkte Anwendung eines Musters erreicht wurden, dann ist das in Ordnung. Lassen Sie es funktionieren und fahren Sie mit dem nächsten Problem fort. Beginnen Sie mit Ihren Daten, nicht mit dem Code.

nasser-sh
quelle
2

Softwarearchitektur erfindet Sprachen

Mit jeder Softwareschicht erstellen Sie die Sprache, in der Sie (oder Ihre Mitarbeiter) ihre Lösung auf der nächsthöheren Ebene ausdrücken möchten (daher werde ich in meinem Beitrag einige Analoga in natürlicher Sprache einfügen). Ihre Benutzer möchten nicht jahrelang lernen, wie man diese Sprache liest oder schreibt.

Diese Ansicht hilft mir bei der Entscheidung über architektonische Fragen.

Lesbarkeit

Diese Sprache sollte leicht verständlich sein (damit der Code der nächsten Ebene lesbar ist). Code wird weitaus häufiger gelesen als geschrieben.

Ein Konzept sollte mit einem Wort ausgedrückt werden - eine Klasse oder Schnittstelle sollte das Konzept offen legen. (Slawische Sprachen haben normalerweise zwei verschiedene Wörter für ein englisches Verb, so dass Sie zweimal das Vokabular lernen müssen. Alle natürlichen Sprachen verwenden einzelne Wörter für mehrere Konzepte.)

Konzepte, die Sie aussetzen, sollten keine Überraschungen enthalten. Dabei handelt es sich hauptsächlich um Namenskonventionen wie Get- und Set-Methoden usw. Und Entwurfsmuster können hilfreich sein, da sie ein Standardlösungsmuster darstellen. Der Leser sieht "OK, ich hole die Objekte aus einer Factory" und weiß, was das bedeutet. Aber wenn das bloße Instanziieren einer konkreten Klasse den Job macht, würde ich das vorziehen.

Benutzerfreundlichkeit

Die Sprache sollte einfach zu benutzen sein (was es einfach macht, "richtige Sätze" zu formulieren).

Wenn alle diese MemCache-Klassen / -Schnittstellen für die nächste Ebene sichtbar werden, entsteht für den Benutzer eine steile Lernkurve, bis er versteht, wann und wo welche dieser Wörter für das einzelne Konzept eines Caches zu verwenden sind.

Wenn Sie nur die erforderlichen Klassen / Methoden bereitstellen, kann der Benutzer leichter finden, was er benötigt (siehe DocBrowns-Zitat von Antoine de Saint-Exupery). Das Anzeigen einer Schnittstelle anstelle der implementierenden Klasse kann dies vereinfachen.

Wenn Sie eine Funktionalität bereitstellen, für die ein festgelegtes Entwurfsmuster gelten kann, ist es besser, diesem Entwurfsmuster zu folgen, als etwas anderes zu erfinden. Ihr Benutzer wird APIs, die einem Entwurfsmuster folgen, leichter verstehen als ein völlig anderes Konzept (wenn Sie Italienisch beherrschen, ist Spanisch für Sie einfacher als Chinesisch).

Zusammenfassung

Führen Sie Abstraktionen ein, wenn dies die Verwendung erleichtert (und es sich lohnt, sowohl die Abstraktion als auch die Implementierung zu verwalten).

Wenn Ihr Code eine (nicht triviale) Unteraufgabe hat, lösen Sie ihn "auf die erwartete Weise", dh folgen Sie dem entsprechenden Entwurfsmuster, anstatt einen anderen Radtyp neu zu erfinden.

Ralf Kleberhoff
quelle
1

Es ist wichtig zu berücksichtigen, inwieweit der konsumierende Code, der Ihre Geschäftslogik tatsächlich verarbeitet, über diese Klassen im Zusammenhang mit dem Zwischenspeichern Bescheid weiß. Idealerweise sollte sich Ihr Code nur um das Cache-Objekt kümmern, das er erstellen möchte, und möglicherweise um eine Factory, die dieses Objekt erstellt, wenn eine Konstruktormethode nicht ausreicht.

Die Anzahl der verwendeten Muster oder die Ebene der Vererbung sind nicht zu wichtig, solange jede Ebene gegenüber anderen Entwicklern gerechtfertigt werden kann. Dies schafft eine informelle Grenze, da jede zusätzliche Ebene schwerer zu rechtfertigen ist. Wichtiger ist, wie viele Abstraktionsebenen von Änderungen der funktionalen oder geschäftlichen Anforderungen betroffen sind. Wenn Sie für eine einzelne Anforderung nur eine Ebene ändern können, sind Sie wahrscheinlich nicht überabstrakt oder schlecht abstrahiert. Wenn Sie dieselbe Ebene für mehrere nicht zusammenhängende Änderungen ändern, sind Sie wahrscheinlich unterabstrakt und müssen die Bedenken weiter trennen.

Ryathal
quelle
-1

Erstens ist das Twitter-Zitat falsch. Neue Entwickler müssen ein Modell ausmachen, Abstraktionen würden ihnen in der Regel helfen, "das Bild zu bekommen". Vorausgesetzt, die Abstraktionen machen natürlich Sinn.

Zweitens besteht Ihr Problem nicht in zu vielen oder zu wenigen Abstraktionen, sondern darin, dass anscheinend niemand die Möglichkeit hat, über diese Dinge zu entscheiden. Niemand besitzt den Code, kein einziger Plan / Design / Philosophie ist implementiert, jeder nächste kann tun, was zum Teufel er für diesen Moment für fit hält. Welchen Stil Sie auch wählen, es sollte einer sein.

Martin Maat
quelle
2
Lassen Sie uns die Erfahrung als "Schwindel" abtun. Zu viele Abstraktionen sind ein echtes Problem. Leider fügen die Leute Abstraktion im Vorfeld hinzu, weil "Best Practice", anstatt ein echtes Problem zu lösen. Auch kann niemand "über diese Dinge" entscheiden ... Menschen verlassen Unternehmen, Menschen schließen sich an, niemand übernimmt das Eigentum an ihrem Schlamm.
Rawkode