Najważniejsze zagadnienia, które musisz znać
5 godz. 53 min · JavaScript · Full-stack i Programowanie
Adam GospodarczykPrzesyłanie oraz transformacja danych to jeden z najważniejszych elementów działania każdej aplikacji. Dobre zrozumienie tego w jaki sposób odbywa się ten proces, daje równocześnie lepsze zrozumienie całej struktury oraz podejmowania decyzji projektowych. W tym kursie znajdziesz lekcje, które pozwolą Ci uporządkować wiedzę na temat protokołu HTTP oraz formatów wymiany danych.
REST oraz GraphQL to nadal nieodłączone zagadnienia tematu wymiany informacji w kontekście aplikacji webowych. Pomimo tego, że ich koncepcje zwykle są bardzo dobrze opisane w różnych źródłach, tak ich wykorzystanie "na produkcji" potrafi sprawić problemy. W szczególności gdy weźmiemy pod uwagę, wyjątki oraz fakt, że nie każda aplikacja będzie wymagać implementacji REST czy GraphQL w 100%. W tym kursie znajdziesz wiele praktycznych wskazówek związanych z pracą z REST API oraz wprowadzenie do pracy z GraphQL.
Niektóre błędy w aplikacji są bardzo pożądane, w szczególności gdy jasno informują użytkownika o tym, co się wydarzyło oraz o tym, co może z tym zrobić. Pomimo tego, że w wielu przypadkach opracowanie komunikatów leży w rękach osoby odpowiedzialnej za copywriting (i/lub ux writing), tak sama implementacja tych komunikatów odbywa się po stronie kodu. Nie rzadko okazuje się, że poprawna i skuteczna walidacja danych oraz obsługa błędów nie jest oczywista w "produkcyjnych" sytuacjach. W tym kursie znajdziesz najczęściej spotykane problemy oraz sposoby ich rozwiązania.
Bazy danych są praktycznie nieodłączną częścią każdej aplikacji. W roli full-stacka prędzej czy później przyjdzie Ci z nimi pracować a nie rzadko nawet projektować oraz rozbudowywać ich struktury. W tym kursie znajdziesz informacje o bazach danych, które pozwolą Ci je zrozumieć oraz od razu poznać użyteczne techniki, które pomogą Ci w pracy z nimi, zarówno na produkcji jak i w środowisku lokalnym czy testowym.
Nie wszystkie informacje w aplikacji są publiczne. Niektóre wprost nie mogą takie być. Z tego powodu niezbędne są sposoby na to aby poznać a potem weryfikować tożsamość użytkownika, by na jej podstawie przydzielać mu dostęp wyłącznie do zasobów, do których odczytywania posiada uprawnienia. Istnieje wiele technik, które umożliwiają zarządzanie dostępem do danych i w tym kursie poznasz najważniejsze z nich. Dowiesz się nie tylko w jaki sposób zabezpieczać dane ale poznasz też najpopularniejsze sposoby na to aby te zabezpieczenia łamać i obchodzić. Mając świadomość takiej możliwości, będziesz w stanie lepiej podejmować decyzje o tym jak projektować dostęp do informacji.
Istnieją problemy charakterystyczne dla niemal każdej aplikacji. W związku z ich powszechnością, istnieje też szereg rozwiązań lub sposobów na to, aby możliwie zredukować ich następstwa. Na przestrzeni lekcji tego kursu zobaczysz wiele przykładów, które pomogą Ci w codziennej pracy a niekiedy nawet, pozwolą uniknąć błędów, których konsekwencje nie zawsze występują natychmiast.
Kurs powstał z myślą o osobach, które chcą rozwijać się w roli full-stack web developera / developerki, przeprowadzając przez najważniejsze zagadnienia z obszaru wymiany, transformacji oraz przechowywania informacji w aplikacji oraz pomiędzy aplikacjami. Jeżeli potrzebujesz zobaczyć szeroką perspektywę tego, w jaki sposób dane przepływają pomiędzy różnymi częściami aplikacji, lub ugruntować swoją wiedzę na ten temat, to ten kurs jest miejscem, którego szukasz.
W tym momencie proponuję, abyśmy przyjrzeli się trochę temu, w jaki sposób
w ogóle wyglądają bazy danych i jak się je projektuje oraz co dużej bazy SQL od SQL.
Mianowicie niemal każda aplikacja
przechowuje informacje na temat użytkowników.
W przypadku bazy SQL będzie to tabela, wewnątrz której musimy zdefiniować
kolumnę, a następnie dodać do niej poszczególne wiersze, które dokładnie
zawierają informacje na temat użytkowników.
Naturalnie tych kolumn może być
zdecydowanie więcej, ale w związku z tym, że mamy do czynienia z tabelą, to od razu
musimy określić jakie kolumny występują w przypadku użytkowników.
Przykładowo, jeżeli zdecydujemy się na
dodanie nowej kolumny do tabeli users, to będzie ona obecna w przypadku każdego
użytkownika, niezależnie czy to pole jest uzupełnione czy też nie.
Naturalnie też możemy określić tutaj typ danej kolumny, czyli np.
możemy doprecyzować czy chcemy przechowywać ciągi znaków czy np.
liczby lub też nawet obiekty Jameson.
Aczkolwiek w tym przypadku trzeba przyznać, że bazy danych SQL raczej nie
zostały zaprojektowane z myślą o obiektach Agile.
W każdym razie to co musisz wiedzieć na temat baz danych SQL to fakt, że są one
niczym innym jak specjalnymi tabelami, w ramach których masz zdefiniowane kolumny,
wiersze oraz dodatkowo różne ustawienia dotyczące poszczególnych kolumn.
Najważniejsze jest jednak to, że w związku
z tym, że mamy do czynienia z tabelą, siłą rzeczy zachowujemy tutaj z góry określoną
strukturę, w przypadku której nie ma znaczenia to, czy dany wiersz posiada
jakieś pole, czy też nie, ponieważ kolumna w jego przypadku jest obecna.
Jednym z ważniejszych elementów
projektowania baz danych jest to, w jaki sposób poukładane informacje, które mogą
znajdować się wewnątrz wielu różnych tabel.
Przykładowo, jeżeli wyobrazimy sobie, że użytkownicy mogą pisać artykuły,
to najlepszym sposobem ich przechowywania jest utworzenie nowej tabeli, wewnątrz
której będziemy przechowywać informacje na temat artykułów.
Ale jednocześnie jak widzisz, mamy tutaj kolumnę User ID, która wskazuje na
identyfikator konkretnego rekordu z tabeli Users.
Oznacza to, że w tym przypadku oba
artykuły zostały przypisane do Michała, więc w momencie, gdy np.
będziemy chcieli pobrać informacje o nim, możemy wykonać tzw.
join po to, aby pobrać również informacje na temat napisanych przez niego artykułów.
Jednocześnie, jak widzisz, ogromną rolę
odgrywają w tym całym procesie identyfikatory poszczególne ich wiersze.
Z tego powodu co prawda zdarzyło mi się spotykać tabele, które nie posiadały
kolumny ID, natomiast moim zdaniem unikanie tej kolumny jest złą praktyką i
też negatywnie wpływa na wydajność odczytu takich informacji.
W związku z tym taką ogólną zasadą, którą zawsze stosuję jest dodawanie tej kolumny
do każdej tabeli, niezależnie od tego jakie dane wewnątrz niej przechowuje.
Dzięki temu mam stosunkowo łatwo możliwość
powiązania ze sobą rekordów i utworzenia relacji pomiędzy tabelami.
No i teraz jak się pewnie domyślasz, takich relacji jest przynajmniej kilka
rodzajów i każdy z nich spełni swoje zadanie w nieco innym przypadku.
Jeżeli zastanawiasz się, dlaczego w ogóle musimy dzielić informacja
na różne tabele, to odpowiedzią na to pytanie jest tzw.
normalizacja.
Jest to proces organizowania informacji w
taki sposób, aby możliwie można było unikać duplikatów.
No bo przykładowo w przypadku artykułów
teoretycznie każdy artykuł należy do jednego użytkownika, ale jednocześnie
dodawanie takiego faktu w przypadku tabel jest stosunkowo trudne.
No bo tak naprawdę jedynym sposobem na to,
aby przechowywać wiele artykułów powiązanych z jednym użytkownikiem byłoby
to, aby przypisać do artykułu adres e-mail użytkownika, którego napisał.
Natomiast jeżeli wyobrazisz sobie nawet prostego bloga, to obok artykułu raczej
nie wyświetlamy adresu e-mail użytkownika, tylko na przykład jego imię i nazwisko.
W związku z tym również te informacje
musiałyby się znaleźć wewnątrz tabeli articles.
Na teraz wyobraź sobie podstronę, na
której chcielibyśmy wyświetlić artykuły, które napisał Michał.
Musielibyśmy przede wszystkim znać jego adres email do tego, aby móc pobrać tylko
te artykuły, w przypadku których został on przypisany.
Natomiast co się stanie w momencie, gdy
Michał zdecyduje się na zmianę swojego adresu email?
Czy to doprowadzi do sytuacji, w której wszystkie wcześniej napisane przez niego
artykuły przestaną być z nim powiązane, czy też np.
będziemy musieli napisać kod, który
zaktualizuje jego adres email we wszystkich artykułach?
A teraz wyobraź sobie, że oprócz artykułów mamy filmy i innego rodzaju treści.
I w związku z tym musimy dokonać tej aktualizacji i wewnątrz wszystkich tabel.
Coś takiego, nawet w teorii brzmi bardzo
skomplikowanie, a w przypadku praktyki jest jeszcze bardziej złożone.
W związku z tym w zamian stosujemy nic
innego jak referencję, czyli odniesienie do konkretnego rekordu.
W tym przypadku adres e-mail użytkownika zmieniamy tylko w jednym miejscu i to ma
zastosowanie do wszystkich powiązanych z nim rekordów.
Po prostu w momencie, gdy pobieramy informacje na temat użytkownika i
przypisanych do niego artykułów, nie posługujemy się danymi, które mogą się
zmienić, tylko stałymi identyfikatorami, które ewentualnie możemy ze sobą powiązać.
I teraz co do zasady całość.
Także w momencie, gdy zaprojektujemy sobie całą strukturę bazy i ewentualnie będziemy
ją rozszerzać, bądź też w niektórych sytuacjach modyfikować, to wchodzenie w
interakcje z tymi danymi dostępne jest poprzez język SQL.
W przypadku gdy piszemy polecenia opisujące to, jakie informacje z jakiej
tabeli chcemy pobrać i czy ewentualnie chcemy wykonywać tzw.
join, czyli po prostu łączyć informacje z
innych tabel na podstawie podanej reguły np.
pobierz informacje na temat użytkowników i połącz z wynikami informacje na temat
artykułów w sposób, który do każdego użytkownika przypisze tylko te artykuły,
które pasują identyfikatorem do jego identyfikatora.
W rezultacie otrzymujemy odpowiedź, którą
możemy przesłać do klienta, a następnie wyświetlić ją w interfejsie.
I teraz jeżeli zestawimy to z bazą SQL,
to tam zamiast tabel mamy do czynienia z kolekcjami, wewnątrz których mogą
znajdować się dokumenty, które w przypadku MongoDB są niczym innym jak obiektem
Jackson i z tego powodu MongoDB tak dobrze łączony jest z ekosystemem JavaScriptu.
Ze względu na to, że po prostu mówimy tutaj o tym samym nośniku danych.
Zatem mamy tutaj odzwierciedlone dokładnie takie same informacje jak w przypadku
pierwszego wiersza z tej tabeli, aczkolwiek istnieją tutaj pewne różnice.
Po pierwsze struktura identyfikatora jest
nieco bardziej złożona, ale w obu przypadkach identyfikatory te są
generowane automatycznie przez bazę danych w momencie, gdy dodajemy nowy rekord.
Dzięki temu nie musimy o to dbać, ale jednocześnie możemy z tego korzystać.
Następnie mamy tutaj poszczególne
informacje na temat użytkownika oraz powiązanych z nim artykułów.
Ciekawostką jest jednak to, że w związku z
tym, że nie jesteśmy tutaj ograniczeni w żaden sposób, strukturę tabeli, możemy
zrobić tak, że do tego dokumentu zostaną dopisane kolejne pola, które będą
wykorzystywane tylko w przypadku tego użytkownika.
Jednocześnie jeżeli na pewnym etapie dojdzie do sytuacji, w której inny
użytkownik również będzie potrzebował tych pól, to po prostu je dopiszemy.
I teraz weź pod uwagę fakt, że w momencie
gdy będziemy mieć kolekcję opisującą artykuły, to również sytuacja może
przypominać tutaj posiadanie drugiej tabeli.
Tym bardziej, że odwołujemy się tutaj do tych tabel poprzez identyfikatory.
Zauważ, że identyfikator, który mamy tutaj
wskazuje dokładnie na identyfikator artykułu znajdującego się w tym miejscu.
W związku z tym można tutaj pomyśleć, że mamy do czynienia w zasadzie z tym samym,
aczkolwiek tu mamy tabelę, a tu kolekcja, tu mamy wiersze, a tu dokumenty.
Jednak ta różnica polegająca na tym, że w
tym przypadku wykorzystujemy tabele, a w tym przypadku obiekty, jest zasadniczą
różnicą, która całkowicie zmienia zasady gry.
No bo przykładowo w związku z tym, że
tutaj nie mamy ściśle określonej struktury obiektu, to możemy tutaj dopisywać
informacje bezpośrednio w ramach tego obiektu, zamiast tworzyć dodatkową tabelę.
Przykładem jest mechanizm użytkownika.
Mianowicie zwykle w przypadku, gdy mamy do czynienia z tabelami, musimy utworzyć
oddzielną tabelę Rails, wewnątrz której przechowujemy nazwy pól, a następnie
tworzymy dodatkową tabelę Used Tools, wewnątrz której dokonujemy tak zwanej
relacji wiele do wielu i łączymy wiele różnych ról z wieloma użytkownikami.
W tym przypadku sytuacja jest zdecydowanie prostsza ze względu na to, że wystarczy
dopisać tablicę zawierającą identyfikatory poszczególnych ról.
I teraz pytanie czy nie moglibyśmy
odwzorować tego samego mechanizmu, który mieliśmy w przypadku tabel?
Odpowiedź brzmi oczywiście moglibyśmy, ale nie musimy.
I na tym polega właśnie różnica pomiędzy tymi dwoma rodzajami baz danych.
W jednym przypadku mamy ściśle określoną strukturę.
W drugim przypadku nie mamy żadnych zasad, którymi musimy podążać.
A to, w jaki sposób wyglądają nasze
dokumenty, zależy wyłącznie od potrzeb naszej aplikacji i tego, w jaki sposób
chcemy otrzymywać dostęp do tych informacji.
No bo przykładowo w tym przypadku mamy do
czynienia z tak zwanym budowaniem informacji.
Oznacza to, że wewnątrz jednego dokumentu po prostu osadzane dodatkowe dane.
Natomiast w przypadku artykułów mamy do
czynienia z pretensją, czyli odniesieniem się do innego dokumentu.
I teraz, jeżeli zastanawiasz się, kiedy wykorzystywać kto to jest sposób, no to
odpowiedź jest uzależniona od rodzaju przechowywanych danych.
Przede wszystkim, jeżeli chcesz mieć
bardzo łatwy dostęp do informacji powiązanych z danym dokumentem, to
zdecydowanie lepiej wykorzystać jest embedded.
Jeżeli jednak istnieje potrzeba sięgania
po konkretny dokument niezależnie, to znacznie lepiej jest utworzyć nową
kolekcję, wewnątrz której będziemy je przechowywać.
No bo przykładowo w naszej aplikacji raczej nie będzie potrzeby wyświetlenia
roli admina, ale jednocześnie będzie potrzeba wyświetlania pojedynczego
artykułu, niekoniecznie ze wszystkimi informacjami na temat użytkownika.
Prawda jest taka, że to w jaki sposób
będziemy organizować informacje i łączyć ze sobą dane zależy mocno od naszego
doświadczenia oraz aplikacji, którą rozwijamy.
W jednej z kolejnych lekcji pokażę Ci rodzaje połączeń.
W SQL, jak i nie SQL owej bazie danych i dzięki temu będziesz mieć niezbędne
minimum informacji do tego, aby zacząć projektować własne bazy.