diff --git a/órai anyagok/week02/api.pdf b/órai anyagok/week02/api.pdf new file mode 100644 index 0000000..f1f74ca Binary files /dev/null and b/órai anyagok/week02/api.pdf differ diff --git a/órai anyagok/week02/api.tex b/órai anyagok/week02/api.tex new file mode 100644 index 0000000..cf098fd --- /dev/null +++ b/órai anyagok/week02/api.tex @@ -0,0 +1,20 @@ +\documentclass[aspectratio=169]{beamer} +\usepackage{../common/webfejl} + +\title{Webtechnológia és webalkalmazás-fejlesztés} +\subtitle{2. hét -- REST API, Architekturális felépítések, CQRS} + +\begin{document} + +\begin{frame} +\titlepage +\logoalul +\end{frame} + +\input{sections/00-visszatekintes} +\input{sections/01-rest-api} +\input{sections/02-architektura} +\input{sections/03-cqrs} +\input{sections/04-kovetkezo-lepesek} + +\end{document} diff --git a/órai anyagok/week02/sections/00-visszatekintes.tex b/órai anyagok/week02/sections/00-visszatekintes.tex new file mode 100644 index 0000000..37a6fc6 --- /dev/null +++ b/órai anyagok/week02/sections/00-visszatekintes.tex @@ -0,0 +1,31 @@ +\section{Visszatekintés} + +\begin{frame}{Miről volt szó múlt héten?} +\footnotesize +Az első héten megismertük a webes kommunikáció alapköveit: a HTTP protokollt, a Node.js futtatókörnyezetet és az npm csomagkezelőt. Ezek nélkül nem tudnánk elindulni -- de önmagukban még nem elegendők egy jól használható backend rendszer megépítéséhez. + +\begin{itemize} +\item \textbf{HTTP/HTTPS:} Request-Response modell, állapotmentes protokoll, metódusok (GET, POST, PUT, PATCH, DELETE), státuszkódok +\item \textbf{Node.js:} szerveroldali JavaScript futtatókörnyezet, beépített \texttt{http} modul egy egyszerű szerver elindítására +\item \textbf{npm:} csomagkezelés, \texttt{package.json}, függőségek +\end{itemize} + +\begin{block}{A hiányzó darab} +Múlt héten a \texttt{http.createServer}-rel csak egyetlen, mindent kiszolgáló függvényt írtunk. Éles alkalmazásoknál ez gyorsan kezelhetetlenné válik -- szükségünk van egy \emph{tervezési logikára}, ami megmondja, hogyan szervezzük az útvonalainkat, adatainkat és a kódunk rétegeit. +\end{block} +\end{frame} + +\begin{frame}{Mi a célja a mai órának?} +\footnotesize +A mai anyag három, egymásra épülő témát dolgoz fel: hogyan tervezzünk jól használható API-kat, hogyan szervezzük a backend kódunkat rétegekbe, és hogyan válasszuk szét az írási és olvasási műveleteket, ha a rendszerünk ezt megkívánja. + +\begin{itemize} +\item \textbf{REST API alapok} -- hogyan tervezzünk következetes, könnyen használható API-t +\item \textbf{Architekturális felépítések} -- hogyan szervezzük a backend kódunkat rétegekbe, hogy karbantartható maradjon +\item \textbf{CQRS} -- mikor éri meg szétválasztani az írási és olvasási műveleteket +\end{itemize} + +\begin{alertblock}{Fontos} +A mai témák még mindig \emph{tervezési} kérdések -- konkrét kódot Express.js-ben csak a jövő héttől írunk. Most a "miért így?" kérdésre keressük a választ, hogy a következő heti kód már értelmes döntéseken alapuljon. +\end{alertblock} +\end{frame} diff --git a/órai anyagok/week02/sections/01-rest-api.tex b/órai anyagok/week02/sections/01-rest-api.tex new file mode 100644 index 0000000..8dfb994 --- /dev/null +++ b/órai anyagok/week02/sections/01-rest-api.tex @@ -0,0 +1,138 @@ +\section{REST API alapok} + +\begin{frame}{Mi az API?} +\footnotesize +Az \textbf{API} (Application Programming Interface) egy megállapodás arról, hogyan kommunikálhat egymással két szoftverkomponens -- anélkül, hogy az egyiknek ismernie kellene a másik belső működését. Amikor a telefonodon megnyitod egy időjárás-alkalmazást, az alkalmazás egy API-n keresztül kér adatot egy távoli szervertől; neked (és az alkalmazásnak) fogalma sincs, hogyan tárolja a szerver az adatokat belül -- csak azt kell tudnia, milyen kérést küldjön, és milyen választ várhat. + +\begin{itemize} +\item Egyértelmű, dokumentált "szerződés" a kliens és a szerver között +\item Elrejti a belső implementációs részleteket (adatbázis típusa, kód szerkezete, stb.) +\item Web API-k esetén jellemzően HTTP felett kommunikálunk -- ez az, amit az elmúlt órán megismertünk +\end{itemize} + +\begin{block}{REST -- egy konkrét API-stílus} +A \textbf{REST} (Representational State Transfer) nem egy protokoll vagy szabvány, hanem egy architekturális stílus, amit Roy Fielding írt le 2000-ben a doktori disszertációjában. Ma a legelterjedtebb módja a web API-k tervezésének. +\end{block} +\end{frame} + +\begin{frame}{Mitől "RESTful" egy API?} +\footnotesize +Fielding öt fő elvet fogalmazott meg, amiknek egy API-nak meg kell felelnie ahhoz, hogy igazán RESTfulnek nevezzük. A gyakorlatban a legtöbb "REST API"-nak nevezett rendszer csak részben követi ezeket -- de minél többet betartunk belőlük, annál kiszámíthatóbb és skálázhatóbb lesz az API-nk. + +\begin{itemize} +\item \textbf{Kliens-szerver:} a kliens és a szerver különálló felelősséggel bír, egymástól függetlenül fejleszthetők +\item \textbf{Állapotmentesség (statelessness):} minden kérés önmagában tartalmaz minden szükséges információt -- ezt már az 1. héten megismertük a HTTP-nél +\item \textbf{Cache-elhetőség:} a válaszoknak jelezniük kell, hogy gyorsítótárazhatók-e (pl. \texttt{Cache-Control} header) +\item \textbf{Egységes interfész (uniform interface):} az erőforrásokat egységes módon, azonosítható URL-eken keresztül érjük el +\item \textbf{Rétegzett rendszer:} a kliens nem tudja (és nem is kell tudnia), hogy közvetlenül a szerverrel, vagy egy köztes rétegen (pl. load balancer, cache) keresztül kommunikál-e +\end{itemize} +\end{frame} + +\begin{frame}[fragile]{Erőforrás-orientált URL tervezés} +\footnotesize +Az URL-ek \emph{erőforrásokat} (főneveket) azonosítsanak, ne \emph{műveleteket} (igéket) -- a műveletet úgyis a HTTP metódus fejezi ki. + +\begin{block}{Rossz gyakorlat (igealapú URL)} +\begin{verbatim} +GET /getAllUsers +POST /createNewUser +POST /deleteUser?id=123 +\end{verbatim} +\end{block} + +\begin{block}{Jó gyakorlat (erőforrás-alapú, többes szám)} +\begin{verbatim} +GET /users # osszes felhasznalo +POST /users # uj felhasznalo letrehozasa +GET /users/123 # egy adott felhasznalo +DELETE /users/123 # felhasznalo torlese +\end{verbatim} +\end{block} +\end{frame} + +\begin{frame}{CRUD $\to$ HTTP metódus megfeleltetés} +\footnotesize +Ez a táblázat gyakorlatilag a REST API tervezés "alaptörvénye" -- ha ezt következetesen betartod, az API-d azonnal ismerős és kiszámítható lesz bárki számára, aki már használt REST API-t. + +\begin{tabular}{|l|l|l|} +\hline +\textbf{Művelet} & \textbf{HTTP metódus} & \textbf{Végpont példa} \\ +\hline +Create (létrehozás) & POST & \texttt{POST /users} \\ +Read (egy elem) & GET & \texttt{GET /users/123} \\ +Read (lista) & GET & \texttt{GET /users} \\ +Update (teljes) & PUT & \texttt{PUT /users/123} \\ +Update (részleges) & PATCH & \texttt{PATCH /users/123} \\ +Delete (törlés) & DELETE & \texttt{DELETE /users/123} \\ +\hline +\end{tabular} + +\begin{block}{Emlékeztető az 1. hétről} +GET, PUT, DELETE idempotensek -- többszöri hívás ugyanazt az állapotot eredményezi. A POST nem az. +\end{block} +\end{frame} + +\begin{frame}{Richardson Maturity Model} +\footnotesize +Leonard Richardson egy szintekre bontott modellt alkotott, amivel megmérhető, mennyire "RESTful" valójában egy API. A legtöbb valós API a 2. szinten áll -- ez teljesen elfogadható, a 3. szint (HATEOAS) ritkán éri meg a többletbonyolultságot. + +\begin{itemize} +\item \textbf{0. szint:} egyetlen végpont, minden művelet ugyanazon keresztül megy (pl. RPC-szerű, SOAP-hoz hasonló stílus) +\item \textbf{1. szint:} külön erőforrások, saját URL-lel, de a HTTP metódusokat még nem használjuk következetesen +\item \textbf{2. szint:} erőforrások + helyesen használt HTTP metódusok és státuszkódok -- \emph{ez a gyakorlatban elterjedt "REST API" szint} +\item \textbf{3. szint (HATEOAS):} a válasz linkeket is tartalmaz a kapcsolódó műveletekhez, így a kliensnek nem kell előre tudnia az összes URL-t +\end{itemize} +\end{frame} + +\begin{frame}[fragile]{API verziózás} +\footnotesize +Az API-k idővel változnak -- új mezők, módosított viselkedés. Ha egy változás nem visszafelé kompatibilis, szükség van egy módra, hogy a régi klienseket ne törjük el. Erre szolgál a verziózás. + +\begin{block}{URL-alapú verziózás (leggyakoribb)} +\begin{verbatim} +GET /api/v1/users/123 +GET /api/v2/users/123 +\end{verbatim} +Egyszerű, jól látható, könnyen tesztelhető Postmanben is. +\end{block} + +\begin{block}{Header-alapú verziózás} +\begin{verbatim} +GET /api/users/123 +Accept: application/vnd.myapp.v2+json +\end{verbatim} +"Tisztább" URL-eket eredményez, de nehezebb böngészőből tesztelni. +\end{block} +\end{frame} + +\begin{frame}[fragile]{Lapozás, szűrés, rendezés} +\footnotesize +Amikor egy erőforrásból (pl. felhasználók) több ezer is lehet, nem küldhetjük vissza mindet egyszerre -- ezt oldják meg a query paraméterek, amikkel a kliens finomíthatja, pontosan mit szeretne kapni. + +\begin{verbatim} +GET /users?page=2&limit=20 +GET /users?role=admin +GET /users?sort=-createdAt +GET /users?search=alice +\end{verbatim} + +\begin{itemize} +\item \textbf{Lapozás (pagination):} \texttt{page}/\texttt{limit} vagy \texttt{offset}/\texttt{limit} párokkal +\item \textbf{Szűrés (filtering):} egy adott mező szerinti szűkítés (\texttt{role=admin}) +\item \textbf{Rendezés (sorting):} \texttt{sort=mezonev}, mínusz előjellel csökkenő sorrend +\end{itemize} +\end{frame} + +\begin{frame}{Összefoglalás -- REST API} +\footnotesize +\begin{block}{REST API tervezés} +\begin{itemize} +\item API: szerződés két rendszer kommunikációjához; REST: egy elterjedt architekturális stílus rá +\item Fielding elvei: kliens-szerver, statelessness, cache-elhetőség, egységes interfész, rétegzettség +\item URL-ek: erőforrások (főnevek, többes szám), nem műveletek (igék) +\item CRUD $\to$ HTTP metódus: POST/GET/PUT/PATCH/DELETE következetesen +\item Richardson Maturity Model: a legtöbb API a 2. szinten van, ez rendben van +\item Verziózás: URL vagy header alapon; lapozás/szűrés/rendezés: query paraméterekkel +\end{itemize} +\end{block} +\end{frame} diff --git a/órai anyagok/week02/sections/02-architektura.tex b/órai anyagok/week02/sections/02-architektura.tex new file mode 100644 index 0000000..d13e009 --- /dev/null +++ b/órai anyagok/week02/sections/02-architektura.tex @@ -0,0 +1,125 @@ +\section{Architekturális felépítések} + +\begin{frame}{Mi a szoftverarchitektúra, és miért számít?} +\footnotesize +A szoftverarchitektúra azt írja le, hogyan van a kódunk nagy egységekre (rétegekre, modulokra, szolgáltatásokra) felosztva, és ezek hogyan kommunikálnak egymással. Egy kis, egyszemélyes prototípusnál szinte mindegy, hova írjuk a kódot -- de amint a projekt nő, csapatban dolgozunk rajta, vagy hónapok múlva kell hozzányúlni, a jó architektúra dönti el, hogy karbantartható marad-e a rendszer, vagy "spagettikóddá" válik. + +\begin{itemize} +\item Könnyebb megérteni: világos, hogy melyik kód mit csinál, és hol keresendő egy adott logika +\item Könnyebb tesztelni: a rétegek külön-külön, elszigetelten tesztelhetők +\item Könnyebb bővíteni: új funkció hozzáadásakor tudjuk, hova illesztjük be +\item Könnyebb csapatban dolgozni: a felelősségek szét vannak választva +\end{itemize} +\end{frame} + +\begin{frame}{Rétegzett architektúra -- az öt réteg (1/2)} +\footnotesize +A rétegzett felépítésnél a kódot vízszintes rétegekbe szervezzük, ahol minden réteg csak a közvetlenül alatta lévővel kommunikál. Ezen a tárgyon a következő öt réteges felosztást fogjuk következetesen használni -- elsőként a "felső" három réteg: + +\begin{block}{} +\begin{itemize} +\item \textbf{API / Controller:} fogadja a HTTP kéréseket, validálja a bemenetet, meghívja az Application réteget, visszaadja a választ -- ezt Express.js-ben írjuk meg a jövő héten +\item \textbf{Application:} az egyes use case-eket (parancsokat/lekérdezéseket) orchesztrálja -- ide kerülnek majd a CQRS command/query handlerek +\item \textbf{Domain:} a tiszta üzleti logika, entitások, aggregates -- semmilyen technikai függősége nincs, nem "tudja", hogy Express-ben vagy adatbázissal fut +\end{itemize} +\end{block} +\end{frame} + +\begin{frame}{Rétegzett architektúra -- az öt réteg (2/2)} +\footnotesize +A maradék két réteg a rendszer "peremén" helyezkedik el: az egyik a kifelé irányuló adatszerződéseket, a másik a technikai megvalósítást fogja össze. + +\begin{block}{} +\begin{itemize} +\item \textbf{Communication:} a rétegek/külső rendszerek közti szerződések -- DTO-k, mapperek (6. hét) +\item \textbf{Infrastructure:} a konkrét technikai megvalósítás -- adatbázis-kapcsolat, külső szolgáltatások +\end{itemize} +\end{block} + +\begin{alertblock}{Miért éri meg?} +Ha lecseréljük az adatbázisunkat, csak az Infrastructure réteget kell módosítani -- a Domain és az API réteg változatlan marad. +\end{alertblock} +\end{frame} + +\begin{frame}{MVC minta} +\footnotesize +Az MVC (Model-View-Controller) a rétegzett architektúra egyik legismertebb konkrét megvalósítása, eredetileg felhasználói felületekhez, de a backend világban is elterjedt elnevezés lett a hasonló felosztásra. + +\begin{itemize} +\item \textbf{Model:} az adatokat és az azokhoz tartozó szabályokat képviseli (nálunk: a Domain + Infrastructure réteg) +\item \textbf{View:} a megjelenítés -- backend API-nál ez jellemzően a JSON válasz formázása +\item \textbf{Controller:} fogadja a bejövő kérést, meghívja a megfelelő Model-műveletet, és visszaküldi a View-t +\end{itemize} + +\begin{block}{Backend kontextusban} +Amikor a jövő héten Express.js-ben "route handler"-t írunk, az gyakorlatilag az API/Controller réteg szerepét tölti be: fogadja a HTTP kérést, és delegálja a munkát az Application rétegnek. +\end{block} +\end{frame} + +\begin{frame}{Monolit vs mikroszolgáltatás} +\footnotesize +Ez a döntés arról szól, hogy a teljes backend rendszerünket egyetlen, összefüggő alkalmazásként (monolit), vagy sok, önállóan futtatható kis szolgáltatásra bontva (mikroszolgáltatások) építjük-e fel. Egyik sem "jobb" alapból -- a projekt méretétől és a csapat helyzetétől függ. + +\begin{columns} +\begin{column}{0.48\textwidth} +\begin{block}{Monolit} +\begin{itemize} +\item Egyetlen kódbázis, egyetlen futó folyamat +\item Egyszerűbb fejleszteni és deployolni kisebb csapatban +\item Egyszerűbb tranzakciókezelés +\end{itemize} +\end{block} +\end{column} +\begin{column}{0.48\textwidth} +\begin{block}{Mikroszolgáltatások} +\begin{itemize} +\item Sok kis, önálló szolgáltatás, saját adatbázissal +\item Külön-külön skálázhatók és deployolhatók +\item Nagyobb komplexitás: hálózati kommunikáció, elosztott tranzakciók +\end{itemize} +\end{block} +\end{column} +\end{columns} + +\begin{alertblock}{Gyakorlati tanács} +Kezdj monolittal! A tárgy során épített API is monolit lesz -- a mikroszolgáltatásokra való szétbontás egy már működő, jól rétegzett monolitból sokkal könnyebb, mint elölről tervezni. +\end{alertblock} +\end{frame} + +\begin{frame}{Separation of Concerns} +\footnotesize +A "Separation of Concerns" (felelősségek szétválasztása) az az elv, ami az összes eddigi mintát (rétegzés, MVC) megalapozza: minden kódegységnek egyetlen, jól körülhatárolt felelőssége legyen. + +\begin{itemize} +\item Egy függvény/osztály ne csinálja egyszerre a HTTP kérés kezelését \emph{és} az adatbázis-lekérdezést \emph{és} az email küldést +\item Ha egy dolog megváltozik (pl. az adatbázis lekérdezésének módja), az csak egy helyen igényeljen módosítást +\item Könnyebb egyesével, elszigetelten tesztelni az egyes felelősségeket +\end{itemize} + +\begin{block}{Ökölszabály} +Ha egy függvény nevét csak "és"-sel tudod leírni (pl. "validál ÉS ment ÉS emailt küld"), valószínűleg érdemes szétbontani. +\end{block} +\end{frame} + +\begin{frame}{Kitekintés -- mi jön még ebben a témában} +\footnotesize +A rétegzett architektúra és a Separation of Concerns elve két fogalmat is megalapoz, amikkel a félév további részében részletesen foglalkozunk majd -- most csak annyit érdemes megjegyezni, hogy hova illeszkednek. + +\begin{itemize} +\item \textbf{Repositories és Aggregates (5. hét):} az Infrastructure réteg formalizált, ORM-alapú megvalósítása -- a repository "elrejti" az adatbázis-lekérdezéseket egy egyszerű interfész mögé +\item \textbf{Dependency Injection (11. hét):} technika arra, hogy a rétegek közötti függéseket (pl. "a controllernek szüksége van a service-re") ne kézzel drótozzuk be, hanem egy keretrendszer intézze +\end{itemize} +\end{frame} + +\begin{frame}{Összefoglalás -- Architekturális felépítések} +\footnotesize +\begin{block}{Architektúra} +\begin{itemize} +\item A jó architektúra karbantarthatóvá, tesztelhetővé és bővíthetővé teszi a rendszert +\item Rétegzett architektúra (öt réteg): API/Controller -- Application -- Domain -- Communication -- Infrastructure +\item MVC: Model-View-Controller -- a Controller felel meg a jövő heti Express.js route handlernek +\item Monolit vs mikroszolgáltatás: kezdj monolittal, bontsd szét később, ha indokolt +\item Separation of Concerns: minden kódegységnek egy jól körülhatárolt felelőssége legyen +\end{itemize} +\end{block} +\end{frame} diff --git a/órai anyagok/week02/sections/03-cqrs.tex b/órai anyagok/week02/sections/03-cqrs.tex new file mode 100644 index 0000000..9a7f585 --- /dev/null +++ b/órai anyagok/week02/sections/03-cqrs.tex @@ -0,0 +1,115 @@ +\section{CQRS} + +\begin{frame}{A probléma: egy modell, két teljesen más terhelés} +\footnotesize +A legtöbb egyszerű alkalmazásban ugyanaz a kód, ugyanaz az adatmodell szolgálja ki mind az adatok módosítását (írás), mind a lekérdezését (olvasás). Ez sokáig teljesen jól működik -- de bizonyos rendszereknél ez a közös modell egyre inkább korlátozó tényezővé válik. + +\begin{itemize} +\item Az írási műveleteknél fontos a szigorú validáció és az üzleti szabályok betartatása +\item Az olvasási műveleteknél viszont gyakran \emph{más} adatszerkezet lenne ideális (pl. több táblából összefésült, "lapos" nézet egy listázó felülethez) +\item Ha ugyanaz a modell szolgál ki mindkét célt, gyakran kompromisszumot kell kötni -- egyik oldal sem lesz igazán optimális +\end{itemize} + +\begin{block}{Példa} +Egy webshopnál a rendelés \emph{leadása} (írás) sok validációt igényel (készlet, fizetés, kedvezmények), míg a rendelések \emph{listázása} (olvasás) egyszerűen csak gyors, jól szűrhető megjelenítést igényel -- a kettő igénye nagyon eltérő. +\end{block} +\end{frame} + +\begin{frame}{A CQRS lényege} +\footnotesize +A \textbf{CQRS} (Command Query Responsibility Segregation, magyarul "parancs-lekérdezés felelősség szétválasztás") azt mondja ki: válasszuk szét élesen az írási (command) és olvasási (query) műveleteket -- akár külön modellel, külön kóddal, szélsőséges esetben külön adatbázissal is. + +\begin{itemize} +\item \textbf{Command (parancs):} egy szándékot fejez ki valaminek a megváltoztatására (pl. "hozz létre egy rendelést") -- nem ad vissza adatot, legfeljebb egy azonosítót vagy sikerességet +\item \textbf{Query (lekérdezés):} adatot kér le, \emph{nem} változtat semmin -- ez pontosan megfelel a HTTP GET idempotens, csak-olvasó jellegének, amit már az 1. héten megismertünk +\end{itemize} + +\begin{alertblock}{Fontos megkülönböztetés} +A CQRS nem ugyanaz, mint a HTTP metódusok GET/POST felosztása -- az egy protokollszintű konvenció, a CQRS pedig egy \emph{architekturális döntés} arról, hogy a kódunk belső szerkezete is kövesse ezt a felosztást. +\end{alertblock} +\end{frame} + +\begin{frame}[fragile]{Command és Query -- egyszerű példa} +\footnotesize +A lényeg pszeudokódban jól látszik: a Command egy műveletet hajt végre és validál, a Query csak lekérdez -- a kettő felelőssége, sőt akár a visszatérési típusa is más. + +\begin{columns} +\begin{column}{0.48\textwidth} +\begin{block}{Command -- írás} +\begin{lstlisting}[language=JavaScript,style=NodeJS] +function createOrder(data) { + validate(data); + checkStock(data.items); + const order = save(data); + return order.id; +} +\end{lstlisting} +\end{block} +\end{column} +\begin{column}{0.48\textwidth} +\begin{block}{Query -- olvasás} +\begin{lstlisting}[language=JavaScript,style=NodeJS] +function getOrderById(id) { + return db + .orders + .findOne({ id }); +} +\end{lstlisting} +\end{block} +\end{column} +\end{columns} + +\begin{block}{Mi változik igazán CQRS-sel?} +Nem feltétlenül a fájlok fizikai elválasztása a lényeg, hanem az, hogy a Command sosem ad vissza lekérdezési adatot, és a Query sosem módosít állapotot -- ez a szigorú szétválasztás teszi átláthatóvá a rendszert. +\end{block} +\end{frame} + +\begin{frame}{Miért éri meg a CQRS-t bevezetni?} +\footnotesize +A szétválasztás nem öncélú bonyolítás -- konkrét, mérhető előnyöket ad olyan rendszereknél, ahol az írási és olvasási terhelés jelentősen eltér egymástól. + +\begin{itemize} +\item \textbf{Független skálázhatóság:} ha egy rendszerben sokkal több az olvasás, mint az írás (ez a leggyakoribb eset), az olvasási oldalt külön lehet skálázni +\item \textbf{Optimalizált olvasási modellek:} a lekérdező oldalon szabadon kialakíthatunk a megjelenítéshez ideális, denormalizált nézeteket, anélkül hogy az írási oldal adatmodelljét kompromisszumba kényszerítenénk +\item \textbf{Egyszerűbb, célzottabb kód:} egy Command csak a validációra és a módosításra koncentrál, egy Query csak a lekérdezésre -- egyik sem próbál "mindent tudni" +\end{itemize} +\end{frame} + +\begin{frame}{Mikor túlzás a CQRS?} +\footnotesize +A CQRS egy erős eszköz, de nem ingyen jön -- minden architekturális mintánál fontos feltenni a kérdést: \emph{a probléma, amit megold, valóban jelen van-e nálunk?} + +\begin{alertblock}{Ökölszabály} +Egyszerű CRUD alkalmazásoknál (ahol az írás és olvasás igénye hasonló, és nincs komoly skálázási probléma) a CQRS csak felesleges réteget és bonyolultságot ad hozzá -- ilyenkor egy egyszerű, közös modell teljesen megfelelő. +\end{alertblock} + +\begin{itemize} +\item Kis csapatnál, kis projektnél a többletkód karbantartása nem éri meg a hasznot +\item Csak akkor vezessük be, ha ténylegesen tapasztaljuk a "két különböző igény" problémáját +\item A tárgy hátralévő részében épített API-nk egyszerű CRUD marad -- a CQRS itt főleg mint \emph{fogalom} és \emph{gondolkodásmód} fontos +\end{itemize} +\end{frame} + +\begin{frame}{Kitekintés: Event Sourcing} +\footnotesize +A CQRS-t gyakran együtt említik egy másik mintával, az \textbf{Event Sourcing}-gal, bár a kettő nem jár automatikusan együtt. + +\begin{block}{Az alapötlet} +Ahelyett, hogy csak az adat \emph{jelenlegi állapotát} tárolnánk, minden változást (eseményt) elmentünk -- pl. "OrderCreated", "OrderPaid", "OrderShipped". A jelenlegi állapotot ezekből az eseményekből lehet bármikor újraszámolni. +\end{block} + +Ez a tárgy keretein túlmutat, de érdemes tudni, hogy létezik: teljes körű auditnaplót ad ingyen, és jól illeszkedik a CQRS command-oldalához. Ára viszont jelentős többletkomplexitás. +\end{frame} + +\begin{frame}{Összefoglalás -- CQRS} +\footnotesize +\begin{block}{CQRS} +\begin{itemize} +\item A probléma: egy közös modell néha rosszul szolgálja ki mind az írást, mind az olvasást +\item CQRS: Command (írás, nem ad vissza adatot) és Query (olvasás, nem módosít) szigorú szétválasztása +\item Előny: független skálázhatóság, optimalizált olvasási modellek, egyszerűbb, célzottabb kód +\item Csapda: egyszerű CRUD alkalmazásoknál felesleges többletkomplexitás +\item Kapcsolódó fogalom: Event Sourcing (események tárolása állapot helyett) -- ez már a tárgy keretein túlmutat +\end{itemize} +\end{block} +\end{frame} diff --git a/órai anyagok/week02/sections/04-kovetkezo-lepesek.tex b/órai anyagok/week02/sections/04-kovetkezo-lepesek.tex new file mode 100644 index 0000000..4a1468f --- /dev/null +++ b/órai anyagok/week02/sections/04-kovetkezo-lepesek.tex @@ -0,0 +1,17 @@ +\section{Következő lépések} + +\begin{frame}{Következő lépések} +\footnotesize +Ma megismertük, hogyan tervezzünk jól használható REST API-t, hogyan szervezzük a backend kódunkat rétegekbe, és mikor érdemes szétválasztani az írási és olvasási műveleteket. A jövő héten ezekre a tervezési elvekre már konkrét kódot építünk. + +\begin{enumerate} +\item \textbf{Express.js megismerése} -- a jövő heti keretrendszer, amivel az API/Controller réteget ténylegesen megírjuk +\item \textbf{Routing gyakorlása} -- a mai órán tervezett erőforrás-orientált URL-eket Express.js route handlerekként fogjuk implementálni +\item \textbf{Postman telepítése} -- API-k manuális teszteléséhez, hogy a saját végpontjainkat is ki tudjuk próbálni +\item \textbf{TypeScript alapok} -- a jövő héttől fokozatosan áttérünk típusos JavaScriptre +\end{enumerate} + +\begin{alertblock}{Javaslat} +Nézd át még egyszer a CRUD $\to$ HTTP metódus táblázatot -- a jövő héten ezt fogjuk közvetlenül route definíciókra fordítani. +\end{alertblock} +\end{frame}