Zwykle instynkt polega na usunięciu wszelkich duplikacji kodu widocznych w kodzie. Znalazłem się jednak w sytuacji, w której duplikacja jest iluzoryczna .
Bardziej szczegółowo opisując sytuację: tworzę aplikację internetową, a większość widoków jest w zasadzie taka sama - wyświetla listę elementów, które użytkownik może przewijać i wybierać, drugą listę zawierającą wybrane elementy oraz „Zapisz ”, aby zapisać nową listę.
Wydawało mi się, że problem jest łatwy. Jednak każdy widok ma swoje dziwactwa - czasem trzeba coś przeliczyć, czasem trzeba zapisać dodatkowe dane itp. Rozwiązałem je, wstawiając haki wywołania zwrotnego do głównego kodu logicznego.
Jest tak wiele drobnych różnic między widokami, że staje się ono coraz mniej łatwe w utrzymaniu, ponieważ muszę zapewnić wywołania zwrotne dla praktycznie całej funkcjonalności, a główna logika zaczyna wyglądać jak ogromna sekwencja wywołań wywołań zwrotnych. W końcu nie oszczędzam czasu ani kodu, ponieważ każdy widok ma swój kod, który jest wykonywany - wszystko w wywołaniach zwrotnych.
Problemy są następujące:
- różnice są tak małe, że kod wygląda prawie dokładnie tak samo we wszystkich widokach,
- jest tak wiele różnic, że kiedy patrzysz na szczegóły, kodowanie nie jest trochę podobne
Jak mam poradzić sobie z tą sytuacją?
Czy posiadanie podstawowej logiki złożonej wyłącznie z wywołań zwrotnych jest dobrym rozwiązaniem?
A może powinienem raczej powielić kod i porzucić złożoność kodu opartego na wywołaniu zwrotnym?
źródło
Odpowiedzi:
Ostatecznie musisz dokonać oceny, czy połączyć podobny kod, aby wyeliminować powielanie.
Wydaje się, że istnieje niefortunna tendencja do przyjmowania zasad takich jak „Nie powtarzaj się” jako zasad, które muszą być przestrzegane przez cały czas. W rzeczywistości nie są to uniwersalne zasady, ale wytyczne, które powinny pomóc ci pomyśleć i opracować dobry projekt.
Jak wszystko w życiu, należy wziąć pod uwagę korzyści w stosunku do kosztów. Ile zduplikowanych kodów zostanie usuniętych? Ile razy kod się powtarza? Ile wysiłku będzie wymagało napisanie bardziej ogólnego projektu? Ile prawdopodobnie opracujesz kod w przyszłości? I tak dalej.
Nie znając swojego konkretnego kodu, jest to niejasne. Być może istnieje bardziej elegancki sposób na usunięcie duplikacji (taki jak sugerowany przez LindaJeanne). A może po prostu nie ma wystarczającej liczby prawdziwych powtórzeń, aby uzasadnić abstrakcję.
Niewystarczająca dbałość o design jest pułapką, ale strzeż się też nadmiernego projektowania.
źródło
Pamiętaj, że DRY to wiedza . Nie ma znaczenia, czy dwa fragmenty kodu wyglądają podobnie, identycznie czy zupełnie inaczej, ważne jest, czy w obu z nich można znaleźć tę samą wiedzę na temat systemu.
Wiedza może być faktem („maksymalne dozwolone odchylenie od zamierzonej wartości wynosi 0,1%”) lub może być pewnym aspektem Twojego procesu („kolejka nigdy nie zawiera więcej niż trzech elementów”). Zasadniczo jest to każda pojedyncza informacja zakodowana w kodzie źródłowym.
Więc kiedy decydujesz, czy coś jest duplikacją, którą należy usunąć, zapytaj, czy to duplikacja wiedzy. Jeśli nie, prawdopodobnie jest to przypadkowe powielenie, a wyodrębnienie go do jakiegoś wspólnego miejsca spowoduje problemy, gdy później będziesz chciał utworzyć podobny komponent, w którym ta pozornie powielona część jest inna.
źródło
Czy rozważałeś zastosowanie wzorca strategii ? Miałbyś jedną klasę View, która zawiera wspólny kod i procedury wywoływane przez kilka widoków. Klasa Children of View zawierałaby kod specyficzny dla tych instancji. Wszystkie wykorzystałyby wspólny interfejs utworzony dla Widoku, a zatem różnice byłyby enkapsulowane i spójne.
źródło
Jaki jest potencjał zmian? Na przykład nasza aplikacja ma 8 różnych obszarów biznesowych z potencjałem 4 lub więcej typów użytkowników dla każdego obszaru. Widoki są dostosowywane na podstawie typu użytkownika i obszaru.
Początkowo dokonano tego przy użyciu tego samego widoku z kilkoma sprawdzeniami tu i tam, aby ustalić, czy różne rzeczy powinny się pokazać. Z czasem niektóre obszary działalności postanowiły zrobić drastycznie różne rzeczy. Ostatecznie przeprowadziliśmy migrację do jednego widoku (widoki częściowe, w przypadku ASP.NET MVC) na część funkcjonalności na obszar biznesowy. Nie wszystkie obszary biznesowe mają tę samą funkcjonalność, ale jeśli ktoś chce mieć funkcjonalność inną, ten obszar ma swój własny widok. Jest to znacznie mniej kłopotliwe dla zrozumienia kodu, a także dla testowalności. Na przykład dokonanie zmiany dla jednego obszaru nie spowoduje niepożądanej zmiany dla innego obszaru.
Jak wspomniano @ dan1111, może sprowadzać się do wezwania sądu. Z czasem możesz sprawdzić, czy to działa, czy nie.
źródło
Jednym z problemów może być to, że udostępniasz interfejs (interfejs teoretyczny, a nie funkcję językową) tylko do jednego poziomu funkcjonalności:
Zamiast wielu poziomów w zależności od wymaganej kontroli:
O ile rozumiem, udostępniasz tylko interfejs wysokiego poziomu (A), ukrywając szczegóły implementacji (inne rzeczy tam).
Ukrywanie szczegółów implementacji ma zalety, a właśnie znalazłeś wadę - kontrola jest ograniczona, chyba że wyraźnie dodasz funkcje dla każdej pojedynczej rzeczy, które byłyby możliwe przy bezpośrednim użyciu interfejsów niskiego poziomu.
Masz dwie opcje. Albo używasz tylko interfejsu niskiego poziomu, użyj interfejsu niskiego poziomu, ponieważ interfejs wysokiego poziomu był zbyt pracochłonny do utrzymania, lub ujawniaj interfejsy wysokiego i niskiego poziomu. Jedyną sensowną opcją jest oferowanie interfejsów wysokiego i niskiego poziomu (i wszystkiego pomiędzy nimi), zakładając, że chcesz uniknąć zbędnego kodu.
Następnie, pisząc coś innego, patrzysz na wszystkie dostępne dotąd funkcje (niezliczone możliwości, od ciebie zależy, które z nich mogą zostać ponownie wykorzystane) i poskładasz je razem.
Użyj jednego obiektu, w którym potrzebujesz niewielkiej kontroli.
Użyj funkcji najniższego poziomu, gdy musi wydarzyć się dziwność.
Jest również niezbyt czarno-biały. Może twoja duża klasa wysokiego poziomu MOŻE rozsądnie obejmować wszystkie możliwe przypadki użycia. Być może przypadki użycia są tak różne, że nie wystarczy nic oprócz prymitywnej funkcjonalności najniższego poziomu. Do ciebie, aby znaleźć równowagę.
źródło
Istnieją już inne przydatne odpowiedzi. Dodam moje.
Powielanie jest złe, ponieważ
Chodzi o to, że nie eliminujesz powielania ze względu na to lub dlatego, że ktoś powiedział, że to ważne. Robisz to, ponieważ chcesz zmniejszyć liczbę błędów / problemów. W twoim przypadku wydaje się, że jeśli zmienisz coś w widoku, prawdopodobnie nie będziesz musiał zmieniać dokładnie tej samej linii we wszystkich innych widokach. Masz więc oczywiste powielanie , a nie faktyczne powielanie.
Inną ważną kwestią jest, aby nigdy nie przepisywać od nowa czegoś, co działa teraz tylko na zasadzie zasady, jak powiedział Joel (mogłeś już o nim słyszeć ...). Tak więc, jeśli twoje poglądy działają, postępuj krok po kroku i nie padaj ofiarą „pojedynczego najgorszego błędu strategicznego, jaki może popełnić każda firma produkująca oprogramowanie”.
źródło