Refactoring – romantyczna wizja a rzeczywistość

Poniedziałek
Zaparzasz poranną filiżankę kawy. Kenijskie ziarno nadaje jej niezwykle pobudzający, ale i rześki aromat. Mijając okno, rzucasz krótkie spojrzenie na zewnątrz. Cóż za cudowny, słoneczny poranek! Jakieś wewnętrzne ciepło mówi ci, że to będzie dobry dzień. Powoli zbliżasz się do biurka, zastanawiasz się co ciekawego dziś cię czeka, jakie wyzwania rzuci ci los. Po kilku minutach spędzonych na poszukiwaniu odpowiedniego zadania trafiasz na coś co nie wygląda tak źle. Nie jest to coś super trudnego, nie jest to coś banalnego. Idealne zadanie na poniedziałkowy poranek. Otwierasz kod projektu i już od początku czujesz to okropne uczucie obrzydzenia. Spod dziesiątek linijek kodu wydobywa się odór zastanego kodu. Tak, to śmierdzi kod legacy.
Wtorek
Wczorajszy dzień nie był zbyt udany. Może i wymagana zmiana nie wydaje się zbyt trudna, ale nasuwa się pytanie w którym miejscu należy jej dokonać. Pierwsze próby nie przynoszą spodziewanego efektu. Pytasz ludzi z zespołu o wskazówki lecz okazuje się, że wszyscy, którzy mieli do czynienia z tą funkcjonalnością już dawno odeszli. W myślach zastanawiasz się czy odeszli czy też uciekli w popłochu? Kolejny dzień samotnej walki przed tobą.
Środa
Udało się okiełznać potwora. W myślach co prawda już trzy razy składasz rezygnację i rzucasz papierami, ale być może obejdzie się tym razem bez tego? Kilka if-ów umiejętnie wstrzykniętych w odpowiednie miejsca wydaje się robić robotę. Może nadal nie masz do końca pojęcia co robisz, ale wyniki są dość dobre. Postanawiasz napisać testy. Unit testy to jest to! Po pierwsze pozwolą na lepsze zrozumienie funkcjonalności, a po drugi zapewnią pokrycie warunków brzegowych. Zderzenie z rzeczywistością jest jednak dość brutalne. Autor kodu nie był fanem testów jednostkowych. Albo inaczej, może i był fanem, ale akurat tutaj nie przewidział możliwości wstrzykiwania zależności. No cóż, następnym razem na pewno się uda. Tymczasem postanawiasz uporządkować kod i stworzyć Pull Request. Od razu znajdujesz kilka pomysłów jak niskim kosztem ulepszyć kod w okolicy twoich zmian lecz czy warto ponosić ryzyko bez testów jednostkowych? Racja, lepiej się nie wychylać, jest stanowczo zbyt wiele do stracenia. Wygrywa opcja „Pull request i fajrant”.
Czwartek
Na spotkaniu zespołu podnosisz temat czasu potrzebnego na refaktoring funkcjonalności z którą właśnie się ścierasz. Jak mityczni „oni” mogli stworzyć takie gówno? „To trzeba zaorać i przepisać”. Twój zespół potakująco kiwa głową, patrząc z boku ma się wrażenie, że jesteście na koncercie rapowym. Potrzebujesz tygodnia, dwóch, góra trzech i „będzie Pan Product Owner zadowolony”. Pan Product Owner przynajmniej na razie nie podziela jednak twojego entuzjazmu. Jak usłyszał o tym, że potrzebujesz nawet 3 tygodni na to by spędzić czas na czymś co nie przyniesie żadnego namacalnego efektu to o mało nie spadł z krzesła. Na szczęście dzięki poparciu innych członków zespołu udało się wynegocjować częściowy refaktoring. Co prawda ograniczony do tygodnia, i nie teraz tylko za sprint lub dwa. Uznajesz to za sukces. Szybko jednak zostajesz zawalony stertą innych zobowiązań, oczywiście wszystko na ASAP. Na szczęście Pan Product Owner zapewnia, że to tylko tymczasowe i że jak się już odkopiecie z ASAPów to będzie chwila na odetchnięcie i refaktoring. To będzie twoja chwila by pisać idealny, skalowalny, czysty kod.
Piątek
Zaczyna do ciebie docierać, że historia zaczyna zataczać koło. Że kiedyś już Pan Product Owner zbywał twoje sugestie o refaktoring. Piątek, piąteczek, piątunio to idealna okazja do refleksji. Tematem refleksji jest „co poszło nie tak?”, „czy refaktoring to słowo tabu?” oraz „jak mieć/zdobyć czas na refaktoring?”
No właśnie, odpowiedzmy sobie na po kolei na pytania.

Co poszło nie tak?
Odsuwanie niezbędnych zmian w kodzie, zaniedbania doprowadzające go do złego stanu i wrażenia „kodu legacy” to choroba która zaczyna się niewinnie. Tutaj magiczna liczba, tutaj dodatkowy „if”, tutaj przekopiowana metoda. Samo w sobie nic z tego nie jest problematyczne, problematyczne jest to, że każde takie małe uchybienie bez stałej pracy o to by poprawiać jakość kodu, prowadzi w tempie błyskawicznym to degradacji jakości kodu. Składają się na to 3 główne czynniki:
- tzw. efekt zbitych okien, czyli łatwiej jest wprowadzić „brzydką” zmianę jeżeli kod już zawiera inny „brzydki” kod, w końcu to nie my zaczęliśmy tą karuzele degradacji, prawda?
- złożoność kodu zależy od jakości ale też i od objętości kodu. Dodając nowe linijki łatwo jest skomplikować kod. Reguła kciuka w tym wypadku mówi nam by w miarę możliwości dodawać tego kodu jak najmniej. Każda nowa linijka to potencjalny bug, to kolejna linijka która musi być przeczytana przez osobę czytającą kod i starającą się go zrozumieć
- im trudniejszy do zrozumienia kod, tym mniejsza szansa że osoba robiąca zmiany po nas będzie miała odwagę by go poprawić
Czy refaktoring to słowo tabu?
Refaktoring to może być dla naszego rozmówcy słowo-trigger. Warto przemyśleć czy to słowo nie ma negatywnych skojarzeń dla osoby z którą dyskutujemy. Ja staram się nie być uprzedzony, ale trudno nie oprzeć się wrażeniu, że o refaktoringu mówią często osoby, które niekoniecznie mają kompetencje by go umiejętnie przeprowadzić. Wg mnie warto tutaj po prostu używać pełnej definicji refaktoringu i mówić o tym jaki efekt chcemy uzysać, czyli np. „chcemy zmienić istniejący kod w taki sposób aby zredukować jego złożoność oraz zmieniejszyć koszt wprowadzania nowych zmian, bez zmiany istniejącej funkcjonalności”.
Jak mieć/zdobyć czas na refaktoring?
To zdecydowanie najważniejsze pytanie. Odpowiedź dla niektórych może wydawać się też zaskakująca. Może rzeczywiście w naszym wypadku to Product Owner ma rację ze swoją wstrzemięźliwością co do refaktoringu? Najłatwiej i najefektywniej, zmiany refaktoryzujące, wprowadzać jako część standardowego procesu implementacji nowych funkcjonalności czy też poprawiania błędów. Wprowadzanie osobnego czasu tylko i wyłącznie na refaktoring to ostateczność. Argumenty? proszę bardzo:
- redukujemy ryzyko związane z wprowadzaniem wielkich zmian. Znacznie łatwiej coś popsuć jeżeli zmieniasz 500 linijek niż gdy zmieniasz 15 lub 50, prawda?
- wprowadzamy zmiany wokół funkcjonalności, która w danym momencie jest przez nas analizowana. Oznacza to, że jest to kod który dokładnie zrozumiany i nasze zmiany będą tam najbardziej przemyślane i sensowne
- nie chcemy być postawieni pod ścianą. Zdarzają się sytuacje w postaci krytycznych błędów, kiedy musimy poprawić coś jak najszybciej. Nie chcielibyśmy by taka sytuacja stała się w chwili tuż przed planowanym refaktoringiem kiedy mamy do czynienia z kumulacją niedoskonałości kodu nagromadzoną przez dłuższy czas
- pokazujemy naszą incicjatywę, jako programista odpowiadamy za jakość tego co wytwarzamy. Jasne, że fajnie jest mieć wymówki, że „mogłem to zrobić lepiej ale mi nie pozwolili”, ale koniec końców to my będziemy musieli się męczyć z tym kodem.
- kod legacy, który przebył już kilka cykli naprawiania w nim błędów, może zwyczajnie posiadać w sobie więcej wiedzy niż jesteś w stanie zrozumieć. Nawet jeżeli kod jest brzydki to często nie ma sensu go ruszać, zwłaszcza jeżeli działa dobrze i w najbliższej przyszłości nie planujemy wprowadzać tam nowej funkcjonalności
- unikamy niepotrzebnych rozmów nt. tego czy potrzebujemy refaktoringu. Jeżeli jesteś pewien/pewna, że dany fragment kodu wymaga refaktoringu, to go robisz. Zakładając ciągłą troskę o kod, ta decyzja jest szybka (oszczędzamy czas potrzebny na osądy), zmiana jest skuteczna i mała (ograniczone ryzyko że coś pójdzie nie tak). Na pewnym poziomie doświadczenia jest to krytyczna umiejętność profesjonalnego programisty by zrobić dokonać zmiany popychającej kierunek projektu w dobrym kierunku, kawałek po kawałku.

Podsumowanie
Refaktoring to na prawdę romantyczna wizja w której siadasz do kodu i zamieniasz coś czego trzeba się wstydzić, na coś co spełnia twoje standardy czystego kodu. Nie trzeba się temu dziwić w końcu w każdym z nas jest przynajmniej trochę takiego wewnętrznego artysty, który chce stworzyć coś swojego i nadać temu pożądany kształt. Po spotkaniu z rzeczywistością jednak często okazuje się że może nie być to najefektywniejszy sposób pracy. O wiele skuteczniejszą metodą niż jednorazowe podrywy refaktoryzujące może okazać się zwykła codzienna troska o jakość dostarczanych rozwiązań. Kto powiedział że nie możemy robić mini-refaktoringu codziennie?












