Jeśli spróbuję stworzyć nową metodę obsługi B w inny sposób, zostanie ona wywołana w celu powielenia kodu.
Nie wszystkie duplikacje kodu są sobie równe.
Załóżmy, że masz metodę, która pobiera dwa parametry i dodaje je razem total()
. Załóżmy, że masz inną add()
. Ich implementacje wyglądają zupełnie identycznie. Czy powinny zostać połączone w jedną metodę? NIE!!!
Zasada Don't-Repeat-Yourself lub DRY nie polega na powtarzaniu kodu. Chodzi o rozpowszechnianie decyzji, pomysłów, więc jeśli kiedykolwiek zmienisz swój pomysł, musisz przepisać wszędzie, gdzie rozpowszechniasz ten pomysł. Blegh. To straszne. Nie rób tego Zamiast tego użyj DRY, aby pomóc Ci podejmować decyzje w jednym miejscu .
Zasada DRY (Don't Repeat Yourself) mówi:
Każda wiedza musi mieć jedną, jednoznaczną, autorytatywną reprezentację w systemie.
wiki.c2.com - Nie powtarzaj się
Ale DRY może zostać zepsute w nawyk skanowania kodu w poszukiwaniu podobnej implementacji, która wydaje się być kopią i wklejaniem gdzie indziej. To martwa mózg forma SUSZENIA. Do diabła, możesz to zrobić za pomocą narzędzia do analizy statycznej. Nie pomaga, ponieważ ignoruje sens DRY, który polega na zachowaniu elastyczności kodu.
Jeśli zmienią się moje wymagania sumowania, być może będę musiał zmienić total
implementację. To nie znaczy, że muszę zmienić add
implementację. Jeśli jakiś Goober zgniótł je razem w jedną metodę, teraz czeka mnie niepotrzebny ból.
Ile bólu Z pewnością mógłbym po prostu skopiować kod i stworzyć nową metodę, gdy jej potrzebuję. Więc nic wielkiego, prawda? Malarky! Jeśli nic więcej nie kosztuje mnie dobre imię! Dobre imiona są trudne do zdobycia i nie reagują dobrze, gdy majstrujesz przy ich znaczeniu. Dobre nazwy, które wyraźnie wyjaśniają cel, są ważniejsze niż ryzyko, że skopiujesz błąd, który, szczerze mówiąc, łatwiej jest naprawić, gdy twoja metoda ma prawidłową nazwę.
Tak więc radzę przestać pozwalać reakcjom szarpiącym kolana na podobny kod wiązać bazę kodu w węzłach. Nie twierdzę, że możesz zignorować fakt, że istnieją metody, a zamiast tego skopiuj i wklej willy nilly. Nie, każda metoda powinna mieć cholernie dobrą nazwę, która popiera jeden pomysł, o którym chodzi. Jeśli jego implementacja będzie pasować do implementacji innego dobrego pomysłu, to teraz, komu, do diabła, to obchodzi?
Z drugiej strony, jeśli masz sum()
metodę, która ma identyczną lub nawet inną implementację niż total()
, ale za każdym razem, gdy zmieniają się twoje łączne wymagania, musisz zmienić, sum()
to jest duża szansa, że są to ten sam pomysł pod dwiema różnymi nazwami. Kod byłby nie tylko bardziej elastyczny, gdyby zostały scalone, ale korzystanie z niego byłoby mniej skomplikowane.
Jeśli chodzi o parametry boolowskie, to nieprzyjemny zapach kodu. Kontrola przepływu nie tylko stanowi problem, ale gorzej pokazuje, że w złym momencie włączyłeś abstrakcję. Abstrakcje mają uprościć, a nie skomplikować. Przekazywanie booli do metody kontrolującej jej zachowanie jest jak tworzenie tajnego języka, który decyduje, którą metodę naprawdę wywołujesz. Ow! Nie rób mi tego. Nadaj każdej metodzie własną nazwę, chyba że masz jakiś uczciwy sposób na pogarszanie się polimorfizmu .
Teraz wydajesz się wypalony abstrakcją. Szkoda, ponieważ abstrakcja jest cudowną rzeczą, gdy jest dobrze wykonana. Używasz go dużo, nie myśląc o tym. Za każdym razem, gdy prowadzisz samochód bez konieczności rozumienia mechanizmu zębatkowego, za każdym razem, gdy używasz polecenia drukowania, nie myśląc o przerwach w systemie operacyjnym, i za każdym razem, gdy myjesz zęby, nie myśląc o każdym włosiu.
Nie, problemem, z którym się wydajesz, jest zła abstrakcja. Abstrakcja stworzona, by służyć innym celom niż twoje potrzeby. Potrzebujesz prostych interfejsów do złożonych obiektów, które pozwolą ci zaspokoić twoje potrzeby bez konieczności rozumienia tych obiektów.
Pisząc kod klienta korzystający z innego obiektu, wiesz, jakie są Twoje potrzeby i czego potrzebujesz od tego obiektu. Tak nie jest. Dlatego kod klienta jest właścicielem interfejsu. Kiedy jesteś klientem, nic nie jest w stanie powiedzieć, jakie są twoje potrzeby oprócz ciebie. Udostępniasz interfejs, który pokazuje, jakie są twoje potrzeby i żądasz, aby wszystko, co zostanie ci przekazane, spełniło te potrzeby.
To jest abstrakcja. Jako klient nie wiem nawet, z kim rozmawiam. Po prostu wiem, czego potrzebuję. Jeśli to oznacza, że musisz coś zawinąć, aby zmienić jego interfejs, zanim w porządku. Nie obchodzi mnie to. Po prostu rób to, co muszę zrobić. Przestań to komplikować.
Jeśli muszę zajrzeć do abstrakcji, aby zrozumieć, jak z niej korzystać, abstrakcja nie powiodła się. Nie powinienem wiedzieć, jak to działa. Po prostu to działa. Nadaj mu dobre imię, a jeśli zajrzę do środka, nie powinienem być zaskoczony tym, co znajdę. Nie każ mi zaglądać do środka, żeby pamiętać, jak go używać.
Kiedy nalegasz, aby abstrakcja działała w ten sposób, liczba poziomów za nią nie ma znaczenia. Tak długo, jak nie patrzysz za abstrakcją. Nalegasz, aby abstrakcja była zgodna z twoimi potrzebami, nie dostosowując się do niej. Aby to zadziałało, musi być łatwe w użyciu, mieć dobre imię i nie przeciekać .
Takie podejście zrodziło Dependency Injection (lub po prostu odniesienie do podania, jeśli jesteś starą szkołą taką jak ja). Działa to dobrze, preferując kompozycję i przekazywanie zamiast dziedziczenia . Takie podejście ma wiele nazw. Moim ulubionym jest powiedz, nie pytaj .
Mógłbym cię utopić w zasadach przez cały dzień. I wygląda na to, że twoi współpracownicy już są. Ale o to chodzi: w przeciwieństwie do innych dziedzin inżynierii, to oprogramowanie ma mniej niż 100 lat. Wszyscy wciąż to rozgryzamy. Więc nie pozwól, aby ktoś z dużą ilością zastraszających, brzmiących książek nauczył cię pisania trudnego do odczytania kodu. Słuchaj ich, ale nalegaj, aby miały sens. Nie bierz niczego na wiarę. Ludzie, którzy w jakiś sposób kodują tylko dlatego, że powiedziano im to w ten sposób, nie wiedząc, dlaczego robią największe bałagany ze wszystkich.