Dlaczego wielu programistów narusza zasadę otwartego / zamkniętego?

74

Dlaczego wielu programistów narusza zasadę otwartego / zamkniętego , modyfikując wiele rzeczy, takich jak zmiana nazw funkcji, które spowodują uszkodzenie aplikacji po aktualizacji?

To pytanie przeskakuje mi do głowy po szybkich i ciągłych wersjach biblioteki React .

Co krótki okres zauważam wiele zmian w składni, nazwach komponentów, itp

Przykład w nadchodzącej wersji React :

Nowe ostrzeżenia o wycofaniu

Największą zmianą jest to, że wyodrębniliśmy React.PropTypes i React.createClass we własnych pakietach. Oba są nadal dostępne za pośrednictwem głównego obiektu React, ale użycie jednego z nich spowoduje zarejestrowanie jednorazowego ostrzeżenia o wycofaniu do konsoli w trybie programowania. Umożliwi to przyszłe optymalizacje rozmiaru kodu.

Te ostrzeżenia nie wpłyną na zachowanie Twojej aplikacji. Zdajemy sobie jednak sprawę, że mogą powodować frustrację, szczególnie jeśli używasz środowiska testowego, które traktuje plik console.error jako błąd.


  • Czy zmiany te są uważane za naruszenie tej zasady?
  • Jako początkujący coś takiego jak React , jak mogę się tego nauczyć dzięki tym szybkim zmianom w bibliotece (to takie frustrujące)?
Anyname Donotcare
źródło
6
Jest to wyraźnie przykład jego zaobserwowania , a twoje twierdzenie, że „tak wielu” jest bezpodstawne. Projekty Lucene i RichFaces są znanymi przykładami i interfejsem API Windows COMM, ale nie mogę wymyślić innych. I czy React to naprawdę „duży programista”?
user207421,
62
Jak każda zasada, OCP ma swoją wartość. Wymaga to jednak od programistów nieskończonego przewidywania. W prawdziwym świecie ludzie często mylą swój pierwszy projekt. Z biegiem czasu niektórzy wolą obejść swoje stare błędy ze względu na kompatybilność, inni wolą je ostatecznie wyczyścić, aby mieć zwartą i nieobciążoną bazę kodu.
Theodoros Chatzigiannakis
1
Kiedy ostatni raz widziałeś język zorientowany obiektowo „tak, jak pierwotnie zamierzałeś”? Podstawową zasadą był system przesyłania wiadomości, który oznaczał, że każda część systemu jest nieskończenie rozszerzalna przez każdego. Porównaj to teraz z typowym językiem podobnym do OOP - ile pozwala na rozszerzenie istniejącej metody z zewnątrz? Ilu sprawia, że ​​jest to wystarczająco łatwe, aby być użytecznym?
Luaan
Dziedzictwo jest do bani. 30 lat doświadczenia pokazało, że powinieneś całkowicie wyrzucić dziedzictwo i zacząć od nowa przez cały czas. Dzisiaj każdy ma połączenie przez cały czas, więc spuścizna jest dziś zupełnie nieistotna. najlepszym przykładem był „Windows kontra Mac”. Microsoft tradycyjnie próbował „wspierać starsze”, widać to na wiele sposobów. Firma Apple zawsze mówiła „F- - - You” starszym użytkownikom. (Dotyczy to wszystkiego, od języków, urządzeń i systemów operacyjnych). W rzeczywistości Apple miał całkowitą rację, a MSFT było całkowicie błędne, proste i proste.
Fattie
4
Ponieważ istnieją dokładnie zero „zasad” i „wzorców projektowych”, które działają w 100% przypadków w prawdziwym życiu.
Matti Virkkunen

Odpowiedzi:

148

Odpowiedź IMHO JacquesB, choć zawiera wiele prawdy, pokazuje podstawowe nieporozumienie OCP. Aby być uczciwym, twoje pytanie również wyraża to nieporozumienie - zmiana nazw funkcji narusza wsteczną kompatybilność , ale nie OCP. Jeśli konieczne jest złamanie kompatybilności (lub utrzymanie dwóch wersji tego samego komponentu, aby nie złamać kompatybilności), OCP był już wcześniej uszkodzony!

Jak już wspomniał Jörg W Mittag w swoich komentarzach, zasada nie mówi „nie można modyfikować zachowania komponentu” - mówi, że należy spróbować zaprojektować komponenty w taki sposób, aby były otwarte do ponownego wykorzystania (lub rozszerzenia) na kilka sposobów, bez potrzeby modyfikacji. Można tego dokonać, zapewniając odpowiednie „punkty rozszerzenia” lub, jak wspomniano w @AntP, „rozkładając strukturę klasy / funkcji do punktu, w którym domyślnie znajduje się każdy naturalny punkt rozszerzenia”. IMHO podążając za OCP nie ma nic wspólnego z „utrzymywaniem starej wersji bez zmian dla kompatybilności wstecznej” ! Lub cytując komentarz @ DerekElkin poniżej:

OCP jest radą, jak napisać moduł [...], a nie wdrażać proces zarządzania zmianami, który nigdy nie pozwala na zmianę modułów.

Dobrzy programiści wykorzystują swoje doświadczenie do projektowania komponentów z myślą o „właściwych” punktach rozszerzenia (lub - jeszcze lepiej - w taki sposób, że nie są potrzebne żadne sztuczne punkty rozszerzenia). Jednak, aby zrobić to poprawnie i bez zbędnej inżynierii, musisz wcześniej wiedzieć, jak mogą wyglądać przyszłe przypadki użycia twojego komponentu. Nawet doświadczeni programiści nie mogą wcześniej spojrzeć w przyszłość i poznać wszystkich przyszłych wymagań. I dlatego czasami trzeba naruszać kompatybilność wsteczną - bez względu na to, ile punktów rozszerzeń ma twój komponent lub jak dobrze przestrzega OCP w odniesieniu do niektórych rodzajów wymagań, zawsze będzie wymaganie, którego nie można łatwo wdrożyć bez modyfikacji składnik.

Doktor Brown
źródło
14
IMO największym powodem „naruszenia” OCP jest to, że prawidłowe dostosowanie się do niego wymaga wiele wysiłku. Eric Lippert ma świetny post na blogu o tym, dlaczego wiele klas frameworka .NET wydaje się naruszać OCP.
BJ Myers
2
@BJMyers: dzięki za link. Jon Skeet ma doskonały post na temat OCP, ponieważ jest bardzo podobny do idei chronionej odmiany.
Dok. Brown
8
TO! OCP mówi, że powinieneś pisać kod, który można zmienić bez dotykania! Dlaczego? Musisz go tylko przetestować, przejrzeć i skompilować tylko raz. Nowe zachowanie powinno pochodzić z nowego kodu. Nie przez wkręcanie starego sprawdzonego kodu. Co z refaktoryzacją? Refaktoryzacja odwiertów stanowi wyraźne naruszenie OCP! Dlatego grzechem jest pisać kod, myśląc, że po prostu zmienimy go, jeśli zmienią się twoje założenia. Nie! Umieść każde założenie w osobnym małym pudełku. Kiedy jest źle, nie naprawiaj pudełka. Napisz nowy. Dlaczego? Ponieważ być może będziesz musiał wrócić do starego. Gdy to zrobisz, byłoby miło, gdyby nadal działało.
candied_orange 30.04.17
7
@CandiedOrange: dzięki za komentarz. Nie widzę refaktoryzacji i OCP tak przeciwnie, jak to opisujesz. Pisanie komponentów zgodnych z OCP wymaga często kilku cykli refaktoryzacji. Celem powinien być komponent, który nie wymaga modyfikacji, aby rozwiązać całą „rodzinę” wymagań. Niemniej jednak nie należy dodawać dowolnych punktów rozszerzenia do elementu „na wszelki wypadek”, który zbyt łatwo prowadzi do nadinżynierii. Powoływanie się na możliwość refaktoryzacji może być lepszą alternatywą w wielu przypadkach.
Doc Brown
4
Ta odpowiedź dobrze sprawdza się w wywoływaniu błędów w (obecnie) najważniejszej odpowiedzi - myślę, że kluczową rzeczą w sukcesie z otwartym / zamkniętym jest przestanie myśleć w kategoriach „punktów rozszerzenia” i zacząć myśleć o rozkładzie twojego struktura klasy / funkcji do punktu, w którym domyślnie znajduje się każdy naturalny punkt rozszerzenia. Programowanie „na zewnątrz” jest bardzo dobrym sposobem na osiągnięcie tego, w którym każdy scenariusz, do którego odnosi się obecna metoda / funkcja, jest wypychany do zewnętrznego interfejsu, który stanowi naturalny punkt rozszerzenia dla dekoratorów, adapterów itp.
Ant P
67

Zasada otwarta / zamknięta ma zalety, ale ma również poważne wady.

Teoretycznie zasada rozwiązuje problem kompatybilności wstecznej, tworząc kod „otwarty na rozszerzenie, ale zamknięty na modyfikację”. Jeśli klasa ma jakieś nowe wymagania, nigdy nie modyfikujesz kodu źródłowego samej klasy, ale tworzy podklasę, która zastępuje tylko odpowiednie elementy niezbędne do zmiany zachowania. W związku z tym nie ma to wpływu na cały kod napisany w stosunku do oryginalnej wersji klasy, więc możesz mieć pewność, że zmiana nie spowodowała uszkodzenia istniejącego kodu.

W rzeczywistości łatwo kończy się wzdęciem kodu i mylącym bałaganem przestarzałych klas. Jeśli nie jest możliwe zmodyfikowanie niektórych zachowań komponentu poprzez rozszerzenie, należy podać nowy wariant komponentu o pożądanym zachowaniu i zachować starą wersję w niezmienionej formie, aby zachować zgodność wsteczną.

Powiedzmy, że odkryłeś podstawową wadę projektową w klasie bazowej, z której dziedziczy wiele klas. Powiedzmy, że błąd wynika z niewłaściwego typu prywatnego pola. Nie można tego naprawić, zastępując członka. Zasadniczo musisz przesłonić całą klasę, co oznacza, że ​​kończysz na rozszerzeniu, Objectaby zapewnić alternatywną klasę podstawową - a teraz musisz również zapewnić alternatywy dla wszystkich podklas, w ten sposób uzyskując podwójną hierarchię obiektów, jedną wadliwą hierarchię, jedną ulepszoną . Nie można jednak usunąć wadliwej hierarchii (ponieważ usunięcie kodu jest modyfikacją), wszyscy przyszli klienci będą narażeni na działanie obu hierarchii.

Teraz teoretyczną odpowiedzią na ten problem jest „po prostu zaprojektuj go poprawnie za pierwszym razem”. Jeśli kod jest doskonale rozłożony, bez żadnych wad i błędów i zaprojektowany z punktami rozszerzenia przygotowanymi na wszystkie możliwe przyszłe zmiany wymagań, unikniesz bałaganu. Ale w rzeczywistości wszyscy popełniają błędy i nikt nie jest w stanie doskonale przewidzieć przyszłości.

Weźmy coś w rodzaju .NET Framework - wciąż zawiera on zbiór klas kolekcji, które zostały zaprojektowane przed wprowadzeniem generics ponad dziesięć lat temu. Jest to z pewnością dobrodziejstwo dla kompatybilności wstecznej (możesz uaktualnić framework bez konieczności przepisywania czegokolwiek), ale także rozpręża ramę i oferuje programistom duży zestaw opcji, z których wiele jest po prostu przestarzała.

Najwyraźniej programiści React uważali, że nie opłaca się kosztować złożoności i rozdętego kodu, aby ściśle przestrzegać zasady otwartej / zamkniętej.

Pragmatyczną alternatywą dla otwierania / zamykania jest kontrolowane wycofanie. Zamiast łamania wstecznej kompatybilności w jednym wydaniu, stare komponenty są przechowywane przez cykl wydania, ale klienci są informowani za pomocą ostrzeżeń kompilatora, że ​​stare podejście zostanie usunięte w późniejszym wydaniu. Daje to klientom czas na modyfikację kodu. To wydaje się być podejście React w tym przypadku.

(Moja interpretacja tej zasady oparta jest na The Open-Closed Principle Roberta C. Martina)

JacquesB
źródło
37
„Zasada zasadniczo mówi, że nie możesz modyfikować zachowania komponentu. Zamiast tego musisz podać nowy wariant komponentu z pożądanym zachowaniem i zachować starą wersję w niezmienionej formie, aby zapewnić zgodność wsteczną”. - Nie zgadzam się z tym. Zasada mówi, że powinieneś projektować komponenty w taki sposób, aby zmiana jego zachowania nie była konieczna, ponieważ możesz go rozszerzyć, aby robił to, co chcesz. Problem polega na tym, że jeszcze nie wymyśliliśmy, jak to zrobić, zwłaszcza w przypadku języków, które są obecnie w powszechnym użyciu. Problem z wyrażaniem jest jedną z części…
Jörg W Mittag
8
… To na przykład. Ani Java, ani C♯ nie mają rozwiązania dla wyrażenia. Haskell i Scala tak, ale ich baza użytkowników jest znacznie mniejsza.
Jörg W Mittag
1
@Giorgio: W Haskell rozwiązaniem są klasy typów. W Scali rozwiązaniem są implikacje i przedmioty. Niestety, obecnie nie mam pod ręką linków. Tak, multimetody (w rzeczywistości nie muszą nawet być „wielopłaszczyznowe”, raczej wymagana jest „otwarta” natura metod Lispa) są również możliwym rozwiązaniem. Należy pamiętać, że istnieje wiele phrasings tego problemu ekspresji, ponieważ zazwyczaj dokumenty są napisane w taki sposób, że autor dodaje ograniczenie problemu ekspresji, co skutkuje tym, że wszystkie obecnie istniejące rozwiązania stają się nieważne, a następnie pokazuje, jak jego własna ...
Jörg W Mittag
1
… Język może nawet rozwiązać tę „trudniejszą” wersję. Na przykład Wadler pierwotnie sformułował problem wyrażenia, aby dotyczył nie tylko rozszerzenia modułowego, ale statycznie bezpiecznego rozszerzenia modułowego. Często stosowane metody Lisp nie są jednak statystycznie bezpieczne, są tylko dynamicznie bezpieczne. Odersky wzmocnił to jeszcze bardziej, mówiąc, że powinno ono być modułowo statycznie bezpieczne, tj. Bezpieczeństwo powinno być statycznie sprawdzalne bez patrzenia na cały program, tylko poprzez spojrzenie na moduł rozszerzeń. W rzeczywistości nie można tego zrobić za pomocą klas typu Haskell, ale można to zrobić za pomocą Scali. A w…
Jörg W Mittag
2
@Giorgio: Dokładnie. Tym, co sprawia, że ​​multimetody Common Lisp rozwiązują EP, w rzeczywistości nie jest wielokrotna wysyłka. Faktem jest, że metody są otwarte. W typowym programie ramowym (lub programowaniu proceduralnym) rozróżnianie typów jest powiązane z funkcjami. W typowym OO metody są powiązane z typami. Typowe metody Lisp są otwarte , można je dodawać do klas po fakcie i w innym module. Ta funkcja sprawia, że ​​można je wykorzystać do rozwiązania EP. Na przykład protokoły Clojure są wysyłane pojedynczo, ale także rozwiązują EP (o ile nie nalegasz na bezpieczeństwo statyczne).
Jörg W Mittag
20

Nazwałbym zasadę otwartą / zamkniętą ideałem. Jak wszystkie ideały, nie bierze się pod uwagę realiów tworzenia oprogramowania. Podobnie jak wszystkie ideały, nie da się go osiągnąć w praktyce - dąży się do tego ideału jak najlepiej.

Druga strona tej historii to Złote Kajdanki. Złote Kajdanki są tym, co dostajesz, gdy zbytnio podporządkowujesz się zasadzie otwarcia / zamknięcia. Złote kajdanki mają miejsce, gdy twój produkt, który nigdy nie łamie się wstecz, nie może rosnąć, ponieważ popełniono zbyt wiele błędów z przeszłości.

Słynny przykład tego można znaleźć w menedżerze pamięci systemu Windows 95. W ramach marketingu systemu Windows 95 stwierdzono, że wszystkie aplikacje systemu Windows 3.1 będą działać w systemie Windows 95. Microsoft faktycznie nabył licencje na tysiące programów do testowania ich w systemie Windows 95. Jednym z problemów było Sim City. W Sim City rzeczywiście wystąpił błąd, który spowodował, że zapisał w nieprzydzielonej pamięci. W systemie Windows 3.1, bez „właściwego” menedżera pamięci, było to niewielkie faux pas. Jednak w Windows 95 menedżer pamięci wychwytuje to i powoduje błąd segmentacji. Rozwiązanie? W systemie Windows 95, jeśli nazwa aplikacji to simcity.exe, system operacyjny faktycznie rozluźni ograniczenia menedżera pamięci, aby zapobiec usterce segmentacji!

Prawdziwym problemem tego ideału są sparowane koncepcje produktów i usług. Nikt tak naprawdę nie robi ani jednego, ani drugiego. Wszystko układa się gdzieś w szarym obszarze między nimi. Jeśli myślisz o podejściu zorientowanym na produkt, otwieranie / zamykanie brzmi jak doskonały ideał. Twoje produkty są niezawodne. Jednak jeśli chodzi o usługi, historia się zmienia. Łatwo jest wykazać, że zgodnie z zasadą otwartej / zamkniętej ilość funkcji, którą musi obsłużyć zespół, musi asymptotycznie zbliżać się do nieskończoności, ponieważ nigdy nie można wyczyścić starej funkcjonalności. Oznacza to, że Twój zespół programistów musi obsługiwać coraz więcej kodu każdego roku. W końcu osiągasz punkt krytyczny.

Większość dzisiejszych programów, szczególnie open source, stosuje wspólną, zrelaksowaną wersję zasady otwartego / zamkniętego. Często zdarza się, że otwarte / zamknięte są niewolniczo wydawane w przypadku mniejszych wydań, ale porzucane w przypadku większych wydań. Na przykład Python 2.7 zawiera wiele „złych wyborów” z Python 2.0 i 2.1 dni, ale Python 3.0 zmieścił je wszystkie. (Również przejście z systemu Windows 95 kodzie w kodzie Windows NT, kiedy wydany Windows 2000 złamał różne rzeczy, ale to nie znaczy, że nie mają do czynienia z menedżera pamięci sprawdzając nazwę aplikacji, aby zdecydować zachowanie!)

Cort Ammon
źródło
To całkiem niezła historia o SimCity. Czy masz źródło?
BJ Myers
5
@BJMyers To stara historia, Joel Spoleky wspomina o niej pod koniec tego artykułu . Pierwotnie czytałem go jako część książki o tworzeniu gier wideo wiele lat temu.
Cort Ammon
1
@BJMyers: Jestem pewien, że mieli podobne „hacki” kompatybilności z dziesiątkami popularnych aplikacji.
Doc Brown
3
@ BJMyers jest wiele takich rzeczy, jeśli chcesz przeczytać, przejdź do bloga The Old New Thing autorstwa Raymonda Chena , przejrzyj tag History lub wyszukaj „zgodność”. Przypomina się wiele opowieści, w tym coś wyraźnie zbliżonego do wspomnianej wyżej sprawy SimCity - Addentum: Chen nie lubi obwiniać nazwisk.
Theraot
2
Bardzo niewiele się zepsuło, nawet przy przejściu 95-> NT. Oryginalny SimCity dla Windows nadal działa świetnie na Windows 10 (32-bit). Nawet gry DOS nadal działają doskonale, pod warunkiem, że wyłączysz dźwięk lub użyjesz czegoś takiego jak VDMSound, aby podsystem konsoli mógł poprawnie obsługiwać dźwięk. Microsoft bardzo poważnie podchodzi do kompatybilności wstecznej i nie przyjmuje też skrótów „włóżmy to do maszyny wirtualnej”. Czasami wymaga to obejścia, ale wciąż robi wrażenie, szczególnie w kategoriach względnych.
Luaan
11

Odpowiedź doktora Browna jest najbliższa dokładności, inne odpowiedzi ilustrują nieporozumienia dotyczące otwartej zasady zamkniętej.

Wyraźnie artykułować nieporozumienie, nie wydaje się być przekonanie, że OCP oznacza, że nie należy wprowadzać zmian niezgodnych wstecz (lub nawet jakieś zmiany lub coś wzdłuż tych linii.) OCP jest o projektowaniu komponentów, dzięki czemu nie trzeba się wprowadzaj w nich zmiany, aby rozszerzyć ich funkcjonalność, niezależnie od tego, czy zmiany te są kompatybilne wstecz, czy nie. Istnieje wiele innych powodów oprócz dodawania funkcji, które możesz wprowadzać zmiany w komponencie, czy są one wstecznie kompatybilne (np. Refaktoryzacja lub optymalizacja) lub wstecznie niezgodne (np. Przestarzałe i usuwane funkcje). To, że możesz wprowadzić te zmiany, nie oznacza, że ​​twój komponent naruszył OCP (i zdecydowanie nie oznacza, że ty naruszają OCP).

Naprawdę, w ogóle nie chodzi o kod źródłowy. Bardziej abstrakcyjne i stosowne stwierdzenie OCP jest następujące: „element powinien umożliwiać rozszerzenie bez potrzeby naruszania jego granic abstrakcji”. Chciałbym pójść dalej i powiedzieć, że bardziej nowoczesna wersja brzmi: „składnik powinien egzekwować swoje granice abstrakcji, ale zezwalać na rozszerzenie”. Nawet w artykule OCP autorstwa Boba Martina, który „opisuje” „zamknięty na modyfikację” jako „kod źródłowy jest nienaruszalny”, później zaczyna mówić o enkapsulacji, która nie ma nic wspólnego z modyfikacją kodu źródłowego i wszystko, co dotyczy abstrakcji Granic.

Tak więc błędnym założeniem w tym pytaniu jest to, że OCP jest (w zamierzeniu) wytyczną dotyczącą ewolucji bazy kodu. OCP jest zwykle sloganizowane jako „element powinien być otwarty na rozszerzenia i zamknięty dla modyfikacji przez konsumentów”. Zasadniczo, jeśli konsument komponentu chce dodać funkcjonalność do komponentu, powinien mieć możliwość rozszerzenia starego komponentu na nowy z dodatkową funkcjonalnością, ale nie powinien mieć możliwości zmiany starego komponentu.

OCP nie mówi nic o twórcy komponentu zmieniającego lub usuwającego funkcjonalność. OCP nie zaleca utrzymywania zgodności błędów na zawsze. Jako twórca nie naruszasz OCP poprzez zmianę lub nawet usunięcie komponentu. Ty, a raczej komponenty, które napisałeś, naruszają OCP, jeśli jedynym sposobem, w jaki konsumenci mogą dodać funkcjonalność do twoich komponentów, jest ich mutacja, np. Łatanie małplub mając dostęp do kodu źródłowego i ponownej kompilacji. W wielu przypadkach żadna z tych opcji nie jest dostępna dla konsumenta, co oznacza, że ​​jeśli Twój komponent nie jest „otwarty na rozszerzenie”, nie ma szczęścia. Po prostu nie mogą użyć twojego komponentu do swoich potrzeb. OCP twierdzi, że nie stawia konsumentów twojej biblioteki w tej pozycji, przynajmniej w odniesieniu do jakiejś możliwej do zidentyfikowania klasy „rozszerzeń”. Nawet jeśli można dokonać modyfikacji kodu źródłowego lub nawet pierwotnej kopii kodu źródłowego, najlepiej „udawać”, że nie można go zmodyfikować, ponieważ może to mieć wiele potencjalnych negatywnych konsekwencji.

Więc, aby odpowiedzieć na twoje pytania: Nie, to nie są naruszenia OCP. Żadna zmiana dokonana przez autora nie może stanowić naruszenia OCP, ponieważ OCP nie jest właściwością zmian. Zmiany mogą jednak powodować naruszenia OCP i mogą być motywowane awariami OCP we wcześniejszych wersjach bazy kodu. OCP jest własnością określonego fragmentu kodu, a nie historii ewolucji bazy kodu.

Dla kontrastu, zgodność wsteczna jest właściwością zmiany kodu. Nie ma sensu mówić, że jakiś fragment kodu jest lub nie jest kompatybilny wstecz. Sensowne jest tylko mówienie o kompatybilności wstecznej jakiegoś kodu w stosunku do starszego kodu. Dlatego nigdy nie ma sensu mówić o tym, że pierwsze cięcie jakiegoś kodu jest kompatybilne wstecz, czy nie. Pierwsze cięcie kodu może spełniać lub nie spełniać OCP, i ogólnie możemy ustalić, czy jakiś kod spełnia OCP bez odwoływania się do jakichkolwiek historycznych wersji kodu.

Jeśli chodzi o twoje ostatnie pytanie, jest to prawdopodobnie nietypowe dla StackExchange, ponieważ jest oparte głównie na opiniach, ale w skrócie jest mile widziane w technologii, a szczególnie w JavaScript, gdzie w ciągu ostatnich kilku lat opisywane zjawisko nazywało się zmęczeniem JavaScript . (Zapraszam do google znaleźć wiele innych artykułów, niektóre satyryczne, rozmowy na ten temat z różnych perspektyw.)

Derek Elkins
źródło
3
„Ty, jako twórca, nie naruszasz OCP poprzez zmianę lub nawet usunięcie komponentu”. - czy możesz podać referencje? Żadna z definicji zasady, którą widziałem, nie stwierdza, że ​​„twórca” (cokolwiek to znaczy) jest wyłączony z tej zasady. Usunięcie opublikowanego komponentu jest przełomową zmianą.
JacquesB
1
@JacquesB Ludzie, a nawet zmiany kodu nie naruszają OCP, tak jak komponenty (tj. Rzeczywiste fragmenty kodu). (I, aby być całkowicie jasnym, oznacza to, że komponent nie spełnia wymagań samego OCP, nie dlatego, że narusza OCP jakiegoś innego komponentu.) Całą moją odpowiedzią jest to, że OCP nie mówi o zmianach kodu , łamanie lub w inny sposób. Składnikiem jest albo otwarty do rozszerzenia i modyfikacji zamknięte, lub nie, podobnie jak metoda może być privatelub nie. Jeśli autor opracuje privatemetodę publicpóźniej, nie oznacza to, że naruszył kontrolę dostępu, (1/2)
Derek Elkins
2
... ani nie oznacza to, że metoda nie była tak naprawdę privatewcześniej. „Usunięcie opublikowanego komponentu jest przełomową zmianą”, to nie sekwencja. Albo składniki nowej wersji spełniają OCP, albo nie, nie potrzebujesz historii bazy kodu, aby to ustalić. Według twojej logiki nigdy nie mogłem napisać kodu, który spełnia OCP. Łączymy kompatybilność wsteczną, właściwość zmian kodu, z OCP, właściwość kodu. Twój komentarz ma tyle samo sensu, co stwierdzenie, że Quicksort nie jest kompatybilny wstecz. (2/2)
Derek Elkins
3
@JacquesB Najpierw zauważ, że chodzi o moduł zgodny z OCP. OCP jest radą, jak napisać moduł, aby biorąc pod uwagę ograniczenie, że kodu źródłowego nie można zmienić, moduł można jednak rozszerzyć. Wcześniej w artykule mówi o projektowaniu modułów, które nigdy się nie zmieniają, a nie o wdrażaniu procesu zarządzania zmianami, który nigdy nie pozwala na zmianę modułów. Odnosząc się do edycji odpowiedzi, nie „łamiesz OCP” poprzez modyfikację kodu modułu. Zamiast tego, jeśli „rozszerzenie” modułu wymaga modyfikacji kodu źródłowego, (1/3)
Derek Elkins
2
„OCP jest własnością określonego fragmentu kodu, a nie historii ewolucji bazy kodu”. - doskonały!
Doc Brown