Najpierw przeczytałem fragment artykułu Edsgera W. Dijkstry z 1974 r. „O roli myśli naukowej”:
Pozwól, że wyjaśnię ci, co według mojego gustu jest charakterystyczne dla każdego inteligentnego myślenia. Chodzi o to, że chce się dogłębnie przestudiować aspekt przedmiotu w oderwaniu dla własnej spójności, cały czas wiedząc, że zajmuje się tylko jednym aspektem. Wiemy, że program musi być poprawny i możemy go studiować tylko z tego punktu widzenia; wiemy również, że powinien on być skuteczny i że tak powiem, możemy zbadać jego skuteczność w innym dniu. W innym nastroju możemy zadać sobie pytanie, czy, a jeśli tak, to dlaczego program jest pożądany. Ale nic nie zyskuje - wręcz przeciwnie! - przez jednoczesne zajęcie się tymi różnymi aspektami. Jest to coś, co czasami nazywam „oddzieleniem obaw”, co nawet jeśli nie jest całkowicie możliwe, jest jeszcze jedyną dostępną techniką skutecznego uporządkowania własnych myśli, o której wiem. Mam na myśli to, że „skupiam uwagę na pewnym aspekcie”: nie oznacza to ignorowania innych aspektów, po prostu oddaje sprawiedliwość temu, że z punktu widzenia tego aspektu drugi jest nieistotny. Jest jednocześnie jedno- i wielościeżkowy.
Widzę współczesne oddzielenie problemów mówiących o modularyzacji twojego kodu. Jednak, czytając powyższy cytat, rozumiem, że skupiasz swój umysł na jednym konkretnym zadaniu na raz, nie koncentrując się jednak na innych aspektach. Nie oznacza to dla mnie koniecznie, że kod musi być podzielony na części modułowe.
To znaczy, powiedzmy, że przed tobą jest kod, który w jednym pliku zawiera pojęcia widoku, repozytorium, kontrolera, obsługi zdarzeń, fabryki itp. W jednym pliku.
Na krótki przykład oto kod, który ma dostęp do danych, i przeglądaj (dane wyjściowe):
$sql = "SELECT * FROM product WHERE id = " . db_input($id);
$row = db_fetch_array(db_query($sql));
<option value="<?=$row['id']?>"<?= $row['ver'] == $row['ver'] ? ' selected="selected"' : '' ?>>Version <?=$row['ver']?></option>
Korzystając z nowoczesnego OO, mogę umieścić dostęp do danych we własnym pliku przy użyciu wzorca repozytorium, kod View może przejść do własnego szablonu pliku i mogę połączyć je ze sobą, aby komunikować się za pośrednictwem kontrolera (lub działania lub procedury obsługi żądań), i mogę dodaj fabrykę, aby tworzyć i łączyć różne zależności. I mogę mieć plik konfiguracyjny, który definiuje te fabryki. Z pewnością jest to krok od pojedynczego pliku-wszystkiego.
Moje pytanie dotyczące rozdzielenia problemów jest takie: czytając cytat Dijkstry, wpadłem na pomysł, że być może niekoniecznie miał na myśli, że rozdzielenie obaw to „modułowe rozdzielenie kodu (na pliki lub ich własne funkcje / metody / itp.)”, i że tym bardziej chciał skupić umysł na aspekcie programu, nie obciążając się skupieniem na innych ważnych, ale jeszcze nieistniejących aspektach, niezależnie od tego, czy są one fizycznie rozdzielone w kodzie, czy nie.
Dlaczego zatem obciążamy się fizycznymi modułowymi wzorcami separacji kodów i wzorami projektowymi? Czy nie wystarczy skupić się na jakimś aspekcie, niezależnie od struktury kodu?
Nie mówię o napisaniu najstraszniejszego kodu spaghetti, a następnie rozważeniu tylko jego aspektu, który prawdopodobnie byłby ciężarem. Ale w końcu, do czego zmierzam, to po co przeprowadzać fizyczną separację kodu, po co dzielić kod na osobne pliki lub fragmenty (metody), skoro nie jest to konieczne do mentalnego skupienia się na aspekcie?
Czy rozdzielenie obaw powinno być ćwiczeniem umysłowym, a nie fizycznym?
Innymi słowy, czy powinno istnieć rozłączenie między mentalnym (skupienie się) a fizycznym (kod na papierze) aspektami programowania?
IF
,WHILE
,FOR
a nieGOTO
. Modułowy = moduły z dobrze zdefiniowanym publicznym interfejsem API ściśle oddzielonym od ukrytej wewnętrznej implementacji i reprezentacji. (Np. Modula, Mesa, Modula-2, Modula-3, później dialekty Pascala (UNIT
).)Odpowiedzi:
Dijkstra zawiera wyraźne oświadczenie dotyczące sposobu myślenia. Modularyzacja programu (i procesu) - i jest pożądana - jest być może wynikiem takiego myślenia, ale kluczową kwestią, którą porusza, jest ocena problemu. Program jest zazwyczaj rozwiązaniem problemu, a zalecając „rozdzielenie obaw”, udziela mądrych rad. Najlepszym tego przykładem jest być może „optymalizacja”. Żart brzmiał: „Planując optymalizację programu, twoją pierwszą strategią powinno być: nie.” Innymi słowy, chcesz skupić się na poprawieniu programu. Sprawienie, by było szybkie i fantazyjne, jest problemem, który należy oddzielić - ale także nie do końca usunąć.
źródło
Rozdzielanie obaw jest abstrakcyjnym sposobem myślenia, polegającym na oddzielnym rozpatrywaniu rzeczy, które nie muszą być ze sobą powiązane.
Modularyzacja (rozdzielenie niepowiązanej grupy funkcji na moduły), enkapsulacja (ukrywanie wewnętrznych szczegółów modułów) i abstrakcja (oddzielenie generała od specyfiki i idei od jego implementacji) to wszystkie sposoby na wdrożenie tego sposobu myślenia w dziedzinie projektowania oprogramowania.
źródło
Sugerowałbym, że chociaż artykuł jest historycznie interesujący, to, co Dijkstra rozumiał przez termin „rozdzielenie obaw” ponad 40 lat temu, nie jest dziś szczególnie istotne. Obecnie jest szeroko stosowany w odniesieniu do modulacji.
Istnieje wiele dowodów na to, że modulacja jest niezwykle korzystna i że korzyści te znacznie przewyższają „obciążenia”, które na nas nakładają. Cokolwiek wtedy miał na myśli Dijkstra, nie zmienia faktu, że małe fragmenty kodu, z których każdy koncentruje się na jednej rzeczy, prowadzi do kodu, który jest łatwiejszy do pisania, czytania, rozumienia, utrzymywania i testowania.
źródło
Mogę podać osobisty przykład rozdzielenia obaw, który moim zdaniem jest porównywalny z koncepcjami Dijkstry. Kiedy analizuję określony temat w oprogramowaniu, tworzę trzy poglądy.
Na koniec uzyskuje się trójwymiarowy obraz przedmiotu, który można następnie sformułować jako kod w dowolnych grupach dogodnych dla samego kodu i jego utrzymania. Trzy aspekty to nie tylko ćwiczenie mentalne. Tworzę pisemne opisy wszystkich aspektów. Dlaczego? Ponieważ jeśli przedmiot jest wystarczająco duży, nie mogę zatrzymać nawet jednego kompletnego aspektu w pamięci krótkotrwałej. Jeśli przedmiot jest niewielki, prawie każde podejście zadziała, ponieważ możesz trzymać to wszystko w głowie.
Motywacją do rozdzielenia problemów jest dostosowanie się do ograniczeń pamięci krótkoterminowej u ludzi. Po prostu nie możemy nosić wszystkiego w naszych głowach naraz, chociaż programiści komputerowi są zazwyczaj bardziej zdolni niż większość innych ludzi pod względem liczby pojęć, którymi mogą manipulować w swojej pamięci krótkoterminowej. Aby być skutecznym, należy rozdzielać obawy systematyczniewyklucz jeden lub więcej aspektów problemu, aby skupić się na innym konkretnym aspekcie. Oczywiście wykluczenie jednego aspektu nie powoduje, że znika ono z rozważań. Musi istnieć sposób na połączenie wszystkich aspektów problemu, aby osiągnąć rozwiązanie. Doświadczenie pokazuje, że często końcowy wynik rozdzielania i rekombinacji daje bardziej zrozumiałe rozwiązanie niż pojedynczy gigantyczny skok, w którym wiele aspektów może zostać pomieszanych. Jest to szczególnie ważne, gdy rozmiar problemu jest duży lub skomplikowany.
źródło
Rozdzielenie problemów jest logiczną koncepcją, która zostanie rozpowszechniona w modelu organizacji kodu bez względu na to, jak ją zaimplementujesz. Prawdą jest, że plik kodu jest tylko szczegółem technicznym, jednym ze sposobów na zarządzanie oprogramowaniem. Pojedynczy plik z dobrym edytorem, który pozwala zwinąć rozszerzenie regionów, może również działać (na chwilę). Lub relacyjna baza danych, która przechowuje klasy i metody w sposób nadrzędny-podrzędny w osobnych tabelach, może działać jako nośnik pamięci. Ale pliki tekstowe są trudne do pokonania w świecie, w którym musi znajdować się kod źródłowy
Najważniejsze jest to, że my, ludzie, nie jesteśmy zbyt dobrzy w myśleniu lub radzeniu sobie z różnymi rzeczami na raz. Potrzebujemy więc modelu, który pozwala myśleć i pracować nad jedną rzeczą naraz, bez niebezpieczeństwa zrujnowania innej części, której w tym czasie nie rozważamy. Budujemy więc, układając po jednej cegle na raz, upewniając się, że cegły, które układamy wcześniej, nie będą kolidować z cegłami ustawionymi później. A jeśli chcemy później zmienić cegłę, rzeczy nie mogą się zawalić. To model, który działa na nasze jednośladowe umysły.
Nie tak rosną grzyby i glony ... Jak to jest z upokarzającego faktu?
źródło
Uważam jednak, że odpowiedziano na konkretną odpowiedź na cytat Dijkstry, ponieważ stwierdzasz: „Korzystając z nowoczesnego OO, mogę umieścić dostęp do danych we własnym pliku” i pytasz: „Czy rozdzielenie obaw powinno być ćwiczeniem umysłowym, a nie fizycznym?” Pozwólcie, że zwrócę uwagę na to, dokąd kierują nas nowi zleceniodawcy.
Należy postępować zgodnie z zasadami SOLID przy programowaniu za pomocą OO. Oto fajny link do nich, ale TLDR na temat „rozdzielenia problemów” znajduje się głównie w S w SOLID: Zasada pojedynczej odpowiedzialności lub SRP.
Zdecydowanie jest to ćwiczenie fizyczne, a nie mentalne. Na przykład MVC (lub jego rodzeństwo MVVM i MVP) nakazuje fizyczny podział koncertów Model, View i Controller / Presenter / ViewModel na osobne pliki. Widziałem niektóre implementacje MVVM, w których są one implementowane w oddzielnych zespołach, aby jeszcze bardziej ograniczyć skłonność do „pomieszania koncepcji”.
Ale. Wykracza poza zwykłe „to jest widok i to jest model”, jeśli podążysz za tym wujkiem Bobem .
Należy również wziąć pod uwagę źródło wymagań dla każdego konkretnego elementu OO. Jeśli łączysz, powiedzmy, czego chce Klient z tym, czego chce Personel Operacyjny, naruszasz również SRP. Lub, mówiąc inaczej, jak wujek Bob: Klasa powinna mieć jeden i jedyny powód do zmiany.
Zdecydowanie zalecamy, abyś przestudiował to dalej za pomocą dostarczonych linków lub przeszukał „solidne zasady”.
źródło