Jak zarządzać delikatnym przestarzałym kodem
Published: 2022-01-26 06:11:04

Witamy w prawdziwym świecie! Przeszedłeś przez wszystkie zbytnio uproszczone przykłady dydaktyczne i zaciągnąłeś się do swojego pierwszego zespołu IT. Po zrobieniu kilku zadań rozgrzewkowych najpewniej zdasz sobie sprawę, że w Twoim projekcie znajdują się fragmenty starego kodu, z którym trudno się pracuje. Jeśli masz szczęście, ktoś w zespole będzie chciał ochronić Cię przed zbytnim zapuszczaniem się w te mroczne zakątki programowania, ale sytuacja taka prędzej czy później się zmieni. W pewnym momencie będziesz musiał zmierzyć się z rzeczywistością – duża część Twojej codziennej pracy będzie polegać na utrzymywaniu przestarzałej bazy kodu. Czytaj dalej, a dowiesz się, jak uprościć to zadanie najbardziej, jak tylko się da.

## Przejrzyj kod

Otwórz kod i nieco się z nim zapoznaj. Kod przed Twoimi oczami będzie pewnie zagmatwany, pliki będą za duże, a cała reszta będzie przypominać jeden wielki bałagan. Dobrze by było, gdybyś najpierw skupił się na strukturze plików i znalazł pewne wzorce. W projekcie, który trwa już długo i w którym nikt nie zadał sobie trudu, żeby popracować nad spójnością, najpewniej znajdziesz rywalizujące designy zastosowane w pozornie dowolny sposób. W takim wypadku spróbuj zdiagnozować wagę problemu, a systematyzację zostaw na później.

## Zaktualizuj plik README

Po przejrzeniu kodu trzeba będzie ocenić stan dokumentacji. Gdzieś powinien znajdować się jakiś plik README. Może ostatnia data jego edycji woła o pomstę do nieba, ale przynajmniej wyjaśni Ci sposób myślenia, zgodnie z którym stworzono bazę kodu. Możesz spróbować zaktualizować jego treść, jeśli natkniesz się na fragmenty, które nijak mają się do rzeczywistości. Na początek dobrze będzie wprowadzić zmiany, o których mowa w mailach i innej korespondencji dotyczącej projektu, i upewnić się, że ich opis znajdzie się w pliku README razem z odpowiednimi odnośnikami. Aktualizuj też plik regularnie, tak aby kolejna osoba pracująca nad projektem miała lżejszy początek.

## Rozpracuj budowanie projektu

Niedawno pracowałem nad kursem dotyczącym upgrade’u Angular, którego ostatnia aktualizacja miała miejsce trzy lata temu. Pierwsze filmy dotyczyły Angular 4 – wersji, która jest tak stara, że nie jest kompatybilna z najnowszym Node.js i najnowszymi procesorami. Przed zainstalowaniem jej na moim sprzęcie musiałem przejść przez serię wymuszonych upgrade’ów – a był to tylko niewielki, przykładowy projekt. Natomiast projekt, nad którym Tobie dane będzie pracować, będzie prawdopodobnie w dużo gorszym stanie.

W idealnym świecie wszystko, czego potrzebujesz do zbudowania projektu, będzie:
1. ujęte w pliku README lub innej dokumentacji,
2. nadal aktualne,
3. działać jak należy.

W większości przypadków Twój projekt nie spełni jednak tych trzech warunków, przez co sam będziesz musiał coś wymyślić. Jeśli projekt nie działa, możesz poszukać problemu i dowiedzieć się, co jest jego przyczyną.

Jeśli dokumentacja nie zawiera pomocnych informacji, kolejnym miejscem, do którego powinieneś się udać, jest plik `package.json`. `”scripts”` może zawierać jakieś wbudowane polecenie. Twoją ostatnią deską ratunku jest szukanie śladów narzędzi do budowania aplikacji, które były popularne w przeszłości, i rozpoczęcie swego rodzaju prac archeologicznych nad JavaScript:
* grunt,
* gulp,
* webpack,
* browserify,
* require.js.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywbjwgw1b8e1mqon7f6l.jpg)

## A teraz wdrożenie

Tu też możesz mieć nieco zabawy. Brak wiedzy o tym, gdzie znajdują się Twoje programy, może być dość frustrujący: obawiasz się przez to tego, co się stanie, jeśli przestaną one działać. Mieliśmy kiedyś taką sytuację, że przez kilka miesięcy próbowaliśmy dociec, gdzie „żyje” nasz wewnętrzny chatbot. Informacje tego typu powinny być prostsze w znalezieniu w przypadku systemów krytycznych, ale szukanie ich i tak zajmuje więcej czasu, niż można byłoby się spodziewać.

Wyszukanie wszystkich szczegółowych informacji o procesie wdrożenia w środowisku produkcyjnym może być czasochłonne. Szyki może pokrzyżować Ci to, że nie masz prawidłowego użytkownika bądź brakuje informacji uwierzytelniających w niektórych obszarach, a poza tym wszystko musisz sprawdzać dwa razy, żeby mieć pewność, że niczego nie zepsujesz. Gratulacje! Właśnie nauczyłeś się wprowadzać zmiany w kodzie na własnym sprzęcie. Zmiany, które będą mogły wejść do środowiska produkcyjnego. Twoja praca będzie mogła komuś pomóc.

## Zbadaj aktualnie stosowane środki zapewniania jakości (QA)

Podobnie jak w przypadku buildu – spróbuj znaleźć wszelkie dostępne Ci informacje na temat:
* testów integracyjnych,
* testów jednostkowych,
* lintingu.

Jeśli nie będzie ich w dokumentacji ani w skryptach `package.json`, możesz poszukać narzędzi, które były popularne w przeszłości. 

* Testy integracyjne:
    * protractor,
    * selenium.
* Testy jednostkowe:
    * jasmine,
    * mocha,
    * sinon.
* Linting:
    * jslint,
    * jshint,
    * tslint.

Jeżeli dokopałeś się do śladów stosowania zautomatyzowanych środków QA, staraj się korzystać z tych środków jak najczęściej. Wszystko, co robili programiści przed Tobą, może okazać się bardzo wartościowe i naprawdę szkoda byłoby to wszystko wyrzucić do kosza.

## Wprowadź test dymny

Jeśli chcesz odnowić stary silnik, za pierwszym razem uruchomisz go bez żadnego obciążenia, żeby zobaczyć, czy działa i czy się nie pali. Nazywa się to testem dymnym – wszystko jest w porządku, dopóki nie ma dymu. To samo tyczy się kodu przestarzałego: jeśli nie masz czym dokładnie przetestować aplikacji, przynajmniej ją zbuduj i sprawdź, czy uruchamia się prawidłowo. Zanim będziesz w stanie uruchamiać automatycznie bardziej skomplikowane testy, lepiej wyjdziesz na wprowadzaniu prostych zmian i korzystaniu z tej samej podstawowej procedury, aby upewnić się, że wszystko działa tak, jak trzeba.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q10unl175pyc2r2k7n1a.jpg)

## Zacznij od drobnych zmian

Jesteś już na dobrej drodze, jeśli chodzi o przywracanie projektu do życia; nadeszła pora na wprowadzanie zmian w kodzie. Niech te pierwsze zmiany będą malutkie, takie, że nikt ich nawet nie zauważy. Możesz:
* zaktualizować jedną z bibliotek,
* zmienić nazwę niektórych zmiennych lokalnych,  
* przeprowadzić refaktoryzację denerwującego antywzorca występującego w jednym miejscu.

Pamiętaj, że celem jest wprowadzenie zmiany, która nie będzie powodować żadnych skutków ubocznych.

## Przeprowadź wdrożenie do środowiska produkcyjnego

Rozwiń kod przy pomocy swoich drobnych zmian i wdróż go we wszystkich środowiskach, w tym w środowisku produkcyjnym. Celem jest przetarcie szlaku dla tego odtworzonego procesu – przelanie zmian w kodzie z Twojej głowy na urządzenia klientów. Zadanie jest wymagające, dlatego właśnie ograniczamy zakres zmian do minimum. Twoim zadaniem jest zwiększenie swojej pewności siebie i zaufania interesariuszy.

## Dodaj testy integracyjne

Testy integracyjne najprawdopodobniej będziesz musiał zbudować od zera. Chodzi tu o ten etap testowania, w którym sprawdza się, czy wszystko jest należycie zintegrowane i czy działa prawidłowo. Testy te znane są również pod nazwą end-to-end (E2E), ponieważ często polegają na jednoczesnej weryfikacji frontendu i backendu. Warto zacząć od nich, bo nie będzie miało znaczenia, że Twoja aplikacja prawidłowo wylicza na przykład podatek VAT, jeśli będzie wyłączać się po każdej próbie rozpoczęcia nowej transakcji. Na pierwszy rzut oka sensowniejszym pomysłem może wydawać się stworzenie prostych testów dla wielu stron, a nie precyzyjnych skryptów tylko dla kilku z nich. Proste testy, obejmujące choćby sprawdzenie trasy albo tego, czy kluczowe elementy interfejsu są nadal dostępne, mogą być bardzo wartościowe – wyłapią przypadki całkowitego rozsypywania się stron.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1z1s5zqruj471jdqzrq1.jpg)

## Przygotuj i zacznij dodawać testy jednostkowe

Po upewnieniu się, że aplikacja działa, jak trzeba, możesz przejść do szczegółów: sprawdzić, czy działają wszystkie jednostki – klasy, funkcje itd. Możesz je przetestować z poziomu interfejsu użytkownika, ale testy end-to-end:
* długo się pisze – zebranie odpowiednich danych w jednym miejscu zajmuje sporo czasu;
* działają powoli – utrzymywanie uruchomionych baz danych, backendu i przeglądarki wymaga dużo zasobów.

Zamiast wpychać do ustawień integracji wszystkie przypadki brzegowe, jakie tylko przyjdą Ci na myśl, lepiej jest mieć na podorędziu osobny test przeznaczony do zajmowania się drobiazgami. Innymi słowy – potrzebne Ci będą testy jednostkowe. Testy te:
* są o rzędy wielkości szybsze od testów E2e,
* nie łączą się z backendem ani z bazą danych,
* pozwalają na testowanie najdrobniejszych elementów aplikacji niezależnie od otaczającego je kodu i workflow.

Chcesz dowiedzieć się więcej? Tutaj dowiesz się, dlaczego według mnie [warto pisać testy jednostkowe](https://poznaj.dev/po-co-komu-testy-jednostkowe).

## Kod lint

Lintery to programy do statycznej analizy kodu, których zadaniem jest identyfikacja wspólnych źródeł różnych problemów. Dobrze jest mieć ustawioną regularną weryfikację kodu, która sprawdza, czy wszystko działa prawidłowo. [eslint](https://eslint.org/), popularny linter dla JavaScript i TypeScript pozwala na szeroko zakrojoną konfigurację. Możesz ustawić plik konfiguracyjny tak, żeby wyłapywać tylko najbardziej problematyczne kwestie, naprawić całą bazę kodu i zintegrować ją przy pomocy Twojego edytora kodu. Aby uzyskać jeszcze więcej wartości, możesz zacząć dokonywać na tym pliku różnych iteracji – włączając lub wyłączając różne zasady i dodając wtyczki obejmujące konkretne frameworki. Dzięki temu sprawisz, że kod z czasem się poprawi; jednocześnie poszczególne kroki będą niewielkie i nie zabiorą Ci zbyt dużo czasu już na samym początku.

## Trzymaj się jednego stylu kodowania

Stosowanie tego samego formatowania upraszcza czytanie kodu: unikniesz dziwnie sformatowanych miejsc, które przyciągają uwagę z niewłaściwych powodów. Konsekwencja w bazie kodu wprowadza poczucie porządku i daje spokój ducha, jeśli chodzi o aktualny stan projektu. Styl kodowania to temat zaciętych dyskusji. Nie przykładam szczególnej wagi do formatowania; zależy mi tylko na zachowaniu konsekwencji niezależnie od tego, kto i kiedy napisał kod, i chciałbym, aby ustalony styl był wykorzystywany automatycznie. Na szczęście istnieją narzędzia takie jak [prettier](https://prettier.io/), które w mgnieniu oka formatują całe projekty i pozwalają zespołowi zadecydować tylko o niektórych kwestiach. Co oznacza możliwość przerzucenia samego formatowania i niekończących się dyskusji na ten temat na zewnętrzne narzędzie!

## Przeprowadź łatwe aktualizacje bibliotek

Czas na finalną rozgrzewkę. Możesz spróbować zaktualizować niektóre zależności z jednej wersji do wersji nowszej – na przykład z wersji 1.2.3 do 1.2.4. Wszystkie biblioteki zewnętrzne wykorzystywane przez Twój kod są najpewniej przestarzałe. Ich aktualizacja będzie wymagać dużo pracy, ale będzie warto: nowsze wersje będą pewnie miały nowe funkcje, poprawki bezpieczeństwa i więcej materiałów dostępnych online. Nawet wprowadzenie łatki nie jest trywialną zmianą, a z całą już wykonaną przez Ciebie pracą w zanadrzu możesz oczekiwać jednego z dwóch rezultatów:
* po aktualizacji pojawią się błędy, które zostaną wyłapane przez jedną z warstw weryfikacyjnych;
* wszystko będzie działać, jak należy – podczas testów i w środowisku produkcyjnym, już po wdrożeniu.

Pamiętaj, nie spiesz się z tymi aktualizacjami! Wprowadź jedną, wdróż ją i poczekaj na reakcję. Pamiętaj, uczysz ludzi wiary we wprowadzane przez Ciebie zmiany i ostatnią rzeczą, na której Ci zależy, jest regresja. 

## Wprowadź jak najmniejsze, jak najprostsze ulepszenie w interfejsie użytkownika

Jak dotąd Twoja praca była dla użytkowników niemalże niewidoczna – chyba że mimo wszystko udało Ci się zamieszać w środowisku produkcyjnym. Gdy organizację całej infrastruktury masz już za sobą, możesz zająć się dodawaniem wartości! Wybierz jak najdrobniejszy i najprostszy problem – literówkę na stronie albo brakujący margines na przycisku. Twoim celem jest pokazanie sobie i innym, że potrafisz naprawiać błędy i wprowadzać zmiany w kodzie bez psucia innych rzeczy. Nie zepsuj tego, porywając się z motyką na słońce.

## Wdróż proces ciągłej integracji (CI)

Jeśli projekt zacznie przeżywać swoją drugą młodość, możesz spodziewać się napływu większej liczby żądań zmian. W takim wypadku sensownym posunięciem będzie wprowadzenie ciągłej integracji. Jeśli chcesz dowiedzieć się więcej,  daj mi znać w [akciecie](https://strawpoll.com/jezdjoe8u).

## Co dalej?
Gratulacje! Właśnie zostałeś osobą, do której wszyscy będą się zwracać, kiedy pojawią się problemy z przestarzałym kodem. Ciesz się z nowo nabytego bezpieczeństwa zawodowego – opisaną tu pracę trzeba wykonać, a ludzie raczej się do niej nie kwapią. W takim momencie aż prosi się, żebyś sprawdził, czy Twoje wynagrodzenie stoi na poziomie rynkowym i odzwierciedla wartość, którą wnosisz do firmy – [więcej na ten temat przeczytasz tutaj](https://poznaj.dev/jak-dostac-podwyzke-w-branzy-it).