Backend

2×5 zasad poprawnego tworzenia oraz rozwijania aplikacji w Laravelu

kodowanie

Nie jest tajemnicą, iż każdą aplikację można napisać na wiele sposobów… i w sumie to bardzo dobrze. Gdyby było inaczej, to proces tworzenia oprogramowania straciłby na przyjemności, ciekawości, a czasem też i tajemniczości. Ale po drodze często przydarzają się błędy. Jak się ich ustrzec? Opowiadają Karol Pietruszka i Rafał Migda z Webchefs.

Karol PietruszkaKarol Pietruszka. Urodzony dokładnie ćwierć wieku temu. Programista, pasjonat, początkujący prelegent oraz blogger. Współorganizator krakowskiego meet-upu o Laravelu – Web Artisans. Obecnie oddaje się jednemu ze swoich hobby w Webchefs w Krakowie. Wielki fan technologii oraz ekosystemu Apple. Chociaż jego konikiem jest PHP i Laravel to aktualnie ma na tapecie Typescript, Vue, troszkę Angular, a nawet Swift. Wyznawca twierdzenia “jeżeli nie idziesz do przodu to się cofasz”.

Rafał Migda

Rafał Migda. Senior Full-Stack Developer w firmie Webchefs. Pasjonat relacyjnych baz danych i rozszerzeń wspierających zapis danych geograficznych, takich jak PostGIS. Współorganizator krakowskiego meet-upu o Laravelu – Web Artisans. Od kilku lat silnie związany z technologiami Laravel i Vue.js. Prywatnie szczęśliwy mąż i świeżo upieczony tata.


Mnogość dróg prowadzących do rozwiązania problemów lub realizowania zadań często może stwarzać zagrożenie. Może być tak, że jedna z nich (lub z więcej) wyprowadzi nas w pole i utrudni powrót na właściwą ścieżkę lub – co gorsza – całkowicie ją uniemożliwi. Jako że oboje już z niejednego pieca chleb jedliśmy i niejeden feature poczyniliśmy, to możemy się poszczycić (a czasem i powstydzić) dokonanych wyborów, które z całą pewnością ułatwiły i przyspieszyły proces podejmowania coraz lepszych decyzji. Postanowiliśmy więc zebrać po pięć zasad, które – według naszych spostrzeżeń – były najczęściej naginane, jeśli chodzi o nasz bądź odziedziczony kod korzystający z frameworka Laravel.

5 zasad by Karol

Staraj się ponownie używać swojego kodu

Zacznę może od dość trywialnego zagadnienia, który doczekał się swojego akronimu w świecie twórców oprogramowania, tj. DRY (Don’t Repeat Yourself). Założę się, że gdy czytacie o rzekomej oczywistości rozpatrywanego problemu, na twarzach wielu z was maluje się uśmiech lub grymas. Tak, ja też należę do tego grona – bowiem DRY uważam za jedną z najświętszych zasad wytwarzania kodu.

Przyjmijmy, że dowiedzieliśmy się od naszego PM-a o nowym projekcie. Zatem nadchodzi dzień rozpoczęcia prac nad nim i okazuje się, że nowy to on jest tylko z nazwy… Ale to nic, bo do zrobienia jest mała poprawka wysyłki powiadomień o rejestracji nowych gości do dodatkowej grupy pracowników, aby mogli oni rzeczonych nowych gości obsłużyć. Siadamy więc do ulubionego IDE, odnajdujemy kawałek kodu, modyfikujemy go, a następnie testujemy. Wszystko gra i tańczy, zatem git commit i poszło!

Następnego dnia okazuje się, że jednak nie do końca zagrało i zatańczyło, bowiem powiadomienia dotarły do nowej grupy ludzi… ale w wyniku jednego ze zdarzeń, jakim jest rejestracja standardowa, natomiast powiadomienia nie zostały rozesłane w wyniku rejestracji za pomocą social mediów. Zatem wybieramy się ponownie do edytora kodu, tym razem domyślając się pogwałcenia zasady DRY. Okazuje się, że zgodnie z naszymi obawami dodaliśmy kod rozszerzający grupę odbiorców tylko do jednego z dwóch bliźniaczo podobnych miejsc w aplikacji. Mając już na uwadze rodzaj napotkanego problemu, dokładamy i refaktoryzujemy w odpowiedni sposób brakującą w tym wypadku logikę, testujemy ponownie – i jest git, a zatem git commit i poszło!

Wydaje mi się, że przytoczony przykład brzmi znajomo dla wielu z was. Zatem powtórzmy: staraj się używać swój kod ponownie – honorując zasadę DRY 🙂

Korzystaj ze zmiennych środowiskowych wyłącznie wewnątrz katalogu z konfiguracją

Temat z pozoru prosty, bo w dokumentacji zawarty jest raptem w kilku zdaniach. Uważam jednak, że warto na niego dodatkowo uczulić, biorąc pod uwagę moje doświadczenia, a w nich wszystkie te env(..) radośnie umieszczane to w kontrolerach, to w serwisach lub jeszcze gdzie indziej. Wydaje mi się, że powodem popełniania tego błędu jest nieznajomość działania komendy cache-ującej konfigurację korzystającą ze zmiennych środowiskowych do pliku .php. Po odpaleniu takowej aplikacja w odpowiedzi na env(…) spoza katalogu konfiguracji zacznie raczyć nas null-ami.

Z doświadczenia wyniesionego z poprzednich firm oraz opowieści znajomych deweloperów wiem, że wiele systemów wdrażanych jest często po przysłowiowych łebkach na serwery staging-owe lub nawet produkcyjne. Nie stosuje się tam np. komendy optymalizującej działanie aplikacji, czego wynikiem jest uśpienie powyższego błędu. Uśpienie to słowo-klucz, bo bombka cały czas tyka, czekając na bardziej rozgarniętego programistę, który prawidłowo zaktualizuje deploy script o cache i tym samym zupełnie nieświadomie pozbawi jakąś usługę np. klucza do łączenia się z API, co będzie skutkowało błędem serwera i zdenerwowaniem użytkowników tej aplikacji.

ZOBACZ TEŻ: Gdy zauważam wątpliwe praktyki, włącza mi się czerwona lampka. Historia Bartosza Doszczaka

Używaj Form Requestów do walidacji

Tutaj krótko. Moim zdaniem jest to kwestia, która stała się niepisaną tradycją, szczególnie w gronie młodszych (stażem i doświadczeniem) programistów Laravela. Gdy przeglądam całkiem fajnie zapowiadające się repozytorium równie dobrze zapowiadającego się juniora, często trafiam właśnie na przeprowadzanie procesu walidacji wszędzie, tylko nie w Form Request-ach. Czar wtedy pryska, bo przecież dokumentacja podaje w bardzo przejrzysty sposób, co jest prawidłowym miejscem dla takiego kodu.

Więc drogi Czytelniku, jeśli uskuteczniasz sprawdzanie danych w kontrolerze bądź serwisie, to polecam udać się do ulubionej wyszukiwarki, wpisać tam “Laravel validation”, kliknąć najprawdopodobniej pierwszy link i delektować się nową i bardzo przydatną wiedzą.

Unikaj jak ognia mutowania danych w akcesorach

Na samą tylko myśl o podobnych “kwiatkach” włos się człowiekowi jeży na głowie. Chodzi tutaj o taką sytuację: wewnątrz metody pewnego modelu, która jest akcesorem, zmodyfikujemy (zmutujemy) dane w jakiejkolwiek innej części aplikacji (np. odwołując się do klasy serwisu celem pobrania danych, która to z kolei może zmienić stan odrębnego modelu). Praktyka taka wywołuje z czasem szereg problemów, czy to z debugowaniem, czy ogólnym utrzymaniem i rozwijaniem aplikacji. Bo przecież nikt z nas nie chce, aby program robił coś, czego mu nie każemy, pisząc kod. Jak to zwykle w życiu bywa, problem dostrzegamy dopiero wtedy, gdy sami go doświadczymy.

Pamiętam, jak kiedyś dostałem informację, że coś niepożądanego się dzieje w paru miejscach w apce. Usiadłem więc do debugowania kodu i siedziałem tak bite pół dnia, starając się powstrzymywać negatywne emocje, które towarzyszyły mi, gdy próbowałem wytypować winowajcę. Ale udało się – bug został namierzony i zabity. Znajdował się na piątym poziomie zagnieżdżenia wywołania rzeczonych akcesorów… To właśnie tego dnia nabrałem uprzedzenia do wszędobylskiego ich stosowania.

Reasumując: jeśli modyfikujemy jakieś dane, zmieniamy stan modelów bądź je usuwamy to róbmy to w sposób możliwie jak najbardziej jawny i widoczny w wyraźnie wyznaczonych do tego miejscach 🙂

Nie dopuść do problemu n+1

Problem ten polega na wykonywaniu wielu zapytań o małe zbiory danych potrzebnych do zapytania nadrzędnego. Na przykład mamy użytkownika, który posiada relację do wielu swoich kont. Potrzebujemy pobrać 10 ostatnich użytkowników wraz z tymi relacjami. Wykonujemy więc proste query pobierające wspomniane dane. Następnie w resource odwołujemy się do nich dla każdego pobranego wcześniej użytkownika. Jak się okazuje, wykonaliśmy 20 zapytań zamiast dwóch lub trzech. Niby to niewiele więcej, ale przyjdzie czas, że będziemy potrzebować 100, 200 lub jeszcze więcej ostatnich użytkowników.

Teraz zapewne u wielu z was zapaliła się czerwona lampka pod tytułem “brak” lub “niedobór eager loading-u”, no i brawo, bo tym to w istocie jest. Zatem gdy będziemy poprawnie stosować eager loading, wyleczymy się z nadmiernej ilości zapytań. Należy też uważać, aby nie przesadzić, Rafał pisze o tej drugiej stronie medalu, jaką jest nadmierność eager loadingu.

5 zasad by Rafał

Zanim wybierzesz paczkę, przeczytaj dokumentację oraz sprawdź jej jakość

W obecnych czasach programista nie musi tworzyć wszystkiego od samego początku. Dzięki GitHubowi i całej społeczności programistycznego środowiska interesujące nas rozwiązania problemów w danej technologii. Jednak wybór paczki nie jest taki oczywisty. Nie wszystkie rozszerzenia mogą być dobre dla rozwiązania Twojego problemu.

Przykład z życia wzięty: Jeśli w przeszłości w swoich aplikacjach pisanych na Laravelu korzystałeś z rozwiązań Spatie, zapewne wiesz, że zazwyczaj są one wysokiej jakości, repozytoria są zawsze aktualne, a wsparcie stoi na wysokim poziomie. To dobrze! Jednak niekiedy dane rozwiązanie może kompletnie nie pasować do rozwiązania konkretnego problemu.

I tak jak w naszym przypadku doskonale sprawdziła się paczka Laravel Permission, tak wybór paczki do obsługi mediów stał pod znakiem zapytania, bowiem Laravel Media Library nie do końca pasował do pomysłów, które mają zostać zrealizowane w pisanych przez nas aplikacjach.

Laravel Media Library, jak wskazuje dokumentacja i dyskusja na Github issues, nie oferuje przypisywania Mediów w relacji polimorficznej wiele do wielu. Taka relacja daje absolutną dowolność w przypisywaniu wgranych plików do modeli zdefiniowanych w naszej aplikacji, co było wymagane przez naszych klientów. Zdecydowaliśmy postawić na nieco mniej popularną paczkę, jednak wskazaną przez Spatie jako alternatywę, Laravel Mediable, dzięki czemu uniknęliśmy dość dużego refactoru.

To tylko jeden z przykładów, jak dobór paczki wpływa na cały proces rozwijania aplikacji. Czytaj dokumentację, nie uzależniaj swoich aplikacji od wątpliwych zależności, a pozwoli to uniknąć wielu problemów.

Tworząc komunikaty zwrotne, zawsze stosuj translacje

Zapewne zadajesz sobie pytanie: “Mam projekt tylko na angielski rynek, to po co mam sobie zaprzątać głowę translacjami?”.

Otóż moja odpowiedź brzmi: warto to robić. Z jednego powodu – wszystkie komunikaty i treści, które są pisane z palca i leżą rozsiane po całym projekcie są trudne w utrzymaniu. Nie jesteśmy w stanie w łatwy i szybki sposób dostać się do nich, musimy szukać i liczyć na to, że nam się uda. Jeśli będziemy trzymać translacje i pliki językowe w jednym miejscu, w ciągu kilku minut dostarczymy klientowi wszystkie komunikaty zwrotne, których użyliśmy w naszym projekcie.

Warto to robić również dlatego, że klient czasem zmienia swoje zdanie, z różnych względów decyduje się na ekspansję na rynki, na których używa się odmiennych języków niż ten pierwotny.

Korzystaj z dedykowanych rozwiązań Twojej technologii

Ekosystem w obrębie danej technologii sprawia, że chcemy z nią obcować jak najwięcej. I tak się dzieje w przypadku Laravela. Mamy do dyspozycji szereg dedykowanych rozwiązań – zarówno tych oferowanych przez autorów Laravela, jak np. Laravel Forge czy Envoyer.io, po te, które oferuje nam społeczność.

I tak pewnego dnia, gdy przeglądałem Laravel News, natrafiłem na całkiem nieźle zapowiadające się narzędzie do debugowania aplikacji Laravela (ale i nie tylko) RAY. Po szybkim teście tego narzędzia zdecydowałem się je kupić. W moim przypadku sprawdziło się doskonale. Debugując aplikację w Laravelu, nie zawsze chcemy poświęcać mnóstwo czasu na konfigurowanie xdebuga, aby działał w różnych warunkach (kolejki, testy, itp.). Z drugiej strony, “printowanie” tego, co zawiera zmienna za pomocą dd(), bywa czasem uciążliwe.

ZOBACZ TEŻ: Czego słuchają programiści podczas kodowania? TOP 10 playlist

Aplikacja RAY oferuje dużo więcej aniżeli dd(). W przypadku Laravela mamy do dyspozycji skorzystanie z wielu dedykowanych funkcji, dzięki czemu debugowanie stało się dużo przyjemniejsze. Nieco więcej o aplikacji RAY opowiem już niedługo podczas krakowskiego meet-upu związanego z Laravelem – Web Artisans, który to mam okazję współorganizować wraz z Karolem i Agnieszką, odpowiedzialną za koordynowanie całego wydarzenia. Dzięki nim oraz wsparciu inicjatywy przez firmę Webchefs, w której obecnie pracuję, już teraz wiem, że event będzie stał na wysokim poziomie merytorycznym i organizacyjnym. Serdecznie zapraszam wszystkich zainteresowanych!

Testuj automatycznie i mądrze

Testy automatyczne są niezwykle pomocne w procesie wytwarzania oprogramowania. Dzięki nim możemy w przyjemny sposób najpierw rozwijać kod aplikacji, a później go utrzymywać.

Jeśli nasza aplikacja jest dobrze otestowana, to dzień deploymentu aplikacji staje się praktycznie bezstresowy, bowiem większość złych rzeczy, która miałaby się wydarzyć, pojawiła się już na etapie testów automatycznych.

Jednak testy, które są nieprzemyślane i napisane błędnie, niosą pewne zagrożenie. Przykładowo: mamy za zadanie przetestować listę stron statycznych zawierających unikalny tytuł strony oraz treść strony. Korzystając z laravelowskich faktorek i Faker’a, w naszym teście możemy zamockować wiele stron statycznych. Jeśli w naszym teście “zamockujemy” na raz 100 stron statycznych i błędnie zdefiniujemy naszą faktorkę, zapominając o unikalności tytułu, test raz na jakiś czas będzie błędny ze względu na niemożność dodania takiego samego wpisu do naszej bazy danych. Nie chcemy tego w naszych aplikacjach – test musi być napisany dobrze, nie może być zależny od tego typu czynników.

Uważaj na nadmierny eager loading

Eager loading jest fantastyczny. Jednak czasami nie jest wskazany, bowiem nieprzemyślany może być trudny w utrzymaniu i może spowolnić naszą aplikację.

Uważaj zwłaszcza na domyślny eager loading, który w eloquentowym modelu można zrealizować bardzo szybko za pomocą propetki $with. Dzięki tak zdefiniowanemu eager loadingowi przy każdym zaciągnięciu danych o danej encji pociągniemy także jego relację. Czy aby na pewno zawsze chcemy, by tak było? Zastanów się dwa razy, nim to zrobisz.

W niektórych przypadkach zastosowanie eager loadingu może być zdecydowanie mniej mniej wydajne od innych rozwiązań. Przetestuj alternatywne możliwości i zdecyduj.

Reasumując

Należy pamiętać, że powyższe porady stanowią jedynie wierzchołek góry lodowej problemów napotkanych w naszych karierach. W Webchefs stawiamy duży nacisk na jakość i optymalizację aplikacji. Więc jeśli zrozumieliście istotę powyższych błędów, problemów czy złych praktyk i zgadzacie się z wnioskami to czekamy na wasze CV.

Chcesz dowiedzieć się więcej? Zapraszamy na meetup Web Artisans Kraków Laravel Group, na którym to można będzie porozmawiać bezpośrednio zarówno z autorami artykułu, jak i pozostałą załogą Webchefs Software House.

Zdjęcie główne pochodzi z unsplash.com.

Podobne artykuły