Jeśli znasz JavaScript, znasz backend. Czy na pewno?
Jeśli znasz JavaScript, znasz backend. Czy na pewno?
JavaScript jest obecnie najbardziej elastyczną technologią i co do tego nie ma żadnych wątpliwości. Node.js, Electron, Tauri czy frameworki full-stack takie jak Astro i Next.js mogą sugerować, że bariery tworzenia aplikacji webowych, backendowych czy desktopowych, praktycznie nie istnieją.
Nie można jednak powiedzieć, że sama znajomość JavaScript otwiera te wszystkie ścieżki, ponieważ do gry wchodzi jeszcze szereg dodatkowych zagadnień i mechanik, które charakteryzują poszczególne obszary. Z drugiej strony, poznanie ich jest zdecydowanie prostsze, niż nauka nowego języka programowania od podstaw (co nie oznacza, że w niektórych sytuacjach nie będzie to uzasadnione).
Przykładowo pracując "na froncie", na każdym kroku towarzyszy nam komunikacja poprzez API, np. z aplikacją działającą na serwerze. W takiej sytuacji wystarcza nam sama wiedza o tym, co musimy przesłać i czego możemy się spodziewać. Jednak gdy sytuacja zaczyna się komplikować (np. na etapie developmentu, gdy API jest jeszcze projektowane), pomocna staje się wiedza na temat tego, "co dzieje się po stronie serwera.
Wiedza ta przekłada się praktycznie na każdy obszar naszej pracy — od komunikacji z innymi osobami z zespołu, poprzez zwiększenie naszej osobistej skuteczności, efektywności projektowanych rozwiązań, przez lepszy komfort pracy, po otworzenie zupełnie nowych możliwości rozwoju kariery.
To ostatnie jest szczególnie ważne, biorąc pod uwagę obecną na rynku sytuację oraz zapotrzebowanie na full-stack web developerów i developerki. Naturalnym potwierdzeniem tego, o czym teraz piszę, jest rosnąca popularność na narzędzia, które odpowiadają na tę potrzebę. Mam tu na myśli wspomniane Astro czy chociażby SvelteKit, w przypadku których bariera wejścia z front-endu jest niesamowicie niska. Jednocześnie swobodne korzystanie z nich i tak prędzej czy później zaprowadzi Cię w stronę ogólnych zagadnień back-endowych, od których możesz zacząć już teraz. Można porównać to do korzystania z React.js bez rozumienia fundamentów JavaScriptu w postaci chociażby operatora spread.
Przechodząc już do konkretów, dzisiejszy wpis dedykowany jest osobom pracującym na froncie, patrzącym w stronę back-endu. Odpowiemy na pytanie: od czego zacząć oraz na co właściwie patrzeć?
Dlaczego to jest dla Ciebie ważne?
Jeśli tworzysz front-end, to w kontekście rozwoju, bardziej uzasadnione wydaje się poszerzanie swojej wiedzy w obszarze UI & UX, niż działanie po stronie serwera. Zwyczajnie zagadnienia związane chociażby z bazami danych wydają się bardziej odległe, niż Auto Layout w Figma.
Co więcej, złożoność procesu tworzenia oprogramowania nadal rośnie. Pojawiają się też nowe narzędzia i techniki, którym warto poświęcić uwagę, pogłębiając tym samym swoją specjalizację w obszarze front-endu. Jeśli jednak spojrzymy na kierunek rozwoju frameworków i bibliotek, to łatwo zauważymy pewne schematy, wynikające z potrzeb rynku. Tą potrzebą jest konieczność szybkiego poruszania się przy zachowaniu możliwie wysokiej jakości. Odpowiedzią na nią jest zdolność tworzenia aplikacji zarówno po stronie klienta, jak i serwera.
W ramach ciekawostki przytoczę też perspektywę Davida Epsteina, którą świetnie przedstawił w książce "Range". Mówi w niej o tym, że odpowiedzią na coraz bardziej złożony Świat, jest generalizacja połączona z odpowiednią "głębokością" w możliwie wielu polach, niż ścisła specjalizacja w jednym z nich. Podobne zdanie wydaje się mieć jedna z najciekawszych postaci Doliny Krzemowej — Naval Ravikant, który mówi o szukaniu unikatowego połączenia swoich umiejętności z cechami charakteru.
Zmierzam do tego, że nawet jeżeli nie planujesz rozwoju jako full-stack, to i tak poszerzanie wiedzy jest uzasadnione — zarówno w stronę designu, jak i zagadnień serwerowych. Mówiąc jednak bardziej konkretnie, chodzi o:
- Bazy danych: wiedza o sposobie przechowywania informacji, które przekazujesz na serwer i które z niego odbierasz, ułatwi Ci projektowanie chociażby wieloetapowych formularzy, w przypadku których użytkownik może przerwać proces bądź wracać do poprzednich kroków. Bez zapisywania identyfikatorów, sesji czy historii, realizowanie niektórych zadań może być trudne. W praktyce więc, okazuje się, że komunikacja client-server zwykle uwzględnia szereg dodatkowych informacji, których nie widzi użytkownik.
- Autoryzacja i uwierzytelnienie: gdy zrozumiesz w jaki sposób serwer chroni wybrane ścieżki i zarządza dostępami, zdecydowanie bardziej jasna stanie się dla Ciebie rola JSON Web Token czy kluczy API. Zrozumiesz także dlaczego "ochrona" zasobów po stronie przeglądarki nie jest skuteczna. Problemy dotyczące nieautoryzowanego dostępu do zasobów są jedynymi z najczęściej występujących błędów dotyczących bezpieczeństwa aplikacji.
- Organizacja logiki aplikacji: podobnie jak po stronie front-endu, na back-endzie funkcjonują wzorce i mechaniki oferujące różne możliwości, ale też narzucające ograniczenia. Przykładowo serwer musi zabezpieczać się na wypadek przesłania ze strony klienta nieobsługiwanego formatu danych. Co więcej, musi poinformować o tym fakcie w sposób precyzyjny i spójny, umożliwiający obsłużenie błędu po stronie użytkownika. Aby to było możliwe, konieczna jest współpraca pomiędzy front-endem i back-endem. Łatwiej jest nią zarządzać w chwili, gdy mamy świadomość tego, co się dzieje z danymi po obu stronach.
- Sposób komunikacji: Dokumentacja API zazwyczaj jest wystarczająca do tego, aby przeprowadzić komunikację client/server. Jednak na etapie developmentu sytuacja jest nieco bardziej skomplikowana, ponieważ część z funkcjonalności jest na etapie tworzenia. Podobnie jak we wspomnianym powyżej przykładzie, zachowanie spójności oraz uwzględnienie wymagań po stronie interfejsu użytkownika, jak i struktury bazy danych, nie jest proste. Ponownie posiadanie przynajmniej ogólnej wiedzy o "tej drugiej stronie", znacznie ułatwia pracę w przygotowaniu schematów oraz standardu wymiany informacji (bo w praktyce REST niemal nigdy nie może być zaimplementowany w 100%, zgodnie ze swoimi założeniami).
- Wydajność: Wiele problemów związanych z szybkością działania aplikacji nie wiąże się z wykorzystaną technologią czy możliwościami serwerów. Źródło problemu zwykle leży w obszarze sposobu wymiany danych i sposobie ich wczytywania. Przykładowo, dość łatwo spotkać przykłady, w których pomimo obecności paginacji (stronicowania), z API pobierane jest jednorazowo kilkaset rekordów, które i tak wyświetlane są fragmentami. Bez względu na sposób prezentacji, ich wczytanie wymaga więcej czasu. Podobne problemy dotyczą przesyłania dużych plików, obrazów czy strumieniowania danych. Posiadanie świadomości na temat sposobów wczytywania zasobów jest wprost krytyczne do budowania wydajnych aplikacji.
- Samodzielność: W przypadku aplikacji rozwijanych w ekosystemie JavaScript, szczególnie w małych zespołach, może istnieć potrzeba wprowadzenia zmian po stronie serwera. Pracując na froncie, nawet proste modyfikacje mogą okazać się zbyt trudne. Jednak posiadanie doświadczenia w projektowaniu backendu, nawet na skali uwzględniającej prywatne zastosowanie, pozwala na znacznie większą samodzielność, co przekłada się na ogólną skuteczność i tempo działania.
- Współpraca: Nawet jeśli pracujesz na froncie, to im więcej dowiesz się na temat back-endu, tym łatwiej będzie Ci pracować w zespole, ponieważ komunikacja będzie z założenia prostsza. Przykładowo, gdy ktoś powie Ci, że wrzuci Ci status 401 w odpowiedzi, a użytkownik był zalogowany, to wiesz, że prawdopodobnie wygasł jego token i potrzebujesz go wygenerować ponownie. Podobnie sytuacja wygląda w innych przypadkach dotyczących komunikacji client-server, uwzględniając także formaty wymiany danych, których struktura nie zawsze jest bezpośrednio połączona z tym, jak prezentujemy ją użytkownikowi.
Myślę, że powyższe przykłady obrazują sytuację, choć oczywiście nie wyczerpują całego tematu. Z kolei jeśli jednak planujesz rozwój w stronę full-stack web developmentu, to tym bardziej zostań ze mną do końca.
Jakie technologie brać pod uwagę?
Jeśli znasz JavaScript, to patrząc w stronę back-endu, (niemal) zawsze będzie interesować Cię node.js i powiązane z nim frameworki. Obecnie najpopularniejszym jest Express, a zaraz za nim znajduje się NestJS, który obecnie jest moim pierwszym wyborem i sam postrzegam go jako nowszą, lepszą wersję tego pierwszego.
Praktycznie niezależnie od tego, na jaki backendowy framework się zdecydujesz, każdy z nich wykorzystuje zbliżone koncepcje, które w większości są znane od lat i sięgają znacznie dalej niż historia Node.js. Mam tutaj na myśli między innymi:
- Ścieżki (routes) odpowiadające za tzw. endpointy i powiązane z nimi akcje. Zatem gdy kierujesz zapytanie na adres GET /api/v1/users, to musi być on na obecny na liście dostępnych ścieżek.
- Middleware, to funkcje pośrednie, które zwykle wykorzystywane są do obsługi danych żądania HTTP, zanim te trafią do akcji kontrolerów.
- Kontrolery, to kolejny element aplikacji, który jest powiązany bezpośrednio ze ścieżkami. Konkretnie przy wywołaniu adresu wspomnianego wyżej, przekazane dane żądania (request) trafiają do akcji kontrolera. Jest to nic innego, jak funkcja, której zadaniem jest zwrócić odpowiedź (response) dla żądania.
- Serwisy, to warstwa w której znajduje się tzw. "logika biznesowa". Nie w każdej aplikacji ta warstwa musi występować, jednak jest to jeden ze sposobów na zarządzanie złożonością oraz współdzielenie logiki pomiędzy różnymi obszarami aplikacji. Przykładowo AuthService może odpowiadać za uwierzytelnienie połączenia i być wykorzystywany w różnych miejscach aplikacji.
- Modele, czyli reprezentacje struktury przechowywanych w bazie danych informacji. Zwykle korzystają z nich serwisy (lub repozytoria) w celu odczytywania i zapisywania danych.
Powyższy schemat jest uproszczony i będzie różnić się od architektury aplikacji oraz metodologii jej projektowania. Można to jednak traktować jako punkt startowy oraz elementy, z których będziemy korzystać w różnych konfiguracjach, podczas projektowania back-endu.
JavaScript po stronie back-endu to nie tylko JavaScript
Na tym etapie widzisz już, że po stronie serwera pojawiają się koncepcje, które albo mają inną formę po stronie frontu, lub ich po prostu nie ma. To jednak nie wszystko, bo poza elementami struktury aplikacji, mamy także zagadnienia związane bezpośrednio z charakterystyką kodu działającego po stronie serwera. Mam tutaj na myśli między innymi:
- Dostęp do systemu plików: Po stronie serwera możesz swobodnie wykonywać operacje na plikach i możesz robić to znacznie bardziej swobodnie niż poprzez File System API.
- Dostęp do narzędzi CLI: Niektóre operacje na plikach mogą wymagać wykorzystania zewnętrznych narzędzi. Np. FFmpeg pozwoli Ci na manipulowanie formatami audio i wideo. Poza tym przeprowadzanie takich operacji na serwerze nie obciąża urządzenia klienta, co nierzadko może stanowić dużą zaletę.
- Dostęp do bazy danych: Przechowywanie informacji po stronie klienta (np. w Local Storage) jest znacznie bardziej ograniczone, niż korzystanie z baz danych. Tutaj możemy przechowywać ogromne zestawy informacji i uzyskiwać do nich dostęp z dowolnego urządzenia. Zwykle w celu ułatwienia sobie komunikacji z bazą, korzystamy z narzędzi takich jak ORM (np. DrizzleORM, Prisma lub Objection.js) i/lub Query Builder (np. Knex)
- Bezpieczeństwo: Kod działający w przeglądarce, w jakiejś formie musi zostać do niej przekazany. W przypadku kodu serwerowego, użytkownik nie ma dostępu do działającej logiki, co naturalnie czyni go bardziej bezpiecznym. Oczywiście nadal musimy pamiętać o różnych formach ataków oraz różnych technikach zabezpieczania aplikacji.
- Zadania realizowane w tle: Podczas gdy aplikacja w przeglądarce musi być otwarta, aby mogła realizować jakieś zadania, po stronie serwera odbywa się to bardziej naturalnie. Kolejkowanie zapytań i harmonogramy (cron) to również zagadnienia, które musisz brać pod uwagę podczas projektowania back-endu
- Narzędzia i automatyzacja: Ostatecznie do działania aplikacji po stronie serwera, konieczne są dodatkowe narzędzia oraz przynajmniej podstawowa praca z terminalem. Poza tym do gry wchodzą tutaj także narzędzia do automatycznego procesu przygotowania aplikacji do publikacji, a także środowiska developerskie.
Zatem ponownie mamy tutaj do czynienia z zagadnieniami, które już znasz lub możesz kojarzyć, co może stanowić świetną podstawę dalszej nauki. Jednocześnie mamy szereg nowych tematów, których poznanie jest konieczne do odnalezienia się po stronie back-endu.
Od czego zacząć?
Patrząc nawet na wymienione wyżej obszary, można odnieść (słuszne) wrażenie, że jest tego sporo. Jednak aby zacząć pracę na back-endzie i przygotować swoje pierwsze API, potrzebujemy skupić się jedynie na wybranych zagadnieniach. Ponownie poruszając się po konkretach, mówimy tutaj o:
- Zainstalowaniu node.js oraz bazy danych postgreSQL lub MySQL na swoim komputerze. Alternatywą może być wykorzystanie Dockera, aczkolwiek jeśli dopiero zaczynasz, to możesz go pominąć
- Rozszerzeniu swojego IDE o pluginy powiązane z technologiami back-endowymi. Optymalnie, jeśli masz taką możliwość, rozważ skorzystanie z WebStorm lub IntelliJ (to najbardziej rozbudowane IDE od firmy JetBrains z którego sam korzystam, pomimo tego, że nie programuję w Java)
- Zainstalowaniu narzędzi do interakcji z bazami danych w formie graficznej. Przykładem może być DataGrip lub Tabnine (dostępny na macOS)
- Utworzeniu pierwszego, podstawowego serwera Express, zgodnie z instrukcją ze strony: https://expressjs.com/en/starter/hello-world.html. Po jego uruchomieniu spróbuj wykonać zapytanie z pomocą Fetch API, kierując je na adres localhost:3000. Twoja aplikacja nie musi nic robić. Wystarczy, że odbierzesz dane i zwrócisz jakąkolwiek odpowiedź, którą wyświetlisz w przeglądarce. Zobaczysz w ten sposób "jak to działa po obu stronach (client / server)"
- Nie musisz łączyć się z bazą danych z poziomu kodu. Uruchom DataGrip (nawet w wersji trial) czy Tabnine i utwórz nową bazę danych. Spróbuj dodać do niej tabele, kolumny i kilka rekordów. Po prostu zobacz, jak to działa.
- Zaawansowane: Jeśli szukasz wyzwań, spróbuj przesłać na serwer prosty plik z pomocą formularza i zapisać go na dysku. Wskazówka — skorzystaj z pomocy ChatGPT.
Gdy przejdziesz przez powyższe kroki lub gdy są Ci już znane i chcesz dowiedzieć się więcej o tworzeniu back-endu, to w tym miejscu mogę Cię zaprosić na wydarzenie nawiązujące do tego wpisu. "Jak zrozumieć back-end" to live, który poprowadzi Michał Jabłoński — człowiek, od którego sam uczę się programowania i który poprowadzi także zbliżający się Sprint Technologiczny "Pierwsze API w NestJS"
Dołącz do nas 13 listopada o godzinie 19:00. Wystarczy że zostawisz e-mail na stronie: https://ahoy.eduweb.pl/events/jak-zrozumiec-back-end-pracujac-na-froncie.
Do zobaczenia!
- Rola zrozumienia backendu na frontendzie
- Najważniejsze zagadnienia serwerowe
- Możliwości JavaScript na Serwerze
- Pierwsze kroki na backendzie