Warum verstoßen viele Softwareentwickler gegen das Open / Closed-Prinzip?

74

Warum verletzen viele Softwareentwickler das Open / Closed-Prinzip, indem sie viele Dinge wie das Umbenennen von Funktionen ändern, die die Anwendung nach dem Upgrade beschädigen?

Diese Frage springt mir nach der schnellen und der kontinuierlichen Version in der React- Bibliothek in den Kopf .

In kurzen Abständen bemerke ich viele Änderungen in der Syntax, den Komponentennamen, ... usw

Beispiel in der kommenden Version von React :

Neue Verfallswarnungen

Die größte Änderung ist, dass wir React.PropTypes und React.createClass in ihre eigenen Pakete extrahiert haben. Auf beide kann weiterhin über das Hauptobjekt "React" zugegriffen werden. Wenn Sie jedoch eines der beiden Objekte verwenden, wird im Entwicklungsmodus eine Warnung zur einmaligen Verfallserklärung in der Konsole protokolliert. Dies wird zukünftige Optimierungen der Codegröße ermöglichen.

Diese Warnungen wirken sich nicht auf das Verhalten Ihrer Anwendung aus. Wir stellen jedoch fest, dass sie möglicherweise zu Frustrationen führen, insbesondere wenn Sie ein Testframework verwenden, das console.error als Fehler behandelt.


  • Werden diese Änderungen als Verstoß gegen diesen Grundsatz angesehen?
  • Wie lerne ich es als Anfänger von etwas wie Reagieren mit diesen schnellen Änderungen in der Bibliothek (es ist so frustrierend)?
Anyname Donotcare
quelle
6
Dies ist eindeutig ein Beispiel für die Beobachtung , und Ihre Behauptung "so viele" ist unbegründet. Die Lucene- und RichFaces-Projekte sind berüchtigte Beispiele und die Windows COMM-Port-API, aber ich kann mir keine anderen vorstellen. Und ist React wirklich ein "großer Softwareentwickler"?
user207421
62
Wie jedes Prinzip hat die OCP ihren Wert. Aber es erfordert, dass Entwickler unendliche Weitsicht haben. In der realen Welt bekommen die Leute oft ihr erstes Design falsch. Im Laufe der Zeit ziehen es einige vor, ihre alten Fehler aus Gründen der Kompatibilität zu umgehen, andere ziehen es vor, sie schließlich zu bereinigen, um eine kompakte und unbelastete Codebasis zu haben.
Theodoros Chatzigiannakis
1
Wann haben Sie das letzte Mal eine objektorientierte Sprache "wie ursprünglich beabsichtigt" gesehen? Das Kernprinzip war ein Messaging-System, bei dem jeder Teil des Systems von jedermann unendlich erweiterbar ist. Vergleichen Sie das jetzt mit Ihrer typischen OOP-ähnlichen Sprache - wie viele erlauben es Ihnen, eine vorhandene Methode von außen zu erweitern? Wie viele machen es leicht genug, nützlich zu sein?
Luaan
Vermächtnis ist scheiße. 30 Jahre Erfahrung haben gezeigt, dass Sie Ihr Erbe jederzeit vollständig ablegen und von vorne anfangen sollten . Heutzutage hat jeder zu jeder Zeit überall eine Verbindung, so dass das Erbe heutzutage völlig irrelevant ist. Das ultimative Beispiel war "Windows versus Mac". Microsoft hat traditionell versucht, "das Erbe zu unterstützen". Sie sehen dies in vielerlei Hinsicht. Apple hat immer nur "F- - - You" zu Legacy-Nutzern gesagt. (Dies gilt für alle Bereiche, von Sprachen über Geräte bis hin zu Betriebssystemen.) In der Tat war Apple völlig korrekt und MSFT völlig falsch, schlicht und einfach.
Fattie
4
Weil es genau null "Prinzipien" und "Entwurfsmuster" gibt, die im wirklichen Leben 100% der Zeit funktionieren.
Matti Virkkunen

Antworten:

148

IMHO JacquesBs Antwort, obwohl sie viel Wahrheit enthält, zeigt ein grundlegendes Missverständnis der OCP. Um fair zu sein, Ihre Frage drückt auch dieses Missverständnis bereits aus - das Umbenennen von Funktionen bricht die Abwärtskompatibilität , nicht aber die OCP. Wenn eine Unterbrechung der Kompatibilität erforderlich erscheint (oder zwei Versionen derselben Komponente beibehalten werden müssen, um die Kompatibilität nicht zu beeinträchtigen), wurde das OCP bereits zuvor unterbrochen!

Wie Jörg W Mittag bereits in seinen Kommentaren erwähnt hat, lautet das Prinzip nicht "Sie können das Verhalten einer Komponente nicht ändern" - es heißt, man sollte versuchen , Komponenten so zu gestalten, dass sie offen für Wiederverwendung (oder Erweiterung) sind. in mehrfacher Hinsicht ohne die Notwendigkeit einer Änderung. Dies kann durch Angabe der richtigen "Erweiterungspunkte" oder, wie von @AntP erwähnt, "durch Zerlegen einer Klassen- / Funktionsstruktur bis zu dem Punkt geschehen, an dem standardmäßig jeder natürliche Erweiterungspunkt vorhanden ist". IMHO, das dem OCP folgt, hat nichts mit "die alte Version aus Gründen der Abwärtskompatibilität unverändert lassen" zu tun ! Oder zitieren Sie @ DerekElkins Kommentar unten:

Das OCP gibt Ratschläge zum Schreiben eines Moduls [...] und nicht zur Implementierung eines Change-Management-Prozesses, bei dem sich Module niemals ändern können.

Gute Programmierer nutzen ihre Erfahrung, um Komponenten unter Berücksichtigung der "richtigen" Erweiterungspunkte zu entwerfen (oder - noch besser - so, dass keine künstlichen Erweiterungspunkte erforderlich sind). Um dies jedoch korrekt und ohne unnötige Überarbeitung durchführen zu können, müssen Sie im Voraus wissen, wie zukünftige Anwendungsfälle Ihrer Komponente aussehen könnten. Selbst erfahrene Programmierer können nicht in die Zukunft schauen und kennen alle anstehenden Anforderungen im Voraus. Und deshalb muss manchmal die Abwärtskompatibilität verletzt werden - unabhängig davon, wie viele Erweiterungspunkte Ihre Komponente hat oder wie gut sie dem OCP in Bezug auf bestimmte Arten von Anforderungen entspricht, wird es immer eine Anforderung geben, die nicht einfach ohne Änderung implementiert werden kann die Komponente.

Doc Brown
quelle
14
IMO ist der Hauptgrund für "Verstöße" gegen OCP, dass es viel Mühe kostet, sich richtig daran zu halten. Eric Lippert hat einen hervorragenden Blogbeitrag darüber verfasst, warum viele der .NET Framework-Klassen offenbar gegen OCP verstoßen.
BJ Myers
2
@BJMyers: danke für den Link. Jon Skeet hat einen ausgezeichneten Beitrag zur OCP geleistet, da er der Idee der geschützten Variation sehr ähnlich ist.
Doc Brown
8
DIESE! Das OCP sagt, dass Sie Code schreiben sollten, der geändert werden kann, ohne berührt zu werden! Warum? Sie müssen es also nur einmal testen, überprüfen und kompilieren. Neues Verhalten sollte aus neuem Code kommen. Nicht durch Verschrauben mit altbewährtem Code. Was ist mit Refactoring? Refactoring ist ein klarer Verstoß gegen OCP! Aus diesem Grund ist es eine Sünde, Code zu schreiben und zu denken, dass Sie ihn nur umgestalten werden, wenn sich Ihre Annahmen ändern. Nein! Legen Sie jede Annahme in eine eigene kleine Schachtel. Wenn es falsch ist, reparieren Sie die Box nicht. Schreiben Sie eine neue. Warum? Möglicherweise müssen Sie zum alten zurückkehren. Wenn Sie das tun, wäre es schön, wenn es immer noch funktioniert.
candied_orange
7
@CandiedOrange: danke für deinen Kommentar. Ich sehe Refactoring und OCP nicht so gegensätzlich, wie Sie es beschreiben. Um Komponenten zu schreiben, die dem OCP folgen, sind häufig mehrere Refactoring-Zyklen erforderlich. Das Ziel sollte eine Komponente sein, die keine Modifikationen benötigt, um eine ganze "Familie" von Anforderungen zu lösen. Nichtsdestotrotz sollte man einer Komponente keine willkürlichen Erweiterungspunkte hinzufügen, "nur für den Fall", dass es zu leicht zu Überentwicklungen kommt. In vielen Fällen kann es die bessere Alternative sein, sich auf die Möglichkeit des Refactorings zu verlassen.
Doc Brown
4
Diese Antwort macht einen guten Job, um die Fehler in der (derzeit) Top-Antwort hervorzuheben. Ich denke, der Schlüssel zum Erfolg beim Öffnen / Schließen ist jedoch, aufhören , an "Erweiterungspunkte" zu denken und darüber nachzudenken, Ihre zu zerlegen Klassen- / Funktionsstruktur bis zu dem Punkt, an dem standardmäßig jeder natürliche Erweiterungspunkt vorhanden ist. Die Programmierung von "Outside In" ist eine sehr gute Möglichkeit, um dies zu erreichen. Dabei wird jedes Szenario, für das Ihre aktuelle Methode / Funktion geeignet ist, auf eine externe Schnittstelle verschoben, die einen natürlichen Erweiterungspunkt für Dekorateure, Adapter usw. darstellt.
Ant P
67

Das Open / Closed-Prinzip hat Vorteile, aber auch einige gravierende Nachteile.

Theoretisch löst das Prinzip das Problem der Abwärtskompatibilität, indem Code erstellt wird, der "offen für Erweiterungen, aber geschlossen für Änderungen" ist. Wenn für eine Klasse neue Anforderungen gelten, ändern Sie niemals den Quellcode der Klasse selbst, sondern erstellen stattdessen eine Unterklasse, die nur die zum Ändern des Verhaltens erforderlichen Elemente überschreibt. Der gesamte Code, der gegen die Originalversion der Klasse geschrieben wurde, ist daher nicht betroffen. Sie können also sicher sein, dass Ihre Änderung den vorhandenen Code nicht beschädigt hat.

In der Realität kommt es leicht zu einer Aufblähung des Codes und zu einem verwirrenden Durcheinander veralteter Klassen. Wenn es nicht möglich ist, ein Verhalten einer Komponente durch Erweiterung zu ändern, müssen Sie eine neue Variante der Komponente mit dem gewünschten Verhalten bereitstellen und die alte Version aus Gründen der Abwärtskompatibilität unverändert lassen.

Angenommen, Sie entdecken einen grundlegenden Konstruktionsfehler in einer Basisklasse, von der viele Klassen erben. Angenommen, der Fehler ist darauf zurückzuführen, dass ein privates Feld vom falschen Typ ist. Sie können dies nicht beheben, indem Sie ein Mitglied überschreiben. Grundsätzlich müssen Sie die gesamte Klasse überschreiben, was bedeutet, dass Sie letztendlich erweitern Object, um eine alternative Basisklasse bereitzustellen - und jetzt müssen Sie auch Alternativen für alle Unterklassen bereitstellen, wodurch eine doppelte Objekthierarchie entsteht, eine Hierarchie fehlerhaft, eine verbesserte . Sie können die fehlerhafte Hierarchie jedoch nicht entfernen (da das Löschen des Codes eine Änderung darstellt). Alle zukünftigen Clients sind beiden Hierarchien ausgesetzt.

Die theoretische Antwort auf dieses Problem lautet nun "Entwerfen Sie es einfach beim ersten Mal richtig". Wenn der Code perfekt zerlegt ist, keine Fehler aufweist und mit Erweiterungspunkten versehen ist, die für alle möglichen zukünftigen Änderungen der Anforderungen vorbereitet sind, vermeiden Sie das Durcheinander. Aber in Wirklichkeit macht jeder Fehler und niemand kann die Zukunft perfekt vorhersagen.

Nehmen Sie etwas wie das .NET-Framework - es enthält immer noch eine Reihe von Auflistungsklassen, die entworfen wurden, bevor Generika vor mehr als einem Jahrzehnt eingeführt wurden. Dies ist sicherlich ein Segen für die Abwärtskompatibilität (Sie können das Framework aktualisieren, ohne etwas neu schreiben zu müssen), aber es erschwert auch das Framework und bietet Entwicklern zahlreiche Optionen, bei denen viele einfach veraltet sind.

Anscheinend haben die Entwickler von React das Gefühl, dass es den Aufwand an Komplexität und Code-Bloat nicht wert war, sich strikt an das Open / Closed-Prinzip zu halten.

Die pragmatische Alternative zum Öffnen / Schließen ist die kontrollierte Abwertung. Anstatt die Abwärtskompatibilität in einem einzelnen Release zu unterbrechen, werden alte Komponenten für einen Release-Zyklus beibehalten, aber Clients werden über Compiler-Warnungen darüber informiert, dass der alte Ansatz in einem späteren Release entfernt wird. Dies gibt den Clients Zeit, den Code zu ändern. Dies scheint in diesem Fall der Ansatz von React zu sein.

(Meine Interpretation des Prinzips basiert auf dem Open-Closed-Prinzip von Robert C. Martin)

JacquesB
quelle
37
"Das Prinzip besagt grundsätzlich, dass Sie das Verhalten einer Komponente nicht ändern können. Stattdessen müssen Sie eine neue Variante der Komponente mit dem gewünschten Verhalten versehen und die alte Version unverändert lassen, um die Abwärtskompatibilität zu gewährleisten." - Ich bin damit nicht einverstanden. Das Prinzip besagt, dass Sie Komponenten so entwerfen sollten, dass das Verhalten nicht geändert werden muss, da Sie es erweitern können, um das zu tun, was Sie möchten. Das Problem ist, dass wir noch nicht herausgefunden haben, wie das geht, insbesondere bei den Sprachen, die derzeit weit verbreitet sind. Das Ausdrucksproblem ist ein Teil von…
Jörg W Mittag
8
... das zum Beispiel. Weder Java noch C♯ haben eine Lösung für den Ausdruck. Haskell und Scala tun dies, aber ihre Nutzerbasis ist viel kleiner.
Jörg W Mittag
1
@ Giorgio: In Haskell sind die Lösungen Typklassen. In Scala heißt die Lösung Implizite und Objekte. Entschuldigung, ich habe die Links momentan nicht zur Hand. Ja, Multimethoden (eigentlich müssen sie nicht einmal "multi" sein, es ist eher die "offene" Natur von Lisps Methoden, die benötigt wird) sind ebenfalls eine mögliche Lösung. Beachten Sie, dass das Ausdrucksproblem mehrfach formuliert ist, da die Artikel in der Regel so geschrieben sind, dass der Autor das Ausdrucksproblem einschränkt, was dazu führt, dass alle derzeit vorhandenen Lösungen ungültig werden, und dann zeigt, wie seine eigenen…
Jörg W Mittag
1
… Die Sprache kann diese "härtere" Version sogar lösen. Zum Beispiel formulierte Wadler das Ausdrucksproblem ursprünglich so, dass es sich nicht nur um eine modulare Erweiterung, sondern auch um eine statisch sichere modulare Erweiterung handelte. Gängige Lisp-Multimethoden sind jedoch nicht statisch, sondern nur dynamisch sicher. Odersky hat dies dann noch verstärkt, indem er sagte, es sollte modular statisch sicher sein, dh die Sicherheit sollte statisch überprüfbar sein, ohne das gesamte Programm zu betrachten, nur durch einen Blick auf das Erweiterungsmodul. Dies ist mit Haskell-Typklassen nicht möglich, aber mit Scala. Und in der…
Jörg W Mittag
2
@ Giorgio: Genau. Das, was Common Lisp Multimethods dazu bringt, die EP zu lösen, ist eigentlich kein Mehrfachversand. Es ist die Tatsache, dass die Methoden offen sind. In einer typischen FP (oder prozeduralen Programmierung) ist die Typunterscheidung an die Funktionen gebunden. In typischen OO sind die Methoden an die Typen gebunden. Gängige Lisp-Methoden sind offen , sie können nachträglich und in einem anderen Modul zu Klassen hinzugefügt werden. Das ist die Funktion, mit der sie zum Lösen der EP verwendet werden können. Zum Beispiel sind Clojures Protokolle Einzelversand, lösen aber auch die EP (solange Sie nicht auf statischer Sicherheit bestehen).
Jörg W Mittag
20

Ich würde das offene / geschlossene Prinzip als Ideal bezeichnen. Wie bei allen Idealen wird die Realität der Softwareentwicklung kaum berücksichtigt. Ebenso wie alle Ideale ist es unmöglich, es in der Praxis tatsächlich zu erreichen - man bemüht sich lediglich, sich diesem Ideal so gut wie möglich anzunähern.

Die andere Seite der Geschichte ist als goldene Handschellen bekannt. Goldene Handschellen sind das, was Sie bekommen, wenn Sie sich zu sehr dem offenen / geschlossenen Prinzip unterwerfen. Goldene Handschellen treten auf, wenn Ihr Produkt, das niemals die Rückwärtskompatibilität bricht, nicht wachsen kann, weil in der Vergangenheit zu viele Fehler gemacht wurden.

Ein bekanntes Beispiel hierfür ist der Windows 95-Speichermanager. Im Rahmen des Marketings für Windows 95 wurde angegeben, dass alle Windows 3.1-Anwendungen unter Windows 95 funktionieren würden. Microsoft erwarb Lizenzen für Tausende von Programmen, um sie unter Windows 95 zu testen. Einer der Problemfälle war Sim City. Sim City hatte tatsächlich einen Fehler, der dazu führte, dass in den nicht zugewiesenen Speicher geschrieben wurde. In Windows 3.1 ohne einen "richtigen" Speichermanager handelte es sich hierbei um einen geringfügigen Fauxpas. In Windows 95 würde der Speichermanager dies jedoch abfangen und einen Segmentierungsfehler verursachen. Die Lösung? Wenn Ihr Anwendungsname unter Windows 95 lautet simcity.exe, lockert das Betriebssystem die Einschränkungen des Speichermanagers, um den Segmentierungsfehler zu vermeiden!

Das eigentliche Problem hinter diesem Ideal sind die reduzierten Konzepte von Produkten und Dienstleistungen. Niemand tut wirklich das eine oder andere. Alles reiht sich irgendwo im grauen Bereich zwischen den beiden aneinander. Wenn Sie von einem produktorientierten Ansatz ausgehen, klingt Öffnen / Schließen nach einem großartigen Ideal. Ihre Produkte sind zuverlässig. Wenn es um Dienstleistungen geht, ändert sich die Geschichte. Es ist leicht zu zeigen, dass mit dem Open / Closed-Prinzip die Menge an Funktionen, die Ihr Team unterstützen muss, sich asymptotisch der Unendlichkeit annähern muss , da Sie niemals alte Funktionen bereinigen können. Dies bedeutet, dass Ihr Entwicklungsteam jedes Jahr mehr Code unterstützen muss. Schließlich erreichen Sie eine Sollbruchstelle.

Die meiste Software, insbesondere Open Source, folgt heute einer gelockerten Version des Open / Closed-Prinzips. Es ist sehr verbreitet, dass Open / Closed für kleinere Releases sklavisch gefolgt, für größere Releases jedoch aufgegeben wird. Zum Beispiel enthält Python 2.7 viele "schlechte Entscheidungen" aus Python 2.0 und 2.1, aber Python 3.0 hat sie alle beseitigt. (Auch die Umstellung von der Windows 95-Codebasis auf die Windows NT-Codebasis bei der Veröffentlichung von Windows 2000 brachte viele Dinge zum Erliegen, aber es bedeutete, dass wir uns nie mit einem Speichermanager befassen mussten, der den Anwendungsnamen überprüfte, um über das Verhalten zu entscheiden!)

Cort Ammon
quelle
Das ist eine ziemlich gute Geschichte über SimCity. Hast du eine Quelle?
BJ Myers
5
@BJMyers Es ist eine alte Geschichte, Joel Spoleky erwähnt sie am Ende dieses Artikels . Ich habe es ursprünglich als Teil eines Buches über die Entwicklung von Videospielen vor Jahren gelesen.
Cort Ammon
1
@BJMyers: Ich bin mir ziemlich sicher, dass sie ähnliche Kompatibilitäts- "Hacks" für Dutzende gängiger Anwendungen hatten.
Doc Brown
3
@BJMyers es gibt eine Menge solcher Sachen, wenn Sie eine gute Lektüre wünschen, gehen Sie zu The Old New Thing Blog von Raymond Chen , durchsuchen Sie den History-Tag oder suchen Sie nach "Kompatibilität". Man kann sich an viele Geschichten erinnern, auch an etwas, das dem oben erwähnten SimCity-Fall auffallend ähnlich ist - Addentum: Chen nennt Namen nicht gerne schuld.
Theraot
2
Beim 95-> NT-Übergang haben nur sehr wenige Probleme geklappt. Das ursprüngliche SimCity für Windows funktioniert unter Windows 10 (32-Bit) immer noch hervorragend. Sogar DOS-Spiele funktionieren einwandfrei, vorausgesetzt, Sie deaktivieren den Ton oder verwenden VDMSound, damit das Konsolensubsystem den Ton ordnungsgemäß verarbeiten kann. Microsoft nimmt die Abwärtskompatibilität sehr ernst, und es werden auch keine Verknüpfungen "Lassen Sie es uns in eine virtuelle Maschine einfügen" verwendet. Es braucht manchmal eine Umgehung, aber das ist immer noch ziemlich beeindruckend, besonders in relativer Hinsicht.
Luaan
11

Die Antwort von Doc Brown ist am ehesten zutreffend, die anderen Antworten veranschaulichen Missverständnisse des Open-Closed-Prinzips.

Um ausdrücklich das Missverständnis zu artikulieren, so scheint es ein Glaube zu sein , dass das OCP bedeutet , dass Sie nicht rückwärts inkompatible Änderungen vornehmen (oder sogar alle Änderungen oder etwas in diese Richtung.) Die OCP - Komponenten über die Gestaltung so , dass Sie nicht brauchen , um Nehmen Sie Änderungen vor, um die Funktionalität zu erweitern, unabhängig davon, ob diese Änderungen abwärtskompatibel sind oder nicht. Neben der Hinzufügung von Funktionen gibt es viele andere Gründe, aus denen Sie Änderungen an einer Komponente vornehmen können, unabhängig davon, ob diese abwärtskompatibel (z. B. Refactoring oder Optimierung) oder abwärtskompatibel (z. B. Ablehnen und Entfernen von Funktionen) ist. Dass Sie diese Änderungen vornehmen, bedeutet nicht, dass Ihre Komponente gegen das OCP verstoßen hat (und bedeutet definitiv nicht, dass Sie dies tun gegen die OCP verstoßen).

Wirklich, es geht überhaupt nicht um Quellcode. Eine abstraktere und relevantere Aussage der OCP lautet: "Eine Komponente sollte eine Erweiterung ermöglichen, ohne dass dabei ihre Abstraktionsgrenzen verletzt werden müssen." Ich würde noch weiter gehen und sagen , eine modernere Interpretation ist: „eine Komponente sollte erzwingen seine Abstraktion Grenzen aber für die Erweiterung ermöglichen“. Sogar in dem Artikel über das OCP von Bob Martin, in dem er "für Modifikationen verschlossen" beschreibt, dass "der Quellcode unverletzt ist", spricht er später von Kapselung, die nichts mit Modifikationen des Quellcodes und allem mit Abstraktion zu tun hat Grenzen.

Die fehlerhafte Prämisse in der Frage ist also, dass das OCP eine Richtlinie über die Entwicklung einer Codebasis ist (beabsichtigt ist). Das OCP wird in der Regel als Slogan bezeichnet: "Eine Komponente sollte für Erweiterungen offen und für Änderungen durch Verbraucher geschlossen sein." Grundsätzlich sollten Verbraucher einer Komponente, die der Komponente Funktionen hinzufügen möchten, in der Lage sein, die alte Komponente durch die zusätzlichen Funktionen zu erweitern, die alte Komponente jedoch nicht zu ändern .

Das OCP sagt nichts über den Schöpfer einer Komponente aus , die Funktionen ändert oder entfernt . Die OCP plädiert nicht dafür, die Fehlerkompatibilität für immer aufrechtzuerhalten . Sie als Urheber verletzen das OCP nicht, indem Sie eine Komponente ändern oder sogar entfernen. Sie, oder besser gesagt die Komponenten, die Sie geschrieben haben, verletzen das OCP, wenn die Konsumenten Ihre Komponenten nur durch Mutation, z. B. durch Affen-Patching , funktionalisieren könnenoder Zugriff auf den Quellcode und erneutes Kompilieren. In vielen Fällen handelt es sich nicht um Optionen für den Verbraucher, dh wenn Ihre Komponente nicht "erweiterungsfähig" ist, hat er kein Glück. Sie können Ihre Komponente einfach nicht für ihre Bedürfnisse verwenden. Die OCP plädiert dafür, die Konsumenten Ihrer Bibliothek nicht in diese Position zu versetzen, zumindest in Bezug auf eine erkennbare Klasse von "Erweiterungen". Selbst wenn Änderungen können auf den Quellcode oder sogar die primäre Kopie des Quellcodes gemacht werden, ist es am besten zu „vorgeben“ , dass Sie es nicht ändern können , da es viele möglichen negativen Folgen sind so zu tun.

Um Ihre Fragen zu beantworten: Nein, dies sind keine Verstöße gegen die OCP. Keine Änderung, die ein Autor vornimmt, kann einen Verstoß gegen das OCP darstellen, da das OCP kein Verhältnis von Änderungen darstellt. Die Änderungen können jedoch erstellen Verletzungen des OCP, und sie können durch Ausfälle der OCP in früheren Versionen der Code - Basis motiviert werden. Das OCP ist eine Eigenschaft eines bestimmten Codeteils, nicht die Evolutionsgeschichte einer Codebasis.

Für dagegen die Abwärtskompatibilität ist eine Eigenschaft einer Änderung des Codes. Es macht keinen Sinn zu sagen, dass ein Teil des Codes abwärtskompatibel ist oder nicht. Es ist nur sinnvoll, über die Abwärtskompatibilität eines Codes mit einem älteren Code zu sprechen . Daher ist es nie sinnvoll, davon zu sprechen, dass der erste Teil eines Codes abwärtskompatibel ist oder nicht. Der erste Codeschnitt kann das OCP erfüllen oder nicht erfüllen, und im Allgemeinen können wir feststellen, ob ein Code das OCP erfüllt, ohne auf historische Versionen des Codes Bezug zu nehmen.

Was Ihre letzte Frage anbelangt, so ist StackExchange im Allgemeinen wohl eher als meinungsbasiert eingestuft, aber kurz gesagt, es ist willkommen, JavaScript zu verwenden, wobei das von Ihnen beschriebene Phänomen in den letzten Jahren als JavaScript-Müdigkeit bezeichnet wurde . (Fühlen Sie sich frei zu googeln , um eine Vielzahl anderer Artikel zu finden, von denen einige satirisch sind und darüber aus verschiedenen Perspektiven sprechen.)

Derek Elkins
quelle
3
"Sie als Urheber verletzen das OCP nicht, indem Sie eine Komponente ändern oder sogar entfernen." - Können Sie hierzu einen Hinweis geben? Keine der Definitionen des Prinzips, die ich gesehen habe, besagt, dass "der Schöpfer" (was auch immer das bedeutet) vom Prinzip ausgenommen ist. Das Entfernen einer veröffentlichten Komponente ist eindeutig eine grundlegende Änderung.
JacquesB
1
@JacquesB Personen und sogar Codeänderungen verletzen die OCP nicht, was Komponenten (dh tatsächliche Codeteile) tun. (Um ganz klar zu sein, bedeutet dies, dass die Komponente dem OCP selbst nicht gerecht wird und nicht das OCP einer anderen Komponente verletzt.) Der springende Punkt meiner Antwort ist, dass das OCP nicht über Codeänderungen spricht , brechen oder auf andere Weise. Eine Komponente kann entweder erweitert und geändert werden oder nicht, genau wie eine Methode private. Wenn ein Autor später eine privateMethode erstellt public, bedeutet dies nicht, dass er die Zugriffskontrolle verletzt hat (1/2)
Derek Elkins,
2
... und das heißt auch nicht, dass die Methode privatevorher nicht wirklich war. "Das Entfernen einer veröffentlichten Komponente ist eindeutig eine entscheidende Änderung", heißt es nicht. Entweder erfüllen die Komponenten der neuen Version die Anforderungen des OCP, oder sie erfüllen diese nicht. Sie benötigen nicht den Verlauf der Codebasis, um dies zu bestimmen. Nach Ihrer Logik könnte ich niemals Code schreiben, der das OCP erfüllt. Sie verbinden die Abwärtskompatibilität, eine Eigenschaft von Codeänderungen, mit der OCP, einer Eigenschaft von Code. Ihr Kommentar ist ungefähr so ​​sinnvoll, als würde er sagen, dass Quicksort nicht abwärtskompatibel ist. (2/2)
Derek Elkins
3
@JacquesB Beachten Sie zunächst noch einmal, dass es sich um ein Modul handelt , das dem OCP entspricht. Das OCP gibt Ratschläge zum Schreiben eines Moduls, damit das Modul angesichts der Einschränkung, dass der Quellcode nicht geändert werden kann, trotzdem erweitert werden kann. Zuvor ging es ihm um das Entwerfen von Modulen, die sich nie ändern, und nicht um die Implementierung eines Change-Management-Prozesses, bei dem sich Module niemals ändern können. Wenn Sie sich auf die Bearbeitung Ihrer Antwort beziehen, brechen Sie das OCP nicht, indem Sie den Code des Moduls ändern. Wenn das Modul "erweitert" werden soll, müssen Sie stattdessen den Quellcode ändern (1/3)
Derek Elkins,
2
"Das OCP ist eine Eigenschaft eines bestimmten Codeteils, nicht die Entwicklungsgeschichte einer Codebasis." - Ausgezeichnet!
Doc Brown