Utrzymanie kodu: utrzymywanie złego wzorca przy rozszerzaniu nowego kodu za spójność, czy nie?

45

Muszę rozszerzyć istniejący moduł projektu. Nie podoba mi się sposób, w jaki to zostało zrobione (dużo anty-wzorca, takiego jak kopiowanie / wklejanie kodu). Nie chcę wykonać pełnego refaktora z wielu powodów.

Czy powinienem:

  • tworzyć nowe metody przy użyciu istniejącej konwencji, nawet jeśli uważam, że to źle, aby uniknąć zamieszania dla następnego opiekuna i być spójnym z bazą kodu?

lub

  • spróbuj użyć tego, co czuję się lepiej, nawet jeśli wprowadza on inny wzorzec w kodzie?

Precison edytowane po pierwszych odpowiedziach:

Istniejący kod nie jest bałaganem. Łatwo jest śledzić i rozumieć. ALE wprowadza wiele kodu typu „płyta podstawowa”, którego można uniknąć dzięki dobrej konstrukcji (kod wynikowy może być trudniejszy do przestrzegania). W moim obecnym przypadku jest to dobry stary moduł DAO JDBC (szablon sprężyny wbudowany), ale napotkałem już ten dylemat i szukam innych opinii deweloperów.

Nie chcę refaktoryzować, bo nie mam czasu. I nawet z czasem trudno będzie uzasadnić, że cały doskonale działający moduł wymaga refaktoryzacji. Koszt refaktoryzacji będzie wyższy niż korzyści. Pamiętaj: kod nie jest bałaganiarski ani zbyt skomplikowany. Nie mogę tam wyodrębnić kilku metod i wprowadzić tutaj abstrakcyjnej klasy. To bardziej wada w projekcie (wydaje mi się, że efektem ekstremalnego „Keep It Stupid Simple”)

Tak więc pytanie może być zadane w ten sposób:
Czy jako deweloper wolisz zachować łatwy, głupi, nudny kod LUB mieć pomocników, którzy zrobią ten głupi, nudny kod?

Minusem ostatniej możliwości jest to, że będziesz musiał nauczyć się kilku rzeczy i być może będziesz musiał też utrzymywać łatwy głupi, nudny kod, aż do pełnego refaktoryzacji)

Guillaume
źródło
Bardzo interesujące pytanie!
Philippe,
1
Utrzymanie łatwego, nudnego, głupiego kodu - z definicji jest łatwe. Wolałbym mieć łatwe życie i każdego dnia wychodzić wcześnie.
szybko_nie
Tak, ale jestem zbyt leniwy, by robić nudny głupi kod :) Wolę ciężko pracować przez 2 lub 3 dni, aby zbudować coś, co zrobi dla mnie tę część!
Guillaume,
1
Kiedy głupie lub nudne łatwo się zagubiły?
Erik Reppen
Cześć Erik, czasami kod, który mógł zostać podzielony na czynniki, jest łatwiejszy do odczytania: to samo tuzin razy, a kod jest prosty. Możesz przeczytać go z rzędu, nie myśląc o tym, i możesz debugować w sposób liniowy. Nie ma ukrytej złożoności.
Guillaume

Odpowiedzi:

42

Refaktoryzację najlepiej przeprowadzać małymi krokami, a najlepiej tylko wtedy, gdy masz testy jednostkowe obejmujące kod. (Jeśli więc nie masz jeszcze testów, postaraj się je najpierw napisać, a do tego czasu trzymaj się najprostszych, najbardziej niezawodnych, najlepiej zautomatyzowanych refaktoryzacji. Ogromną pomocą w tym jest Efektywna praca ze Starszym Kodem autorstwa Michaela Feathersa.)

Ogólnie rzecz biorąc, staraj się nieco poprawić kod za każdym razem, gdy go dotkniesz. Postępuj zgodnie z regułą skautową ( wymyśloną przez Roberta C. Martina ), pozostawiając kod czystszy, niż go znalazłeś. Podczas dodawania nowego kodu staraj się go oddzielać od istniejącego złego kodu. Np. Nie zakopuj go w środku długiej metody, zamiast tego dodaj wywołanie do osobnej metody i umieść tam swój nowy kod. W ten sposób wyhodujesz stopniowo większe wyspy czystego (er) kodu w ramach istniejącej bazy kodów.

Aktualizacja

Koszt refaktoryzacji będzie wyższy niż korzyści. [...] Czy jako deweloper wolisz utrzymywać łatwy, głupi, nudny kod LUB mieć pomocników, którzy zrobią ten głupi nudny kod w twoim miejscu?

Podkreśliłem, co moim zdaniem jest tutaj kluczowe. Zawsze warto oszacować koszty i zalety refaktoryzacji, zanim w nią wejdziemy. Podobnie jak w twoim przypadku, większość z nas ma ograniczone zasoby do refaktoryzacji, dlatego musimy mądrze z nich korzystać. Poświęć tak mało czasu na refaktoryzację, gdzie przynosi najwięcej korzyści przy najmniejszym wysiłku.

Jako twórczy umysł oczywiście wolałbym tworzyć idealny, piękny i elegancki kod i przepisywać wszystko, co nie przypomina moich ideałów :-) W rzeczywistości jednak płacę mi za tworzenie oprogramowania, które rozwiązuje prawdziwe problemy dla jego użytkowników, więc powinni zastanowić się, czy w dłuższej perspektywie będą wytwarzać jak najwięcej swoich pieniędzy.

Korzyści z refaktoryzacji pojawiają się tylko wtedy, gdy istnieją wystarczające oszczędności czasu i wysiłków na rzecz zrozumienia, utrzymania, naprawy i rozszerzenia kodu w dłuższej perspektywie . Więc jeśli fragment kodu - jakkolwiek jest brzydki - jest rzadko lub nigdy nie jest dotykany, nie ma w nim żadnych znanych błędów i nie znam żadnych nadchodzących funkcji w dającej się przewidzieć przyszłości, które wymagałyby ode mnie dotknięcia, wolę odejść w pokoju.

Péter Török
źródło
7
Tak łatwo wpaść w pułapkę „kod już jest do bani, równie dobrze może dalej działać ...” Dobrzy programiści nie. Niezła odpowiedź.
sevenseacat
Chociaż jest to prawdopodobnie najbezpieczniejsze podejście (kod gwarantuje działanie dzięki testom), nadal powoduje problem wymieniony w pytaniu. W kodzie wprowadzono inny wzorzec. Ogólnie uważam, że powinieneś spróbować poświęcić swój czas na refaktoryzację wszystkiego na raz (podczas wykonywania TDD, najlepiej z pośrednimi krokami), aby nie mieć tego pośredniego niespójnego stanu. Po zakończeniu przekaż kod do kontroli źródła.
Steven Jeuris
2
@ Steven, możesz refaktoryzować wszystko na raz, jeśli możesz sobie na to pozwolić . Jednak w większości rzeczywistych projektów nie można po prostu zatrzymać wszystkiego i spędzić kilka dni lub tygodni z rzędu tylko na refaktoryzacji. Nawet jeśli masz szczęście, że masz menedżera, który go wspiera, projekt nadal musi się rozwijać.
Péter Török
1
@Steven, to zależy - zobacz moją aktualizację powyżej.
Péter Török
1
@ Péter Török: Ładna aktualizacja! Doskonały opis rzeczywistych czynników, które należy wziąć pod uwagę.
Steven Jeuris
4

Ponieważ nie masz czasu na refaktoryzację, a kod można utrzymać, zachowaj spójność. Następnym razem pamiętaj o uwzględnieniu refaktoryzacji w oszacowaniu.

kirk.burleson
źródło
3

Zachowanie spójności pomaga tylko następnemu deweloperowi, gdy otaczający kod jest w dobrej formie. Pomyśl, ile czasu zajęło ci zrozumienie dostępnego kodu i znalezienie odpowiednich „punktów rozszerzeń”, aby dodać zmiany. Jeśli podążasz za obecnym trendem, następny facet musi zrozumieć istniejący kod, a także nowy kod, gdy musi wprowadzić zmiany.

Jeśli przeredagujesz kod na znaczące funkcje, następny facet będzie miał łatwiejszy do zrozumienia, co się dzieje i będzie musiał poświęcić mniej wysiłku, aby dodać swoje zmiany. Pomyśl o tym w ten sposób. Załóżmy, że następnym facetem jesteś ty. Co wolisz zobaczyć, kiedy ponownie odwiedzasz ten blok kodu, ten sam bałagan, na który patrzysz teraz, lub coś bardziej logicznie skonstruowanego?

Michael Brown
źródło
3

Spójność ma wysoki priorytet. Oczywiście wszyscy przy zdrowych zmysłach woleliby wszędzie eleganckie SUCHE rozwiązanie zamiast wklejonej płyty grzewczej, ale czy naprawdę wolelibyście dwa różne podejścia w tej samej bazie kodu niż konsekwentnie stosowane? Co jeśli ktoś wymyśli jeszcze inteligentniejsze rozwiązanie, a także zastosuje je niekonsekwentnie? Masz trzy różne sposoby robienia tego samego.

Widziałem dużo niechlujnego kodu wynikającego z tego, że programiści znaleźli „lepszy sposób” na zrobienie czegoś, ale nie stosowali go konsekwentnie na bazie kodu. Jeśli stopniowe stosowanie nowego wzorca jest częścią planowanej i skoordynowanej strategii, może on z czasem działać, ale każdy wdrożony niekonsekwentnie grozi pogorszeniem całego systemu.

Może warto rozważyć refaktoryzację w mniejszych krokach, tak aby każdy krok można było zastosować do całej bazy kodu za jednym razem. Na przykład. wyodrębnianie mniejszej części płyty kotła do funkcji pomocniczej w każdej iteracji. Z czasem kończysz z całą płytą kotłową w klasie pomocnika. Może wyglądać naprawdę brzydko, ponieważ nie został zaprojektowany, ale wyhodowany, ale możesz to teraz naprawić, ponieważ masz cały kod w jednym miejscu.

JacquesB
źródło
+1 „Zatem masz trzy różne sposoby robienia tego samego”. Widziałem to w każdym projekcie korporacyjnym, nad którym pracowałem. Powiedziałbym, że nawet nie próbuj refaktoryzować, dopóki nie przeszukasz kodu, aby upewnić się, że nie ma już innego fragmentu kodu, który próbuje zająć się brzydkim kodem, który postanowiłeś refaktoryzować. Czasami najlepiej jest trzymać się konwencji typu bojler, przynajmniej do czasu dokładnego przeczytania kodu.
TK-421,
1

Wszelkie refaktoryzacje, które eliminują duplikaty kodu, są dobrym refaktoryzacją i nie powinny być odraczane, chyba że zbliża się termin. Raz poświęcony na refaktoryzację łatwo zrekompensuje czas wygrany w przyszłych wdrożeniach. Dzięki refaktoryzacji wewnętrzne funkcjonowanie nie jest już widoczne, więc powinno być łatwiejsze do zrozumienia, a nie trudniejsze do naśladowania.

Moim zdaniem powszechne błędne przekonanie, że kod refaktoryzowany jest trudniejszy do naśladowania. Zwykle jest to argument ludzi, którzy znają tylko to, co jest refaktoryzowane, a nie refaktoryzowany wynik. Dla nowo przybyłych, ponownie ustawiony wynik będzie wyraźniejszy.

Wszelkie błędy / funkcje mogą zostać naprawione / zaimplementowane w centralnym miejscu w późniejszym czasie i są automatycznie dostępne wszędzie w Twojej aplikacji. Jest to ogromny zysk, który jest zwykle bardzo niedoceniany. Ogólnie rzecz biorąc, całkowita refaktoryzacja komponentu nie trwa tak długo. (dni zamiast miesięcy) W porównaniu z czasem straconym z powodu błędów, koniecznością zrozumienia kodu, który mógł zostać zrefaktoryzowany, koszt refaktoryzacji staje się minimalny.

Aktualizacja odnosząca się do odpowiedzi Pétera Töröka: Czy nie przez odroczenie refaktoryzacji „ponieważ to wymaga czasu”, czas refaktoryzacji w późniejszym czasie wzrasta? Refaktoryzacja nie powinna zająć dużo czasu, jeśli jest wykonywana częściej.

Jak wytłumaczyć swojemu szefowi, że spędzisz kilka dni na pisaniu kodu, który niczego nie dodaje do produktu, jest trudny i jest zupełnie innym pytaniem. :)

Steven Jeuris
źródło
1
„Jak wytłumaczyć swojemu szefowi, że spędzisz kilka dni na pisaniu kodu, który niczego nie dodaje do produktu, jest trudny i jest zupełnie innym pytaniem”. Niezła próba ;-) Niestety, w prawdziwym życiu również musimy to rozwiązać. Dlatego bardziej praktyczne jest przechodzenie małymi krokami. Pół godziny refaktoryzacji można wykonać w ramach dwugodzinnego zadania, bez potrzeby, aby kierownik nawet o tym wiedział. OTOH dwa pełne dni spędzone na refaktoryzacji rzadko pozostają niezauważone.
Péter Török
@ Péter Török: Trochę zaktualizowałem post. Oczywiście nadal masz sytuacje w świecie rzeczywistym, w których nie możesz poświęcić czasu na refaktoryzację. Ale głęboko wierzę, że w teorii zawsze zyskuje się czas. (chyba że wiesz, że kod, nad którym pracujesz, nie będzie już obsługiwany w najbliższej przyszłości)
Steven Jeuris
jak mówią, w teorii nie ma dużej różnicy między praktyką a teorią. Jednak w praktyce ... :-) W rzeczywistości nie zawsze możesz odzyskać koszty poniesione na refaktoryzację. Rozszerzyłem swoją odpowiedź na ten temat.
Péter Török
1
Refaktoryzacja, która usuwa zduplikowany kod, nie zawsze jest dobra; możliwe, że dwie metody mogą być identyczne według dzisiejszych reguł biznesowych, ale nie jutro. Na przykład AcmeLockerBankjeden może mieć getRow(int itemIndex)metodę, która zwraca, index % 5i AcmeButtonPanelmoże mieć identyczną metodę, ponieważ zarówno szafka, jak i tablice przycisków numerują rzeczy w ten sam sposób; jeśli żaden z dzisiejszych banków szafek nie ma przedmiotów o indeksie powyżej 1000, ale niektóre panele przycisków mają, a przyszłe szafki stosują inne odstępy między wierszami dla indeksów w zakresie 1000-1999 ...
supercat
1
... dodanie dodatkowych zachowań do banków szafek będzie łatwe, jeśli banki szafek i banków przycisków będą miały różne getRowmetody, ale może być trudniejsze, jeśli funkcje zostaną połączone w jedną wspólną metodę.
supercat
0

Czy nie możesz utworzyć nowego interfejsu / klas, które działają jako fasada w stosunku do starego kodu, jednocześnie wprowadzając nowy kod we własnym stylu, który można łatwo rozszerzyć?

Darren Young
źródło
0

Zrób to dobrze, idąc naprzód. Używaj funkcji zamiast wycinania i wklejania. Nie wymaga to refaktoryzacji, ale daje początek podstawy do refaktoryzacji w przyszłości.

Andy Lester
źródło
0

Czy jako programista wolisz utrzymywać łatwy, głupi, nudny kod LUB mieć pomocników, którzy zrobią ten głupi, nudny kod u Ciebie?

Nie rozumiem poprawionego pytania. Myślę, że większość ludzi, podobnie jak ja, wolałaby nie utrzymywać „głupiego nudnego kodu”. Przepraszam, nie wiem, co masz na myśli przez pomocnika.

Plakat odpowiedział na własne pytanie, nie dokonując w tej chwili dużych zmian. Dobry wybór. Mam problemy z arogancją programisty, że wiedzą, co jest najlepsze dla firmy. Wielkie refaktoryzacja podstępnej ... bo wiesz lepiej niż twój szef? Każdy zdolny menedżer może zważyć korzyści.

Jeśli refaktoryzacja nie jest opcją, pytanie staje się bardziej dyskusją na temat właściwego czasu, miejsca itp. Na zrobienie tego. Spójność jest bardzo ważna. Jednak długowieczny kod często korzysta z „odnowienia”. Inni dyskutowali o tym ...


źródło