W inspirującej myśli Richa Hickeya na konferencji goto „ Wartość wartości ” po 29 minutach mówi o narzutach związanych z językiem takim jak Java i mówi: „Wszystkie te interfejsy zabijają ponowne użycie”. Co on ma na myśli? Czy to prawda?
W poszukiwaniu odpowiedzi natknąłem się na:
Zasada najmniejszej wiedzy AKA Prawo Demeter, które zachęca do szczelnych interfejsów API. Wikipedia wymienia również niektóre wady.
Kryzys odzieżowy Kevlina Henneya, który dowodzi, że używanie, a nie ponowne wykorzystywanie jest właściwym celem.
Wystąpienie Jacka Diedericha „ Stop Writing Classes ” przemawia ogólnie przeciwko nadmiernej inżynierii.
Oczywiście wszystko, co napisano wystarczająco źle, będzie bezużyteczne. Ale w jaki sposób interfejs dobrze napisanego API zapobiegnie użyciu tego kodu? W całej historii są przykłady czegoś, co zostało wykonane w jednym celu i jest wykorzystywane bardziej do czegoś innego . Ale w świecie oprogramowania, jeśli używasz czegoś do celu, do którego nie było przeznaczone, zwykle się psuje.
Szukam jednego dobrego przykładu dobrego interfejsu uniemożliwiającego prawidłowe, ale niezamierzone użycie jakiegoś kodu. Czy to istnieje? Nie mogę tego sobie wyobrazić.
źródło
Odpowiedzi:
Nie oglądałem pełnej prezentacji Richa Hickeya, ale jeśli dobrze go rozumiem i sądząc po tym, co mówi o 29-minutowej ocenie, wydaje się, że kłóci się o typy zabijające ponowne użycie. Termin „interfejs” używa luźno jako synonim „nazwanego typu”, co ma sens.
Jeśli masz dwie jednostki
{ "name":"John" }
typuPerson
i{ "name": "Rover" }
typuDog
w Javie, prawdopodobnie nie będą mogły współpracować, chyba że będą miały wspólny interfejs lub przodka (np.Mammal
Co oznacza pisanie większej ilości kodu). Tak więc interfejsy / typy „zabijają twoje ponowne użycie”: chociażPerson
iDog
wyglądają tak samo, jednego nie można używać zamiennie z drugim, chyba że napiszesz dodatkowy kod, który to obsługuje. Uwaga Hickey żartuje także z projektów w Javie wymagających dużej liczby klas („Kto tutaj napisał aplikację Java z wykorzystaniem zaledwie 20 klas?”), Co wydaje się jedną z konsekwencji tego.Jednak w językach „zorientowanych na wartość” nie będziesz przypisywać typów do tych struktur; są to tylko wartości, które dzielą tę samą strukturę (w moim przykładzie oba mają
name
pole z wartością String) i dlatego mogą łatwo współpracować, np. można je dodać do tej samej kolekcji, przekazać do tych samych metod itp.Podsumowując, wydaje się, że wszystko to dotyczy równości strukturalnej vs. jawnej równości typu / interfejsu . Chyba że coś przeoczyłem z fragmentów filmu, których jeszcze nie obejrzałem :)
źródło
ERROR: Object doesn't have a property called "name"
jest często wynikiemvalue-oriented
języków, a drugim problemem jest to, że nie chcesz już wywoływać tej właściwościname
. Refaktoryzacja powodzenia, ponieważ prawdopodobnie istnieją setki obiektów z właściwością,name
ale nie wszystkie sąPerson
lubDog
.interface
s, ale z bałaganem, który jest typowym projektem Java.Prawdopodobnie odnosi się do podstawowego faktu, że interfejsu nie można utworzyć. Nie możesz
reuse
interfejsu. Możesz zaimplementować tylko kod, który go obsługuje, a kiedy piszesz kod interfejsu, nie ma możliwości ponownego użycia.Java ma historię dostarczania struktur wielu interfejsów API, które przyjmują interfejs jako argument, ale zespół, który opracował interfejs API, nigdy nie wdrożył szerokiej gamy klas do ponownego użycia z tymi interfejsami.
To coś w rodzaju frameworku GUI z
IWindow
interfejsem do okna dialogowego, a następnie można dodawaćIButton
interfejsy do kontrolek. Tyle że nigdy nie dali ci dobrejButton
klasy, która implementujeIButton
. Pozostajesz więc tworzyć własne.Wyodrębnione frameworki, które mają szeroki zakres klas bazowych zapewniających podstawowe funkcje, są bardziej wielokrotnego użytku i działają najlepiej, gdy te abstrakcyjne klasy są dostępne dla osób korzystających z frameworka.
Programiści Java zaczęli to robić, gdy ich warstwy API były widoczne
interfaces
. Można zaimplementować te interfejsy, ale nigdy nie można ponownie użyć klas od programisty, który zaimplementował te interfejsy. To trochę jak peleryna i sztylet w stylu API.źródło
Myślę, że slajd 13 w jego prezentacji ( The Value of Values ) pomaga to zrozumieć:
Rozumiem, że Hickey sugeruje, że jeśli muszę, powiedzmy, podwoić wartość, którą mi przesłałeś, po prostu piszę kod wyglądający jak
Widzisz, powyższy kod jest taki sam, bez względu na to, jaką wartość przesłałeś - coś w rodzaju idealnego ponownego wykorzystania .
Jak by to wyglądało w języku posiadającym obiekty i interfejsy?
zaczekaj! co jeśli
YourValue
się nie wdrażaDoublable
? nie to, że nie można go podwoić, może być idealnie, ale ... co jeśli nie ma po prostu żadnej metodyDouble
? (a jeśli istnieje metoda o nazwie powiedzTwiceAsMuch
?)Och, mamy problem.
YourValue.Double
nie będzie działać, nie będzie można go ponownie wykorzystać . Według mojej lektury powyższego slajdu chodzi o to, co Hickey miał na myśli, mówiąc: „Wszystkie te interfejsy zabijają twoje ponowne użycie!”Widzicie, interfejsy zakładają, że obiekty są przekazywane „wraz z ich metodami” wraz z działającym na nich kodem. Aby używać obiektów, należy zrozumieć, jak wywołać ten kod i jaką metodę wywołać.
Gdy brakuje oczekiwanej metody , pojawia się problem, chociaż semantycznie pożądana operacja ma idealny sens dla obiektu. Jak stwierdzono w prezentacji, wartości nie potrzebują metod („Mogę przesyłać ci wartości bez kodu i wszystko w porządku”), co pozwala pisać kod, który zajmuje się nimi w sposób ogólny.
Uwaga dodatkowa: pojęcie przekazywania wartości bez kodu w jakiś sposób przypomina mi wzór Flyweight w OOP.
Zastosowania Flyweight zwykle widziałem to samo podejście do usuwania kodu (metod, interfejsów) z obiektów i przekazywania rzeczy dookoła, a także wartości bez kodu , spodziewając się, że kod otrzymujący ma środki niezbędne do działania na nich.
Czuje się to tak, jak na slajdzie: „wartości nie wymagają metod. Mogę przesyłać ci wartości bez kodu i wszystko jest w porządku”.
źródło
MyValue = Double(YourValue)
nie ma sensu, jeśli YourValue jest ciągiem, adresem, użytkownikiem, funkcją lub bazą danych. W przeciwnym razie argument braku metody jest silny. OTOH, metody akcesora pozwalają egzekwować różne ograniczenia, aby Twoje Wartości były ważne, i aby tylko nowe rozsądne operacje były używane do tworzenia nowych Wartości. Jeśli później zdecydujesz się oddzielić adres od użytkownika i firmy, metody dostępu oznaczają, że nie złamiesz wszystkich klientów kodu. Mogą więc pomóc w ponownym użyciu w perspektywie długoterminowej, nawet jeśli czasami utrudniają to w perspektywie krótkoterminowej.W (tj. Moim) idealnym świecie klasy i interfejsy zawsze opisywałyby zachowanie, ale faktem jest, że zbyt często tak naprawdę kończą opisywanie danych. Dopiero wczoraj obejrzałem wideo kogoś, kto buduje tak zwaną
BankAccount
klasę, która była niczym innym jak tylko uwielbionąint
(w rzeczywistości była znacznie mniej przydatna niżint
, a zatem „zabijała” ponowne użycie, które miałbym, gdyby był po prostu pozostawiony jakoint
), wszystko w imię „dobrego” projektu. Ilość kodu, potu i łez zmarnowanych na ciągłe wymyślanie skomplikowanych reprezentacji danych jest oszałamiająca; jeśli nie używasz danych w znaczący sposób, pozwól, aby tak było.Na tym etapie Rich Hickey jest zadowolony z wyrzucenia dziecka z kąpielą i powiedzenia, że wszyscy powinniśmy żyć w krainie wartości (sąsiedzi królestwa rzeczowników). Z drugiej strony myślę, że OOP może i promuje ponowne wykorzystanie (i, co ważne, wykrywalność, której brakuje w programowaniu funkcjonalnym), gdy jest rozsądnie stosowane. Jeśli szukasz zasady OOP, która najlepiej wychwytuje to napięcie, myślę, że może to być http://c2.com/cgi/wiki?TellDontAsk (która oczywiście jest bliską kuzynką Demeter)
źródło