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.
Zobacz teraz jak może wyglądać przykładowe rozwiązanie zadania teoretycznego, w
którym chcemy zidentyfikować i zdefiniować kilka interfejsów w systemie zarządzania
użytkownikami, nad którym pracujemy.
W tych zadaniach teoretycznych i upewnić się, że żadna klasa nie jest
zmuszona do implementacji interfejsu, którego nie używa.
Przejdźmy więc do kodu.
Zobacz ten główny skrypt.
Mamy tutaj nowego użytkownika typu premium, ale już po samych portach
widzisz, że pojawiły się nowe klasy, nowe obiekty.
Przede wszystkim mamy klasę Registration Service i Registration Service.
Odpowiada nam zarejestrowanie użytkownika i ten flow aplikacji wygląda tak, że mamy
Registration Service, która implementuje tylko jedną publiczną metodę Register.
Klasa Registration Service implementuje nam jeszcze interfejs Registration,
który z kolei dalej definiuje nam tę jedną, jedyną metodę Register.
Oznacza to, że ta klasa Registration Service implementuje dokładnie tylko tę
jedną jedyną rzecz, której w danym kontekście potrzebujemy.
Implementuje konkretny interfejs dla siebie zgodnie z zasadą ISP.
Następnie mamy tutaj Auth Service, który odpowiada z kolei za autentykacji
użytkownika, a Service implementuje interfejs API Authentication, który
mamy tutaj w katalogu Identity.
I mamy tutaj metodę Authentication, która przyjmuje username password i
zwraca nam wartość typu Boolean.
Jeśli użytkownik jest z autentykacji, zapisujemy go do bazy danych.
Jeśli nie jest z autentykacji to go usuwamy, więc zobacz, że nasze
repozytorium zyskało dodatkowe funkcje, dodatkowe metody, ale także
pojawił się tutaj interfejs User Repository, który ma metodę Save delete,
więc nasze repozytorium ma bardzo ściśle określony interfejs i korzysta dokładnie z
tych metod, które są charakterystyczne dla repozytorium.
Mamy tutaj jeszcze taki data transfer Object dla usera, który jest przekazywany
z kolei jako podstawowa struktura danych, żeby zapisać ją do bazy danych.
Natomiast w naszej klasie User w klasie bazowej pojawiła się dodatkowa metoda
tutaj, którą dziedziczą wszystkie klasy pochodne.
I ta metoda tutti transformuje strukturę tej klasy, transformuje jej
pola do tego formatu do obiektu user.
Wtedy mamy kasowanie obiektów i zwraca nam już nowy typ danych, mianowicie User Tito,
który z kolei jest akceptowany jako parametr do zapisu.
W naszym repozytorium mamy rozdzielone interfejsy, bardzo wąskie
interfejsy i Registration Service i Auth Service.
Mają bardzo wąski interfejs jeśli chodzi o metody publiczne.
Mielibyśmy pewnie jakiś login service.
Często jest tak, że pakujemy całą taką logikę autentykacji rejestracji
użytkowników do jakiegoś auth serwisu klasy, która gdzieś w nazwie
ma auth authentication.
A tutaj pokazujecie jak można pójść dalej posługując się zasadą segregacji
interfejsów, żeby te interfejsy były wąskie, bardzo wyspecjalizowane
i bardzo konkretne.