10 praktyk hańbiących developera – cz. II
Kolejna lista powodów, dla których w niektórych projektach pracuje się przyjemnie, a w innych... już niekoniecznie.
W zeszłym tygodniu pojawiła się pierwsza część wpisu dotyczącego 10 najgorszych praktyk developerskich. Jeśli jeszcze go nie czytałaś/eś, kliknij tutaj. Co jeszcze znalazło się na liście?
6. Brak modułowości, czyli wielka micha spaghetti
Jeśli mamy już kod z wcięciami, który się w miarę łatwo czyta, to warto wspiąć się poziom wyżej i zastanowić się, jak całe rozwiązanie jest ustrukturyzowane. Czy mamy do czynienia z jednym gargantuicznym plikiem, czy może setką małych? Jeden plik niektórym może wydawać się lepszym rozwiązaniem, no bo przecież mam wszystko pod ręką. Niby tak, ale co jeśli pracujemy w kilka osób nad takim plikiem? Konflikty, konflikty, konflikty – a potem trzeba robić doktorat z obsługi gita. Dużo lepiej rozbić kod na wiele małych plików. Wtedy problem konfliktów znacząco się zmniejsza. Przy okazji znacząco zmniejszamy ryzyko wprowadzenia przypadkowych błędów. Błędów typu: gdzieś się tam kliknęło, coś tam się przypadkiem wpisało.
Teraz pewnie ktoś stwierdzi, że zarządzanie setką plików jest trudne. No cóż… tu nie chodzi o to, aby mieć setkę byle jakich plików. Pliki to bardzo duże uproszczenie. Tak naprawdę chodzi o modułowość całej aplikacji. Chcemy mieć odpowiednią ilość (nie za małą i nie za dużą) luźno powiązanych modułów. Każdy moduł powinien być zwięzły i spójny. Jeśli mam moduł odpowiedzialny za rozmawianie z zewnętrznym API, to nie chcę, aby tam pałętał się też kod związany z zapisywaniem do lokalnego pliku. Prosta zasada Single Responsibility – jeden moduł – jedna odpowiedzialność. Wtedy dużo łatwiej zapanować nad całością.
7. Rodzynki w misce spaghetti, czyli czego nie chcemy w kodzie aplikacji
Słyszałeś o ostatnim wycieku danych z …? Nie wiem, kiedy będziesz czytać ten artykuł ale jestem przekonany, że niedawno gdzieś coś wyciekło. Zadziwiające jest jak często programiści sami – zupełnie nieświadomie – przyczyniają się do wycieków wszelkiej maści. Tworząc algorytm szyfrujący, wrzucają hashe, sole, pieprze i inne tego typu rzeczy bezpośrednio do kodu. Czasem w kodzie można znaleźć dane dostępowe do środowiska produkcyjnego, a jeśli to jest środowisko w chmurze, to można komuś narobić kosztów. Czasami są to dane do baz danych, a w bazach, jak to w bazach, zazwyczaj jest bardzo dużo ciekawych rzeczy.
Czasem zdarza się tak, że w kodzie nie ma nic, do czego można by się przyczepić, ale obok kodu aplikacji radośnie leży sobie plik z wszelkimi rodzynkami, hasłami i URLami i z zadowoleniem commitujemy to do repozytorium kodu. No właśnie, a co jeśli ten kod wycieknie? Wystawiamy całą infrastrukturę na atak. Co się stanie, jeśli cała infrastruktura Twojej aplikacji zostanie wyłączona? Niemożliwe? Praca zdalna jest coraz bardziej popularna. Wystarczy, że ktoś zgubi sprzęt, a ten trafi w niepowołane ręce. Dobrą praktyką jest, aby zarówno w kodzie, jak i repozytorium nie było kluczy, haseł, możliwie nawet bez URLów do usług.
8. Przedwczesna optymalizacja
Taki tam mały grzeszek – a może nie grzeszek? Przecież wiadomym jest, że „tu, o tutaj, to będzie wolne i trzeba to zoptymalizować od razu”. Jeśli nie przyszło Ci to nigdy przez myśl, to omiń ten akapit. Jeśli jednak czytasz dalej to zastanówmy się, dlaczego przedwczesna optymalizacja to nie jest coś pożądanego. Mamy tu do czynienia z dwoma problemami. Pierwszy jest taki, że optymalizacja, czy to wydajności, czy zużycia pamięci, często powoduje, że kod staje się mniej czytelny. Trudniej go zrozumieć, czyli trudniej rozwijać, a jednocześnie łatwiej wprowadzić błąd. Tego nie chcemy, jeśli nie jest to potrzebne. No właśnie, niepotrzebne.
Tu dotykamy drugiego problemu. Kto wie, która część mojej aplikacji „muli”? Czy to funkcja X, która ma 2 linijki i wykonuje się w 0.1 sekundy? Czy funkcja Y, która ma 10 linii i wykonuje się w 5 sekund? Co jeśli dodam, że funkcja X jest wywoływana 10 000 000 razy na godzinę, a funkcja Y raz w miesiącu? Nie ma co rzucać się na optymalizację w ciemno, bo jest więcej niż pewne, że spadek wydajności ma zupełnie inne źródło niż Ci się wydaje. Sięgnij po dobry profiler i sprawdź empirycznie, co tak naprawdę spowalnia aplikację. Tak robią profesjonaliści. Nie optymalizują wszystkiego, są jak snajperzy. Znajdują cel i go eliminują. Skutecznie i w punkt.
9. TODO, czyli poprawię to później
Wiele razy zostawiałem sobie w kodzie komentarz zaczynający się od magicznego TODO – do zrobienia. Najczęściej po kilku miesiącach trzeba było usunąć komentarz, bo nie pamiętałem, o co w nim chodziło i czy to ma jeszcze w ogóle sens. My developerzy, pod presją czasu lubimy zostawiać TODO, bo naiwnie wierzymy, że nadejdzie ten dzień, kiedy będzie chwila i poprawimy kod. Uwaga, to może Cię zszokować: ta chwila zazwyczaj nie nadchodzi! Kończy się sprint i trzeba pozamykać zadania, bo przecież nam velocity spadnie. Serio wierzysz, że jak na szybko odmalujesz kod, tak żeby jako tako działało i w TODO pozaznaczasz co tam jeszcze trzeba poprawić (byle tylko zamknąć wszystkie taski w sprincie, żeby velocity rosło, a KPI były prawilne), to w następnym sprincie to naprawisz? Naprawdę wierzysz, że taka robota na ostatnią chwilę nie będzie się odbijała czkawką za 1-2 sprinty?
10. Niemyślenie o przyszłości
Siadamy i kodzimy. Kodzimy jakby nie było jutra. Jakiż to wspaniały i kreatywny moment. Spod palców lecą kolejne linie kodu, maszyna albo i setka maszyn radośnie uruchamia kod i dzieje się magia. To jest to, co urzeka wiele osób wchodzących w ten zawód, ale zarazem to, co powoduje, że za pół roku, za rok klniemy na czym świat stoi. Kto to tak napisał…?! Git blame… aha to ja… No właśnie. Zanim siądziemy do kodowania, warto się zastanowić, co tak naprawdę chcemy napisać. Czy w ogóle warto to pisać, a jeśli tak, jak zapewnić, by miało to ręce i nogi oraz współgrało z istniejącą już częścią systemu.
Osobiście bardzo lubię TDD – Test-Driven Development – ale brakuje w tej metodyce jednej rzeczy – myślenia. Powinno być TTDD – Think Test-Driven Development. Zanim dotkniemy klawiatury, warto dokładnie przemyśleć, co chcemy napisać i jak to będzie działało. Dopiero po wykonaniu tej czynności możemy użyć np. TDD do zaimplementowania funkcjonalności. Stwierdzenie kodzimy – jakoś to będzie – zazwyczaj kończy się bardzo źle i zgadnij na kogo spadnie przyjemność walczenia ze skutkami? Na pewno nie na klienta, na pewno nie na kierownika, za to z całą pewnością na zespół, który tak stworzył aplikację. Jak sobie pościelisz, tak się wyśpisz.
Nie zgadzasz się? Okay, jakie w takim razie według Ciebie są najgorsze rzeczy, jakie można popełnić w kodzie?