Entropia front-endu jest realna. Kod nie rozpada się z dnia na dzień. On narasta. Pewnego wtorku dodajesz bibliotekę do formatowania dat. Pół roku później ktoś dodaje kolejną, bo nie znalazł pierwszej. Polyfille piętrzą się dla przeglądarek, których już nie wspieracie. Narzędzia budujące nakładają się na siebie. W końcu folder node_modules staje się cyfrową szufladą na graty, z której niczego nie można wyrzucić bez strachu. Przestajesz aktualizować. Potem przestajesz zaglądać. Wtedy każda mała zmiana staje się hazardem.
Uderzyłem w tę ścianę, próbując podbić wersję Material UI w starym projekcie. Otworzyłem package.json i ledwo rozpoznałem połowę wpisów. Dziesiątki bibliotek leżały tam, niektóre przestarzałe o lata, inne tak niszowe, że musiałem sprawdzać git blame, aby dowiedzieć się, kto je dodał i dlaczego. Uruchomiłem komendę instalacji nowej wersji Material UI, a terminal rozświetlił się ostrzeżeniami o zależnościach peer. Pakiet, który chciałem zaktualizować, był w porządku. Ekosystem wokół niego – już nie. Zdałem sobie sprawę, że nie przeprowadzam aktualizacji. Przekopywałem się przez ruiny.
Dlaczego ten bałagan kosztuje więcej niż dumę
Ignorowanie zależności to nie problem kosmetyczny. Tworzy on realne, kosztowne problemy.
Ryzyko bezpieczeństwa to oczywiste zagrożenie. Porzucone pakiety niosą ze sobą ujawnione podatności, które skanery flagują co tydzień. Co gorsza, biblioteki, które zainstalowałeś bezpośrednio, mogą być w porządku, podczas gdy te przechodnie, które je ściągnęły, już nie. Dziedziczysz cudzy dług techniczny, nawet o tym nie wiedząc.
Koszty rosną wraz z narastającym dystansem. Im dłużej zwlekasz, tym większa staje się luka między wersjami. Przeskok o jedną główną wersję Reacta to praca. Przeskok o trzy to projekt migracyjny, który może pochłonąć tygodnie. Przestajesz otrzymywać poprawki błędów, ulepszenia wydajności i kompatybilność z nowoczesnymi narzędziami. Zespół kończy, budując rozwiązania wokół ograniczeń, które już nie istnieją.
Biblioteki umierają. Pakiet bez aktywnych utrzymujących staje się domyślnie Twoim prywatnym forkiem. Gdy przestanie działać, to Ty będziesz czytać jego zminifikowany kod źródłowy o północy. Społeczność przeszła już do lepszych rozwiązań, a Twój zespół utknął w utrzymywaniu ducha przeszłości.
Prędkość pracy gwałtownie spada. Nowi programiści spędzają swoje pierwsze dni na nauce specyficznych API dla narzędzi, które zostały zastąpione przez standardy webowe lub popularne alternatywy. Zamiast dostarczać funkcje, Twoi starsi inżynierowie stają się historykami, tłumacząc, dlaczego ten projekt wciąż używa task runnera z 2015 roku.
Przeprowadź audyt, zanim dotkniesz jakiejkolwiek wersji
Najgorszym błędem jest wykonanie masowej aktualizacji i liczenie na to, że testy przejdą. Zacznij od audytu. Weź package.json i poddaj każdy wpis przesłuchaniu.
Zadaj cztery pytania:
- Jaki problem to rozwiązuje?
- Gdzie dokładnie tego używamy?
- Czy to nadal jest konieczne?
- Czy istnieje teraz lepsza alternatywa?
Znajdziesz redundancję. Może moment i date-fns zajmują oba miejsca na liście, ponieważ dwóch programistów rozwiązało ten sam problem w różnym czasie. Może polyfill dla Internet Explorera wciąż jest dołączany, mimo że Twoje analityki pokazują zero ruchu z przestarzałych przeglądarek. Być może niestandardowy wrapper wokół fetch może zostać usunięty, ponieważ nowoczesne przeglądarki obsługują przypadki brzegowe natywnie.
Czasami zastąpienie jest lepsze niż aktualizacja. Walka z porzuconą biblioteką do wykresów przez trzy lata zmian łamiących kompatybilność może trwać dłużej niż wprowadzenie stabilnej alternatywy i przebudowanie kilku komponentów. Bądź gotowy na odejmowanie.
Ukryta warstwa: zależności przechodnie i Semver
Bezpośrednie zależności to tylko widoczna część góry lodowej. Prawdziwa masa znajduje się pod spodem w zależnościach przechodnich – pakietach, których potrzebują Twoje pakiety. Nie wybierałeś ich, ale są one wykonywane podczas Twojego procesu budowania. Powodują rozrost paczki, zwiększają powierzchnię ataku i okazjonalnie wchodzą ze sobą w konflikty, generując niejasne błędy budowania.
Musisz czytać semantyczne wersjonowanie tak, jak ono faktycznie znaczy, a nie tak, jak chciałbyś, żeby znaczyło.
- Aktualizacje Major: To migracje. Traktuj je jako zmiany łamiące (breaking changes), dopóki nie udowodnisz inaczej. Przeczytaj changelog, zarezerwuj czas i przeprowadź dokładne testy.
- Aktualizacje Minor: Dodają nowe funkcje. Mogą również w subtelny sposób zmieniać zachowanie. Nie zakładaj, że są darmowe.
- Aktualizacje Patch: Naprawiają błędy. Zazwyczaj są bezpieczne, ale jeśli Twój kod polega na danym błędzie lub jeśli poprawka zmienia wewnętrzną strukturę, którą modyfikowałeś metodą monkey-patchingu, nadal możesz coś zepsuć.
Znajomość tych zasad pomaga skategoryzować ryzyko, zanim cokolwiek dotkniesz.
Używaj swoich narzędzi jak rzemieślnik
Jeśli używasz Yarn, kilka wbudowanych komend zamienia zgadywanie w proces.
Najpierw uruchom yarn outdated. Daje Ci on migawkę tego, co uległo rozbieżności
