Tworzenie kodu według najlepszych praktyk
2 godz. 45 min · Full-stack i Programowanie
Rafał PiekaraSoftware KomandosNie zrozumiesz SOLIDa bez teoretycznych podstaw. Przejdziemy przez założenia stojące za każdą z nich. Przeanalizujemy problemy, które możesz spotkać oraz dowiesz się dlaczego ciągle jeszcze tak wielu programistów nie stosuje się do tych zasad.
Ruby i Typescript to technologie, które świetnie odzwierciedlają uniwersalizm SOLIDa. Te złote zasady działają w językach dynamicznie typowanych i interpretowanych jak Ruby oraz przy statycznym typowaniu na przykładzie Typescript.
Zanim zabierzesz się za programowanie warto poćwiczyć SOLIDny sposób myślenia. Zmierzysz się z zadaniami, w ramach których będziesz projektować kod tak, aby wszystkie zasady SOLID znalazły w nim swoje zastosowanie.
Prawda jest taka, że kod, z którym w większości pracujemy ma swoją historię. Czasami historia ta jest tak bolesna, że klasy i metody są zagmatwane, poplątane i trudne w utrzymaniu. Gdy dotrzesz do tego miejsca będziesz mieć w arsenale wszystkie potrzebne narzędzia, żeby zmierzyć się z zadaniami praktycznymi, które przekształcą kod legacy w SOLIDne arcydzieło.
Tak ważny temat, jak testowanie nie może zostać pominięty. Między innymi po to też stosujemy zasady SOLID, żeby nasz kod praktycznie sam się testował. Napiszesz więc testy, których wzorce możesz wykorzystać w dowolnym projekcie, dowolnej technologii, jeśli tylko kod, który testujesz będzie spełniał wymagania zasad SOLID.
Nie ma znaczenia, czy dopiero zaczynasz przygodę z programowaniem, czy też jesteś starym wyjadaczem, który klasami i interfejsami myśli przy zagryzaniu tosta na śniadanie. Ten kurs jest właśnie dla Ciebie. Technologia ani język programowania też nie mają znaczenia. Zasady SOLID to uniwersalny zbiór. Ich znajomość sprawi, że Twój kod będzie lepszy, łatwiejszy w utrzymaniu i odporny na perturbacje i zmiany.
Solid to nie tylko łąka usłana kwiatami i tęcza nad łąką.
To też masa błędów, które możemy popełnić w trakcie implementacji
naszych zasad, w trakcie usilnego starania się, żeby te zasady spełniać.
I ja 10 takich błędów wybrałem i teraz każde z nich pokrótce omówię.
Błąd numer jeden to jest over engineering over engineering, czyli przesadna
implementacja, dodawanie zbyt wielu warstw abstrakcji, wydzielanie zbyt wielu małych
metod, sprawianie, aby nasz kod był tak bardzo solid, że zapominamy o tym,
żeby on tak naprawdę dawał wartość.
Kod przede wszystkim jest dobry i czysty, kiedy daje wartość biznesowi, kiedy
funkcjonalności i funkcje, które implementujemy w kodzie
działają i dają wartość końcowemu użytkownikowi i po prostu
przynoszą kasę biznesowi.
A jeśli mamy over engineering, tracimy czas na dodatkowe testy.
Tracimy czas na sprawdzanie, czy nasz kod jest stabilny.
Mamy zbyt dużo metod, które później trudno utrzymywać, więc łatwo przesadzić w drugą
stronę, gdzie zgadza obiektów dużych klas.
Z wieloma metodami, które robią wszystko.
Będziemy tak bardzo chcieli się zrobić SOLID tak bardzo chcieli wyszukać
te pojedyncze odpowiedzialności, że skończymy na milionach klas z małymi
metodami, jedną linijkę nowymi, które z kolei będą trudne do utrzymania, bo będzie
ich tak dużo i cognitive load, który będzie potrzebny do tego, żeby te klasy
refaktoryzacji, żeby je utrzymywać, żeby wyeliminować bugi, będzie
po prostu zbyt duży.
Więc błąd numer jeden over engineering.
Trzeba naprawdę dużo wyczucia, żeby nie przesadzić, ale to wyczucie
zdobywa się przez doświadczenie.
Ty to doświadczenie będziesz teraz zdobywać, bo masz te narzędzia, masz
wiedzę i ćwiczenia praktyczne, które już przerobiła eś.
Przerobiła się w tym kursie, które pozwolą Ci umiejętnie dostosowywać swój kod
do tego, żeby spełniał zasady SOLID.
Błąd numer dwa to zbyt dużo małych interfejsów.
Jeśli na siłę będziemy się starać, aby spełniać zasady SOLID i wydzielać małe
kontrakty, małe interfejsy, bo skończymy z tym, że będziemy mieć przesyt małych form
w kodzie, które będą dla nas nie do ogarnięcia umysłem.
Błąd nr 3 Dodawanie nowych metod.
W momencie kiedy chcemy spełnić zasadę OCP i sprawiać, żeby nasz kod był rozszerzany,
możemy ją trochę mniej zinterpretować, interpretować w zły sposób.
Poprzez rozszerzanie będziemy rozumieć dodawanie nowych metod, a nie o to chodzi.
W zasadzie Open Krauss Principle.
Chodzi o to, żeby nasz kod przybrał formę trochę takich
wtyczek, które wtykami do gniazda trochę jak klocki Lego.
Nie tworzymy nowych klocków, nie do budowy nowych metod, ale dołączamy
je do istniejącej budowli.
Wobec czego dopisywanie nowych metod jest niejako modyfikacją istniejącego kodu.
Nie jest rozszerzaniem, chyba że ta nowa metoda niesie nam totalnie inne zachowanie
niż to, które już mamy, bo nie będziemy wtedy wstrzykiwać jakichś
karkołomnych konfiguracji do konstruktora klasy, żeby zmienić jej zachowanie
zgodnie z nowymi wymaganiami.
Więc tutaj też trzeba dużo rozwagi i dużo analizy, zanim usiądziemy do pisania kodu.
Błąd numer 4 to nadpisywanie metod i zmiana ich zachowań.
O tym mówiłem już wcześniej.
Jeśli chodzi o kilka poprzednich zasad.
Kiedy chcemy tworzyć łańcuch dziedziczenia i nadpisuje
metody, musimy się starać, żeby nie zmieniać radykalnie ich zachowania.
Nadpisywanie metody to jest narzędzie udostępniane przez niektóre języki, które
pozwala nam zmodyfikować istniejące zachowanie obiektu w danej metodzie,
ale nie możemy radykalnie zmienić.
Jeśli mamy klasę, która wysyłam maile, nie możemy nagle wysyłać SMS ów.
Trzeba o tym pamiętać, żeby nie zmieniać radykalnie zachowania metody.
Błąd nr 5 Bezpośrednie tworzenie instancji w klasach.
Jeśli wstrzykuje się zależności, to pilnujmy tego, żeby je
wstrzykiwać z zewnątrz klasy.
Tworzenie instancji w danej klasie nie jest wstrzykiwania zależności.
Dlaczego jest to błąd, skoro przecież ten kod działa i zachowuje się poprawnie?
Ano dlatego, że te zależności nam umkną i możemy skończyć na tym, że będziemy je za
każdym razem instancje chować w każdej innej klasie, zamiast tworzyć jedną
instancję, która będzie wstrzykiwania.
Są języki, które umożliwiają nam tworzenie tak zwanych kontenerów do wstrzykiwania
zależności, ale są też rozwiązania, które tych kontenerów nie dostarczają.
I wtedy tego typu zachowanie, tego typu kod może nas po prostu
uderzyć w twarz błędami.
Błąd nr 6 to abstrakcja na wszystko.
Jak już będziemy tworzyć abstrakcję, możemy skończyć na tym, że będziemy mieć
abstrakcję na każdą drobną, dziwną rzecz.
I to też nie jest dobre.
Trzeba wyważyć złoty środek.
Nie będę się tutaj zbytnio rozwodził, po prostu zostawiam to Twojej
ocenie, Twojemu doświadczeniu.
To nabywa się w praktyce, nabywa się w boju.
Więc będzie taki moment, w którym w Twoim kodzie będzie naprawdę dużo abstrakcji, a
skończysz na momencie, w którym tych abstrakcji będzie dokładnie tyle, ile
trzeba i każdy interfejs będzie miał duże znaczenie dla logiki aplikacji.
Błąd numer 7 to zbyt dużo odpowiedzialności w klasach,
czyli złamanie zasady SRP.
Tutaj wszystko jest chyba jasne.
Budujemy klasy, które mają zbyt dużo odpowiedzialności, bo
chcemy, żeby były elastyczne.
Chcemy wstrzykiwać te zależności i możemy skończyć na tym, że nasza klasa
robi zwyczajnie zbyt wiele.
Kolejny błąd to zbyt duże interfejsy, czyli to, co prowadzi nas do
implementacji zasad LSB i ESP, gdzie pilnujemy tego, aby nasze interfejsy
były konkretne, małe i bardzo dobrze i ciasno zdefiniowane, Żeby nasze
klasy korzystały tylko z tych metod, implementować tylko te metody, które są
faktycznie potrzebne, więc potrzebujemy małych, konkretnych interfejsów.
No i błąd numer 9 to częsta modyfikacja istniejącego kodu.
Jeżeli nasz kod istniejący już napisany kod musi być często modyfikowany z innego
powodu niż zmieniające się wymagania biznesowe, bo to jest
czynnik, który uzasadnia modyfikację kodu.
Wiadomo, zmienia się logika aplikacji, musimy coś zmienić, ale jeśli dodajemy
nową funkcjonalność, która bezpośrednio nie jest związana z tym kodem, a ona i tak
go dotyka, to znaczy, że popełniliśmy błąd na etapie designu i trzeba przeanalizować,
czy wszystkie zasady są prawidłowo zachowane.
Ostatni, dziesiąty błąd to ślepe ufanie postanowieniom,
które mamy gdzieś na początku.
Ślepe ufanie temu, że dana klasa powinna mieć jedną odpowiedzialność i trzymamy się
tego tak bardzo kurczowo, że rodzą nam się później potworki.
Dużo małych klas z małymi interfejsami, które sprawiają problem w utrzymaniu.
Pamiętaj, że programowanie to jest dynamiczna dyscyplina.
Tworzenie aplikacji to dynamiczna dyscyplina.
Wiadomo, software musi być stabilne, oprogramowanie musi być stabilne i odporne
na błędy, ale ślepe ufanie postanowieniom, decyzjom, które gdzieś na początku
podjęliśmy, może prowadzić do błędów.
Bo biznes się zmienia, rynek się zmienia, technologia się zmienia, a
tylko krowa nie zmienia zdania.
Nie ufaj ślepo postanowieniom, analizuj cały czas swoje decyzje, analizuj kod i
wprowadzać zmiany tam, gdzie to jest konieczne.