Refaktoryzacja o niskim wpływie i czyszczenie niechlujnego kodu podczas oczekiwania na wymagania

17

Odziedziczyłem istniejącą bazę kodu dla produktu, który jest nagle niechlujny. Podstawowy projekt jest bardzo nieodpowiedni, na co niestety niewiele mogę poradzić bez kompletnego refaktora (WYSOKIE sprzężenie, NISKA spójność, gwałtowne powielanie kodu, brak dokumentacji technicznej projektu, testy integracyjne zamiast testów jednostkowych). Produkt ma historię, wysoką ekspozycję na krytycznych klientów „krów gotówkowych” z minimalną tolerancją na ryzyko, dług techniczny, który sprawi, że Grecy się rumienią, BARDZO duża baza kodów i złożoność, a także zmęczone walką defetystyczne podejście do błędów przez zespół wcześniej mnie.

Stara drużyna wskoczyła na statek do innej dywizji, aby mieć szansę zrujnowania kolejnego projektu. Bardzo rzadko zdarza się awaria projektu dotycząca niekompetencji technicznej w przeciwieństwie do niepowodzenia zarządzania projektem, ale jest to rzeczywiście jeden z tych przypadków.

W tej chwili jestem sam, ale mam dużo czasu, swobodę decyzji i przyszłe kierunki oraz umiejętność zbudowania zespołu od zera, aby mi pomóc.

Moim pytaniem jest zebranie opinii na temat refaktoryzacji o niskim wpływie na taki projekt, kiedy masz trochę wolnego czasu podczas fazy zbierania wymagań funkcjonalnych. Istnieją tysiące ostrzeżeń kompilatora, prawie wszystkie nieużywane importy, nieprzeczytane zmienne lokalne, brak sprawdzania typu i niebezpieczne rzutowania. Formatowanie kodu jest tak nieczytelne i niechlujne, że wygląda na to, że programista cierpiał na chorobę Parkinsona i nie był w stanie kontrolować liczby naciśnięć spacji w danym wierszu. Dalsze zasoby bazy danych i plików są zwykle otwierane i nigdy nie zamykane bezpiecznie. Bezcelowe argumenty metod, zduplikowane metody, które robią to samo itp.

Podczas gdy czekam na wymagania dotyczące następnej funkcji, od czasu do czasu czyszczę rzeczy o niskim wpływie i niskim ryzyku i zastanawiam się, czy marnuję czas, czy robię właściwą rzecz. Co jeśli nowa funkcja oznacza zgrywanie kodu, nad którym spędziłem wcześniej czas? Mam zamiar rozpocząć podejście zwinne i rozumiem, że jest to akceptowalne i normalne, aby stale refaktoryzować podczas rozwoju zwinnego.

Czy potrafisz wymyślić jakieś pozytywne lub negatywne skutki mojego działania, które chciałbyś dodać?

wałek klonowy
źródło
1
Odzyskaj to, co warte jest uratowania, przepisz resztę ...
SF.
„Bardzo rzadko zdarza mi się niepowodzenie projektu związane z niekompetencją techniczną, a nie niepowodzenie zarządzania projektem [...]” Jak to prawda, +1.
Gregory Higley,

Odpowiedzi:

22

Po pierwsze chciałbym zauważyć, że testy jednostkowe nie zastępują testów integracyjnych. Obie muszą istnieć obok siebie. Bądź wdzięczny, że masz testy integracyjne, w przeciwnym razie jedno z twoich małych refaktoryzacji może sprawić, że jedna z krów gotówkowych o niskiej tolerancji wpadnie w balistę.

Zaczynam pracę nad ostrzeżeniami kompilatora oraz nieużywanymi zmiennymi i importami. Najpierw uzyskaj czystą wersję. Następnie zacznij pisać testy jednostkowe, aby udokumentować bieżące zachowanie, a następnie rozpocznij prawdziwe refaktoryzowanie.

Naprawdę nie widzę żadnego negatywnego wpływu. Zyskasz wiele dogłębnego zrozumienia podstawy kodu, co pomoże w większych refaktoryzacjach. Prawie zawsze lepiej jest refaktoryzować niż przepisać, ponieważ podczas refaktoryzacji nadal masz działający produkt, podczas gdy podczas przepisywania nie. I w końcu sprzedaż produktu musi zapłacić twoją pensję.

Gdy wymagania zaczną się pojawiać, wykorzystam to, co nazywam podejściem reflektorowym. Wykonaj zwykłą zwinną czynność (uszereguj pod względem priorytetów, a następnie odetnij małą płytę w celu wykonania iteracji i przepracuj ją) i pozostaw sporo czasu na ulepszenia kodu. Następnie zreformuj, gdzie i tak pracujesz. Z czasem obejmie to szerokie obszary bazy kodu, bez konieczności wchodzenia w obszary, w których trudno byłoby uzasadnić zarządzanie, dlaczego pracujesz nad tą częścią kodu.

wolfgangsz
źródło
Naprawdę podoba mi się ta odpowiedź. Potrzebuję głębszego zrozumienia podstawy kodu, a krowy gotówkowe PŁACĄ moją pensję, a także umożliwią nam pracę nad lepszymi nowymi projektami dla innych klientów, w których mam możliwość zacząć od zera i zrobić to od samego początku.
wałek klonowy
10

Pisanie testów jednostkowych może być bardziej wartościowym zajęciem twojego czasu: da ci pewien wgląd w bieżące funkcjonowanie bazy kodu, a jeśli zdecydujesz się zacząć od tego, co masz, a nie od przepisywania wszystkiego od zera, będziesz miał solidną bazę wprowadzać zmiany bez podejmowania zbyt dużego ryzyka. Szanse są takie, że podczas pisania testów jednostkowych wprowadzisz również zmiany w bazie kodu, aby nadać jej kształt do przetestowania; są dobre, ponieważ testowanie jednostkowe zwykle oznacza również modułowość, kapsułkowanie i w większości niezależne od stanu zewnętrznego. A przede wszystkim dobrze napisane testy jednostkowe są nieocenioną dokumentacją techniczną. Po wdrożeniu testów jednostkowych będziesz w stanie ocenić, co może i czego nie może zrobić obecna baza kodu, zamiast na wszelki wypadek zgadywać lub przepisywać różne rzeczy.

tdammers
źródło
2
Zacznij więc od tych łatwych i podążaj swoją drogą?
tdammers
2
Jest to zawsze problem z mojego doświadczenia - taki kod nigdy nie jest zapisywany w celu umożliwienia testowania, a w końcu będziesz musiał dokonać ogromnych refaktoryzacji, jeśli nie wprost przepisać kod, aby w ogóle pozwolić na testy jednostkowe.
Wayne Molina,
2
Jeśli kod nie został zaprojektowany do testów, jest to tym bardziej powód, aby przeprowadzać testy wokół niego - ale bezpiecznie. Przeczytaj książkę Michaela Feathersa „Skutecznie współpracując ze starszym kodem”; zawiera przepisy, dzięki którym testowalny kod będzie niemożliwy do przetestowania.
Joe White
1
Zgadzam się; stwierdzając z mojego doświadczenia, że ​​nie ma żadnych testów, musiałbyś zainicjować ogromne refaktoryzowanie, aby przygotować go do testów, co prowadzi do dłuższego „zmarnowanego” refaktoryzacji, co utrudnia napisanie testów, które sprawia, że ​​znacznie trudniej jest zreformować cokolwiek.
Wayne Molina,
1
Potrzeba trochę doświadczenia i dobrego osądu. Nie wszystko może (lub powinno) być możliwe do przetestowania w jednostce.
tdammers
1

Mieszanie odpowiedzi - myślałem o połączeniu testów i czyszczenia - może 50/50? Jeśli pracujesz w obszarze z podejściem TDD - skonfiguruj testy, musisz wiedzieć, że testy jednostki i integracji są zgodne z oczekiwaniami, a następnie rozpocznij naprawę. Ruszaj się, gdy pozwala na to czas.

Prawdopodobnie oznacza to, że nie zrobisz tyle postępów, ale oznacza to, że będziesz mieć całkiem stabilną bazę kodu, przynajmniej w niektórych obszarach, i będziesz mieć dobrą bazę początkową.

Moja pierwotna reakcja brzmiała: „czy naprawdę może zaszkodzić oczyszczenie zepsutego kodu?” (aka, błędy kompilatora), ale potem przypomniałem sobie czasy, w których naprawienie problemu faktycznie zepsuło funkcjonalność w niektórych naprawdę dziwnych przypadkach, ponieważ zamiast umierania nici pozostawiało pamięć w złych miejscach - w zasadzie zła przerwa maskowała jeszcze gorszy błąd. Może to być dosłownie Puszka Pandory nieprzyjemnych niespodzianek.

Biorąc pod uwagę, że robisz to, czekając na dodatkowe wymagania, myślę, że wszystko, co możesz zdiagnozować chaos, znacznie zwiększy twoje zdrowie psychiczne na dłuższą metę.

bethlakshmi
źródło