Pracuję na dość dużej podstawie kodu. Setki klas, mnóstwo różnych plików, wiele funkcji, potrzeba więcej niż 15 minut, aby pobrać nową kopię itp.
Dużym problemem związanym z tak dużą bazą kodu jest to, że ma całkiem sporo metod narzędziowych i takich, które robią to samo, lub kod, który nie używa tych metod narzędziowych, kiedy może. A także metody użytkowe nie są tylko jedną klasą (ponieważ byłby to ogromny pomieszany bałagan).
Jestem raczej nowy w bazie kodu, ale lider zespołu, który pracował nad nim od lat, wydaje się mieć ten sam problem. Prowadzi to do dużej ilości kodu i powielania pracy, i jako takie, gdy coś się psuje, zwykle jest dzielone na 4 kopie zasadniczo tego samego kodu
Jak możemy ograniczyć ten wzór? Podobnie jak w przypadku większości dużych projektów, nie cały kod jest udokumentowany (choć niektóre są) i nie cały kod jest ... cóż, czysty. Ale w gruncie rzeczy byłoby naprawdę miło, gdybyśmy mogli popracować nad poprawą jakości pod tym względem, aby w przyszłości mieliśmy mniej powielania kodu, a takie funkcje, jak funkcje użytkowe były łatwiejsze do wykrycia.
Ponadto funkcje narzędziowe są zwykle albo w statycznej klasie pomocniczej, w innej niestatycznej klasie pomocniczej, która działa na jednym obiekcie, lub jest statyczną metodą w klasie, z którą głównie „pomaga”.
Miałem jeden eksperyment z dodawaniem funkcji narzędziowych jako metod rozszerzenia (nie potrzebowałem żadnych elementów wewnętrznych klasy, a na pewno było to wymagane tylko w bardzo specyficznych scenariuszach). Skutkowało to zapobieganiem zaśmiecaniu klasy podstawowej i tym podobnych, ale tak naprawdę nie jest już możliwe do odkrycia, chyba że już o tym wiesz
Odpowiedzi:
Prosta odpowiedź jest taka, że tak naprawdę nie można zapobiec duplikacji kodu. Możesz jednak „naprawić” trudny, ciągły, powtarzalny proces przyrostowy, który sprowadza się do dwóch etapów:
Krok 1. Rozpocznij pisanie testów na starszym kodzie (najlepiej przy użyciu środowiska testowego)
Krok 2. Przepisz / przeredaguj kod, który jest zduplikowany, korzystając z tego, czego nauczyłeś się z testów
Możesz użyć narzędzi do analizy statycznej, aby wykryć zduplikowany kod, a dla języka C # istnieje mnóstwo narzędzi, które mogą to zrobić za Ciebie:
Takie narzędzia pomogą ci znaleźć punkty w kodzie, które robią podobne rzeczy. Kontynuuj pisanie testów, aby ustalić, czy naprawdę tak robią; użyj tych samych testów, aby uprościć korzystanie ze zduplikowanego kodu. To „refaktoryzacja” można wykonać na wiele sposobów i możesz użyć tej listy do ustalenia poprawnej:
Co więcej, jest też cała książka na ten temat autorstwa Michaela C. Feathersa, działającego skutecznie z Legacy Code . Omówiono różne strategie, które można zastosować, aby zmienić kod na lepszy. Ma „starszy algorytm zmiany kodu”, który nie jest daleko od dwustopniowego procesu powyżej:
Książka jest dobra do przeczytania, jeśli masz do czynienia z rozwojem brązowych pól, tj. Starszego kodu, który należy zmienić.
W tym przypadku
W przypadku OP mogę sobie wyobrazić, że nieuleczalny kod jest powodowany przez garnek miodu dla „metod użytkowych i sztuczek”, które przybierają różne formy:
Zauważ, że nie ma w tym nic złego, ale z drugiej strony są one zazwyczaj trudne do utrzymania i zmiany. Metody rozszerzeń w .NET są metodami statycznymi, ale są również stosunkowo łatwe do przetestowania.
Zanim przejdziesz do refaktoryzacji, porozmawiaj o tym ze swoim zespołem. Muszą one znajdować się na tej samej stronie co Ty, zanim zaczniesz cokolwiek robić. Wynika to z faktu, że jeśli coś refaktoryzujesz, wówczas szanse są duże, będziesz powodować konflikty scalania. Zanim coś przerobisz, sprawdź to i powiedz swojemu zespołowi, aby przez pewien czas pracował nad tymi punktami kodu, dopóki nie skończysz.
Ponieważ OP jest nowością w kodzie, jest kilka rzeczy do zrobienia, zanim powinieneś cokolwiek zrobić:
Powodzenia!
źródło
Możemy także spróbować spojrzeć na problem z innej strony. Zamiast myśleć, że problemem jest duplikacja kodu, możemy rozważyć, czy przyczyną problemu jest brak zasad ponownego użycia kodu.
Niedawno przeczytałem książkę Inżynieria oprogramowania z komponentami wielokrotnego użytku i rzeczywiście zawiera ona zestaw bardzo interesujących pomysłów, w jaki sposób promować wielokrotne użycie kodu na poziomie organizacji.
Autor tej książki, Johannes Sametinger, opisuje zestaw barier w ponownym użyciu kodu, niektóre koncepcyjne, a niektóre techniczne. Na przykład:
Według autora różne poziomy ponownego wykorzystania zdarzają się w zależności od dojrzałości organizacji.
Być może więc, oprócz wszystkich sugestii podanych w innych odpowiedziach, możesz pracować nad projektem programu wielokrotnego użytku, obejmować zarządzanie, utworzyć grupę komponentów odpowiedzialną za identyfikację komponentów wielokrotnego użytku poprzez analizę domeny i zdefiniować repozytorium komponentów wielokrotnego użytku, które inni programiści mogą łatwo odpytuj i szukaj gotowych rozwiązań ich problemów.
źródło
Istnieją 2 możliwe rozwiązania:
Zapobieganie - staraj się mieć jak najlepszą dokumentację. Spraw, aby każda funkcja była odpowiednio udokumentowana i łatwa do przeszukania całej dokumentacji. Pisząc kod, wyraźnie zaznacz, gdzie powinien się znaleźć kod, aby było oczywiste, gdzie szukać. Ograniczenie ilości kodu „użyteczności” jest jednym z kluczowych punktów tego. Za każdym razem, gdy słyszę „zróbmy klasę użytkową”, moje włosy podnoszą się, a krew zamarza, ponieważ to oczywiście problem. Zawsze miej szybki i łatwy sposób, aby poprosić ludzi o zapoznanie się z bazą kodu, gdy tylko jakaś funkcja już istnieje.
Rozwiązanie - Jeśli zapobieganie się nie powiedzie, powinieneś być w stanie szybko i skutecznie rozwiązać problematyczną część kodu. Twój proces programowania powinien umożliwić szybkie naprawienie duplikatu kodu. Testowanie jednostkowe jest do tego idealne, ponieważ można efektywnie modyfikować kod bez obawy jego uszkodzenia. Jeśli więc znajdziesz 2 podobne fragmenty kodu, wyodrębnienie ich do funkcji lub klasy powinno być łatwe przy odrobinie refaktoryzacji.
Osobiście uważam, że zapobieganie nie jest możliwe. Im więcej spróbujesz, tym trudniej będzie znaleźć już istniejące funkcje.
źródło
Nie sądzę, że tego rodzaju problemy mają ogólne rozwiązanie. Duplikat kodu nie zostanie utworzony, jeśli programiści będą mieli wystarczającą ochotę wyszukać istniejący kod. Również programiści mogą naprawić problemy na miejscu, jeśli chcą.
Jeśli językiem jest C / C ++, scalanie będzie łatwiejsze dzięki elastyczności łączenia (można wywoływać dowolne
extern
funkcje bez uprzedniej informacji). W przypadku Java lub .NET może być konieczne opracowanie klas pomocniczych i / lub składników narzędziowych.Zwykle zaczynam od kopiowania istniejącego kodu tylko wtedy, gdy główne błędy wynikają z powielonych części.
źródło
Jest to typowy problem większego projektu, którym zajmowało się wielu programistów, którzy wnieśli swój wkład pod niekiedy dużą presją ze strony otoczenia. Bardzo kuszące jest tworzenie kopii klasy i dostosowanie jej do tej konkretnej klasy. Jednak gdy problem został znaleziony w klasie inicjującej, należy go również rozwiązać w przyzwoitkach, o których często się zapomina.
Istnieje na to rozwiązanie, które nazywa się Generics, które zostało wprowadzone w Javie 6. Jest to odpowiednik C ++ o nazwie Szablon. Kod, którego dokładna klasa nie jest jeszcze znana w klasie ogólnej. Sprawdź Java Generics, a znajdziesz mnóstwo ton dokumentacji.
Dobrym podejściem jest przepisywanie kodu, który wydaje się być kopiowany / wklejany w wielu miejscach, przepisując pierwszy, który musisz np. Naprawić z powodu określonego błędu. Przepisz go, aby używać Generics, a także pisać bardzo rygorystyczny kod testowy.
Upewnij się, że wywoływana jest każda metoda klasy Generic. Możesz także wprowadzić narzędzia do pokrycia kodu: kod ogólny powinien obejmować cały kod, ponieważ będzie używany w kilku miejscach.
Napisz także kod testowy, tj. Używając JUnit lub podobnego dla pierwszej wyznaczonej klasy, która będzie używana w połączeniu z częścią Ogólną.
Zacznij korzystać z kodu Generic dla drugiej (najczęściej) skopiowanej wersji, gdy cały poprzedni kod działa i jest w pełni przetestowany. Zobaczysz, że istnieją pewne wiersze kodu, które są specyficzne dla tej wyznaczonej klasy. Możesz wywołać te wiersze zakodowane w abstrakcyjnej metodzie chronionej, która musi zostać zaimplementowana przez klasę pochodną, która używa ogólnej klasy bazowej.
Tak, to żmudna praca, ale w miarę postępów będzie coraz lepiej wyrywać podobne klasy i zastępować ją czymś, co jest bardzo czyste, dobrze napisane i o wiele łatwiejsze w utrzymaniu.
Miałem podobną sytuację, gdy w klasie generycznej ostatecznie zastąpiłem coś w rodzaju 6 lub 7 innych prawie identycznych klas, które były prawie prawie identyczne, ale zostały skopiowane i wklejone przez różnych programistów w pewnym okresie czasu.
I tak, jestem bardzo za automatycznym testowaniem kodu. Na początku będzie to kosztować więcej, ale zdecydowanie zaoszczędzi Ci mnóstwo czasu. I spróbuj osiągnąć zasięg kodu wynoszący co najmniej 80% i 100% dla kodu ogólnego.
Mam nadzieję, że to pomoże i powodzenia.
źródło
Mam zamiar powtórzyć najmniej popularną opinię tutaj i po stronie
Gangnus
i zasugerować, że duplikacja kodu nie zawsze jest szkodliwa i czasami może być mniejszym złem.Jeśli powiesz mi, że możesz użyć:
A) Stabilna (niezmienna) i niewielka biblioteka obrazów, dobrze przetestowana , która powiela kilkadziesiąt wierszy trywialnego kodu matematycznego dla matematyki wektorowej, takich jak produkty kropkowe, wyrywki i klamry, ale jest całkowicie oddzielona od wszystkiego innego i tworzy ułamek sekunda.
B) Niestabilna (szybko zmieniająca się) biblioteka obrazów, która zależy od epickiej biblioteki matematycznej, aby uniknąć wspomnianych kilku tuzinów linii kodu, przy czym biblioteka matematyczna jest niestabilna i stale otrzymuje nowe aktualizacje i zmiany, a zatem biblioteka obrazów musi również zostać przebudowany, jeśli nie całkowicie również zmieniony. Zbudowanie całości zajmuje 15 minut.
... więc dla większości ludzi powinno być oczywiste, że A, a właściwie właśnie ze względu na niewielkie powielanie kodu, jest preferowane. Najważniejszym akcentem, który muszę zrobić, jest dobrze przetestowana część. Oczywiście nie ma nic gorszego niż zduplikowany kod, który nawet nie działa, w tym momencie powielają błędy.
Ale trzeba też pomyśleć o sprzężeniu i stabilności, a także o niewielkim stopniu powielania tu i tam może służyć jako mechanizm odsprzęgający, który również zwiększa stabilność (niezmienną naturę) pakietu.
Tak więc moją propozycją będzie skupienie się bardziej na testowaniu i próbie znalezienia czegoś naprawdę stabilnego (jak w przypadku niezmienności, znajdowania kilku powodów do zmiany w przyszłości) i niezawodnego, którego zależności od źródeł zewnętrznych, jeśli takie istnieją, są bardzo stabilny, ponad próbę usunięcia wszelkich form duplikacji w bazie kodu. W środowisku dużego zespołu ten ostatni jest niepraktycznym celem, nie wspominając o tym, że może zwiększyć sprzężenie i ilość niestabilnego kodu, który masz w bazie kodu.
źródło
Nie zapominaj, że powielanie kodu nie zawsze jest szkodliwe. Wyobraź sobie: teraz masz jakieś zadanie do rozwiązania w absolutnie różnych modułach swojego projektu. Właśnie teraz jest to to samo zadanie.
Mogą to być trzy przyczyny:
Niektóre motywy wokół tego zadania są takie same dla obu modułów. W takim przypadku duplikacja kodu jest zła i powinna zostać zlikwidowana. Byłoby sprytnie stworzyć klasę lub moduł do obsługi tego tematu i używać jego metod w obu modułach.
Zadanie jest teoretyczne z punktu widzenia twojego projektu. Na przykład pochodzi z fizyki lub matematyki itp. Zadanie istnieje niezależnie od twojego projektu. W takim przypadku duplikacja kodu jest zła i również powinna zostać zlikwidowana. Stworzyłbym specjalną klasę dla takich funkcji. I użyj takiej funkcji w dowolnym module, w którym jej potrzebujesz.
Ale w innych przypadkach zbieżność zadań jest zbiegiem okoliczności i niczym więcej. Niebezpiecznie byłoby wierzyć, że zadania te pozostaną takie same podczas zmian w projekcie z powodu refaktoryzacji, a nawet debugowania. W takim przypadku lepiej byłoby utworzyć dwie takie same funkcje / fragmenty kodu w różnych miejscach. A przyszłe zmiany w jednym z nich nie dotkną drugiego.
I ten trzeci przypadek zdarza się bardzo często. Jeśli powielasz „nieświadomie”, głównie z tego właśnie powodu - to nie jest prawdziwe powielanie!
Staraj się więc utrzymywać go w czystości, gdy jest to naprawdę konieczne, i nie bój się powielania, jeśli nie jest to konieczne.
źródło
code duplication is not always harmful
jest jedna kiepska rada.