wtorek, 9 lipca 2013

Więcej nie znaczy wolniej cz.7 - refaktoryzacja

ach refaktoryzacjo, a na cóż Ty mi?

Dzisiaj przyszła pora na jedną z przyjemniejszych aktywności opisywanych w ramach tej serii. Żeby jednak jakiś temat poruszyć, trzeba najpierw wiedzieć o czym będzie mowa, tak więc zacznijmy od początku, a na początku był kod (i jeszcze kilka innych produktów było wcześniej, ale na dzisiaj możemy założyć, że od kodu zaczynamy :).

Każdy z nas ma pewnie w sobie coś takiego, że chciałby aby jego kod był doskonały, pewnie większość z Was zaliczyła jakiś własny projekt, w którym setki razy dopieszczaliście isniejącą funkcjonalność, bo mimochodem wpadliście na pomysł, co tu zrobić, żeby działa/wyglądała lepiej, była czytelniejsza bądź przyjemniejsza dla oka. I tak w nieskończoność, aż pewnego dnia dochodzimy do wniosku, że już szkoda naszego czasu na pracę nad nim i trafia on gdzieś na dno szafy.

Pewnie równie wielu z Was zdaje sobie sprawę, że w projektach, które muszą ujrzeć światło dzienne i wyjść do użytkowników, takie zabiegi nie są możliwe i w pewnym momencie (zazwyczaj dość szybko) musimy powiedzieć stop i iść dalej.
Jednym zdaniem - projekty dzielimy na te idealne i te zrealizowane (niestety nie pamiętam autora cytatu) i osobiście zgadzam się z nim w zupełności i pomimo mojej lubości dobrych praktych, czytelnego kodu, itp., itd., kiedyś trzeba powiedzieć stop i ruszyć do przodu.

Ludzie zajmujący się tworzeniem oprogramowania zgodnie jednak twierdzą, że im kod czytelniejszy, im przyjemniej się z nim spędza czas, tym szybciej jesteśmy w stanie go modyfikować i ulepszać. Dlatego też, nie porzucają w zupełności tego dążenia do doskonałości i często, dotykając istniejącego kodu - refaktoryzują go. Jendak nie dlatego, żeby sobie pofolgować i dać upust temu pędowi do doskonałości, to się po prostu opłaca.

nie planuj refaktoryzacji

Refaktoryzacja to nie jest kolejne zadanie na liście rzeczy do zrobienia (no chyba, że projekt wymaga podjęcia drastycznych kroków, ale to już inna historia), wręcz przeciwnie, ta aktywność zazwyczaj nie jest nigdzie odnotowana, deweloper powinien po prostu nieustannie ulepszać kod. Piękno tego procesu polega na tym, że nie trzeba nikogo przekonywać, że "gra jest warta świeczki", że taka dodatkowa aktywność się opłaci. Tak naprawdę wymaga to jedynie zmiany myślenie programisty, przestawienia się na inny sposób rozwijania kodu.

Gdy patrzysz na zmienną, która Ci nic nie mówi i przegrzebujesz się przez zakamarki dokumentacji i kodu, po to, aby odkryć do czego ten magicznie kalkulowany int jest potrzebny, jak już tylko to odkryjesz - zmień jego nazwę na bardziej deskryptywną. Nie ograniczaj się do długości, jedyne o czym musisz pamiętać to żeby była na tyle jasna, aby zaoszczędzić następnemu programiście tych kilku chwil szukania odpowiedzi.
Wszyscy wiemy, jak prosta w dobie dzisiejszych IDE jest zmiana nazwy, więc nie wpływa to na zwiększenie czasu przeznaczonego na issue, a z pewnością wpływa na zmniejszenie czasu, który będzie potrzebny w przyszłości, gdy ponownie trzeba będzie zagłębić się w kod.

Takich prostych refaktoryzacji jest ogrom, wiele z nich wspierają współczesne IDE, sprawiając, że czas poświęcany na takie zmiany to kilka minut (maksymalnie). Tak niewiele, a jak wielkie korzyści!

Z pewnością większość z Was słyszała zdanie, że kod powinno się czytać, jak książkę i jest to prawda. Zmiany nazw, na bardziej opisowe, dokładniejsze, tworzenie wielu metod i klas z odpowiednimi nazwami, to wszystko kosztuje nas niewiele wysiłku i czasu, a o ile przyjemniejsza i prostsza jest praca, z kodem, który się czyta, a nie przegrzebuje się w celu odnalezienia sensu.

Pamiętajcie: kod częściej czytacie, niż go piszecie dlatego też warto dbać o jakość tej twórczości.

przecież to nie tylko o nazwy chodzi

Dobra, lekkie przekłamanie "wkradło" się do wcześniejszego akapitu. Napisałem, że refaktoryzacji nie trzeba planować, to dla ścisłości chciałbym sprostować powyższe - drobnej refaktoryzacji nie trzeba planować. Z tym, że chcę dodać, że "drobna" nie oznacza "nie istotna", wręcz przeciwnie, każdy detal ma wpływ na całość, a im większej jakości detale, tym jakość całości się zwiększa.

Wracając jednak do tych większych zmian. Czasami musimy zmienić kod, w taki sposób aby była możliwy jego rozwój w wymarzonym przez klienta kierunku i w takich przypadkach, taką pracę niekiedy zaplanować trzeba, zmiany są na tyle duże/istotne/krytyczne, że graniczłoby z głupotą robienie ich mimochodem. Na szczęście refaktoryzacja zazwyczaj dość szybko "się opłaca", bo najczęściej dotyczy kodu, który właśnie modyfikujemy, więc czas, który oszczędzamy przeprowadzając ją, prawie natychmiast zwraca się z nawiązką.

Dużo prościej rozszerzać kod, który jest czytelny i gdzie widać, w którą stronę i w którym miejscu należy go rozszerzać, niż taki, przez który trzeba się przedzierać i za każdym razem, gdy spotykamy jakąś zmienną czy też inną konstrukcję musimy wytężać szare komórki i niekiedy udawać się na dalsze "rozpoznanie terenu". W dodatku, dalszy rozwój funkcjonalności również będzie proporcjonalnie prostszy, jakiekolwiek zmiany, nawet te wynikłe z czystej upierdliwości są łatwe do przeprowadzenia, ponieważ łatwo je znaleźć. Ewentualne naprawy bugów również przestają wywoływać mimowolny strach na twarzy dewelopera, ponieważ wie, że nie znajdzie się w miejscu gdzie ni sensu ni logiki brak.

kod! ja zaczynam go rozumieć!

Czytelny kod sprawia, że łatwiej jest go zrozumieć, nie wymaga to znajomości historii firmy ani pracowników, którzy maczali w nim swoje palce. Po prostu siadasz i czytasz i nawet jeżeli do treści wedrze się jakaś nieścisłość, to dużo łatwiej ją poprawić.
Idąc dalej, dobra znajomość kodu wpływa na znajomość logiki biznesowej, a to bezpośrednio przekłada się na jakość tworzonego oprogramowania, ponieważ deweloper szybciej wyłapie jakieś problemy/nieścisłości w przyszłych wymaganiach, rozumie co klient chce i w jaki sposób jest to realizowane, a to często przekłada się na ilość (i jakość) pomysłów na nową funkcjonalność wychodzącą od programistów.

nowy, rzuć okiem na kody

Skoro "staremu" deweloperowi łatwiej się odnaleźć i rozumieć to, co się dzieje, to oznacza, że nowy deweloper również dużo szybciej pojmie całą złożoność projektu. Dodatkowo, im większa czytelność kodu, tym mniejsza ilość dokumentacji musi powstać. W końcu, po co otwierać kod i dokumentację i używać jednego dokumentu jako nawigacji po innym, skoro wszystko jest w jednym miejscu?

lepsze jest wrogiem dobrego

Dlaczego uwielbiam refaktoryzację? Ponieważ skupia się na ulepszaniu czegoś, co już istnieje, dopieszczaniu, sprawianiu, że jest jeszcze lepsze. Jest to technika dzięki, której mogę na chwilę zatracić się i skupić tylko i wyłącznie na sztuce, tak aby dzieło doganiało doskonałość. Stop! Z tym zatracaniem to trochę popłynąłem :)

Z refaktoryzacją trzeba ostrożnie i to właśnie dlatego, że dla wielu programistów jest to dość przyjemna czynność.
Przed przystąpieniem do pracy zawsze warto sobie określić jej zakres, wyznaczyć granice i nie wychodzić poza nie. Wiemy, którego kodu dotykamy aktualnie, który modyfikujemy i nic poza nim nie powinno nas interesować, bo to się nie skończy na "jeszcze tylko tej linijce", a refaktoryzować można w nieskończoność i tak naprawdę nigdy nie osiągniemy stanu idealnego. Ba, w pewnym momencie przestanie nam odpowiadać to, co stworzyliśmy na samym początku. Cały czas się rozwijamy i uczymy i to jest całkiem naturalne. Dlatego też tak istotne jest trzymanie się tylko i wyłącznie tego kodu, który rzeczywiście ruszamy.

Nie refaktoryzujcie nigdy dla idei, to jest zgubne i jak już wyżej napisałem - można tak w nieskończoność. To jest proces ciągły i niestety nigdy nie osiągniecie tego cudownego poczucia spełnienia, że każda linijka jest idealna, zawsze będzie coś do zmiany.
Refaktoryzacja to proces ciągły i za każdym razem, gdy modyfikujecie kod powinniście go zostawiać lepszym, niż przed Waszym przyjściem, jednak nie powinniście zapuszczać się dalej niż kod, nad którym aktualnie pracujecie.

Kolejną pułapką refaktoryzacji jest to, że wielu programistów w jej toku dochodzi do wniosku, że jeszcze można dorzucić przy okazji jakiś kod. Nie można! Refaktoryzacja kończy się w momencie, gdy tworzycie coś nowego. Stan wejściowy (to co robi aplikacja i do czego jest zdolna) musi równać się stanowi wyjściowemu. Tak więc, jeżeli dojdziecie do wniosku, że trzeba dodać jeszcze jakiś test i nie wynika on z odkrytego właśnie nieprzetostowanego kawałku kodu, to jest to ten moment, kiedy powinniście przestać :)