• Nebyly nalezeny žádné výsledky

Hlavní práce74813_hrus03.pdf, 1 MB Stáhnout

N/A
N/A
Protected

Academic year: 2022

Podíl "Hlavní práce74813_hrus03.pdf, 1 MB Stáhnout"

Copied!
55
0
0

Načítání.... (zobrazit plný text nyní)

Fulltext

(1)

Vysoká škola ekonomická v Praze

Fakulta informatiky a statistiky

Implementace datové vrstvy frontendové aplikace Adgame a komunikace

s backendem

BAKALÁŘSKÁ PRÁCE

Studijní program: Aplikovaná informatika Studijní obor: Aplikovaná informatika

Autor: Šimon Hrubý

Vedoucí bakalářské práce: Ing. Filip Vencovský, Ph.D.

Praha, květen 2021

(2)

Poděkování

Tímto bych rád poděkoval svému vedoucímu bakalářské práce Ing. Filipu Vencovskému, Ph.D., za příležitost podílet se na tak zajímavém projektu, jakým je Adgame. Taktéž bych mu rád poděkoval za jeho cennou zpětnou vazbu k této práci a jeho čas.

(3)

Abstrakt

Tématem této bakalářské práce je implementace datové vrstvy a komunikace s backendovou částí frontendové aplikace Adgame. Cílem bylo vyvinout požadovanou funkčnost celé aplikace a v rámci toho najít vhodné technologie a přístupy pro tento proces.

Práce představuje technologie a přístupy nejprve teoreticky a poté je v části implementace uvádí do praxe.

Výsledkem této práce je hotová implementace, díky které je hru Adgame možno hrát a využívat ji například při výuce. Testování řešení probíhalo mnou, v rámci dvou dalších bakalářských prací a validace poté proběhla i v rámci reálně odehraných her.

Klíčová slova

Adgame, webová aplikace, frontend, Vue.js, Vuex, datová vrstva, datová komunikace

(4)

Abstract

The topic of this bachelor thesis is the implementation of the data layer and

communication with the backend part of the frontend application Adgame. The goal was to develop the required functionality of the entire application and to find suitable

technologies and approaches for this process. The work presents technologies and

approaches first theoretically and then puts them into practice in the implementation part

The result of this work is an implementation, thanks to which the game Adgame can be played and used, for example in teaching. The solution was tested by me, within two other bachelor’s theses and through the real gameplay during the school lesson.

Keywords

Adgame, web application, frontend, Vue.js, Vuex, data layer, data communication

(5)

Obsah

Úvod ... II 1. Moderní webové aplikace ... III 1.1. Způsoby interakce frontendu a backendu ... III 1.1.1. Aplikace renderované na serveru (tradiční přístup) ... III 1.1.2. Aplikace renderované na klientské části ... IV 1.2. Samostatná frontendová aplikace... IV 1.2.1. Vytváření HTTP požadavků ... V 2. Vue.js ... VI 2.1. Znovupoužitelné komponenty ... VI 2.2. Virtuální DOM ... X 3. Datová vrstva ... XI 3.1. Správa dat pomocí lokální datové vrstvy ... XII 3.2. Vlastní řešení centralizované datové vrstvy ... XIII 3.3. Vuex ... XIV 3.3.1. Koncept Vuexu ... XIV 4. Obousměrná komunikace ... XVI 5. Webová aplikace Adgame ... XVII 5.1. Koncept hry Adgame ... XVII 5.2. Náležitosti frontendové části Adgame ... XVIII 5.3. Z pohledu uživatele jako hráče ...XIX 5.3.1. Seznam her a lobby ...XIX 5.3.2. Hra ... XX 5.3.3. Správa produktů ...XXI 5.3.4. Správa kampaní ... XXII 5.3.5. Nákup herních dat ... XXIII 5.3.6. Průběh herních kol ... XXIII 5.3.7. Týmová spolupráce ... XXIII 5.4. Z pohledu uživatele jako administrátora ... XXIV 6. Akademické práce zabývající se podobnou problematikou ...XXV 6.1. Software pro agregaci vzdělávacích akcí (Bc. Jakub Voráček, 2020) ...XXV 6.2. Problémy implementace platformy využívající sdílenou ekonomiku (Ing. Josef Doškář, 2019) ...XXV 6.3. Testování UX pro výukový simulátor AdGame ( Bc. Michael Veis, 2021)...XXV

(6)

6.4. Automatizované testování frontendu webové aplikace Adgame (Bc. Dominik Renč, 2020) XXVI

7. Implementace datové vrstvy a komunikace s backendovou částí ... XXVII 7.1. Frontendové rozhraní pro komunikaci s REST API ... XXVII 7.2. Implementace datové vrstvy v podobě Vuex ... XXIX 7.3. Implementace oboustranné komunikace ... XXXI 7.4. Implementace dat a komunikace v rámci komponent ... XXXIII 7.4.1. Základní způsob implementace ... XXXIII 7.4.2. Řešené problémy ... XXXV 7.5. Moduly datové vrstvy ... XXXVII 7.5.1. Uživatelský účet (UserAccount) ... XXXVII 7.5.2. Autentizace (Auth)... XXXVIII 7.5.3. Lobby hry (GameLobby) ... XXXVIII 7.5.4. Hra (Game) ... XXXVIII 7.5.5. Tým (Team) ... XXXIX 7.5.6. Produkt (Product)... XXXIX 7.5.7. Kampaně (Campaign)... XLII 7.5.8. Data hry (GameData) ... XLIII 7.5.9. Data ... XLIII 7.5.10. Vlastník hry (GameOwner) ... XLIII 7.5.11. Indikátor načítání (Loader) ... XLIII 8. Diskuze výsledku ... XLV Závěr ... XLVII Použitá literatura ... XLVIII

(7)

I

Seznam výpisů programového kódu

Výpis 1 Příklad prázdné Vue.js komponenty (vlastní zpracování) ... VI Výpis 2 Příklad šablony komponenty počítadla (vlastní zpracování) ... VII Výpis 3 Příklad stylu komponenty počítadla (vlastní zpracování) ... VII Výpis 4 Příklad struktury logické části komponenty ve Vue.js (vlastní zpracování) ... VIII Výpis 5 Příklad „props“ komponenty počítadla (vlastní zpracování) ... VIII Výpis 6 Příklad "data" komponenty počítadla (vlastní zpracování) ... VIII Výpis 7 - Příklad "methods" komponenty počítadla (vlastní zpracování) ... VIII Výpis 8 Příklad "computed" komponenty počítadla (vlastní zpracování) ... X Výpis 9 Příklad zaregistrování a výpisu komponenty počítadla (vlastní zpracování) ... X Výpis 10 Příklad struktury Vuex store (vlastní zpracování) ... XIV Výpis 11 Příklad stavu dat počítadla ve Vuex (vlastní zpracování) ... XV Výpis 12 Příklad getterů počítadla ve Vuex (vlastní zpracování) ... XV Výpis 13 Příklad mutací počítadla ve Vuex (vlastní zpracování) ... XV Výpis 14 Příklad akcí počítadla ve Vuex (vlastní zpracování) ... XV Výpis 15 Ukázka kódu api rozhraní pro získání týmových produktů (vlastní zpracování) ... XXVIII Výpis 16 Zjednodušená ukázka kódu importování a exportování API modulů (vlastní zpracování) ... XXVIII Výpis 17 Ukázka kódu funkce vyčkání na socketové spojení (vlastní zpracování) ... XXXII Výpis 18 Ukázka kódu funkce pro zpracování socketové zprávy (vlastní zpracování) XXXIII Výpis 19 Ukázka kódu pro demonstraci využití Vuex getteru (vlastní zpracování) .... XXXIV Výpis 20 Ukázka kódu pro demonstraci využití "mapGetters" z Vuexu (vlastní zpracování) ... XXXIV Výpis 21 Ukázka kódu zavolání akce na Vuex store (vlastní zpracování) ... XXXIV Výpis 22 Ukázka kódu zavolání akce s využitím "mapActions" z Vuexu (vlastní zpracování) ... XXXIV Výpis 23 Ukázka kódu stavu dat Vuex modulu produktu (vlastní zpracování) ... XXXIX Výpis 24 Ukázka kódu akce Vuex modulu produktu (vlastní zpracování) ... XL Výpis 25 Ukázka kódu API rozhraní pro získání týmových produktů ... XL Výpis 26 Ukázka kódu mutace pro nastavení produktů Vuex modulu produktu (vlastní zpracování) ... XL Výpis 27 Ukázka kódu získání dat pomocí getterů z Vuex modulu produktu (vlastní zpracování) ... XLI Výpis 28 Ukázka kódu využití dat z logiky v šabloně ve výpisu produktů (vlastní zpracování) ... XLI Výpis 29 Ukázka kódu zpracování socketové zprávy ve Vuex modulu produktu (vlastní zpracování) ... XLI Výpis 30 Ukázka kódu pro hlídání změny produktu jiným hráčem v logiky komponenty (vlastní zpracování) ... XLI Výpis 31 Příklad ideálních dat kampaní (vlastní zpracování) ... XLII Výpis 32 Příklad skutečných dat kampaní (vlastní zpracování) ... XLIII

(8)

Úvod

Doba, kdy webové aplikace byly čistě statické, což znamená, že veškerá data byla uložena v rámci kódu frontendové aplikace, již je dávno pryč. Data jsou v dnešní době nesmírně důležitá a je kladen důraz na to, aby s nima bylo nakládáno efektivně. Jejich ukládání v rámci zdrojového kódu se rozhodně za efektivní považovat nedá, protože při každé jejich změně se do zdrojového kódu musí zasahovat. Zároveň pak možnost data upravit připadá jen lidem, kteří se v kódu vyznají, tedy většinou programátorům, a ani se nedají nijak automatizovat.

Z těchto a dalších důvodu se v dnešní době data většinou ukládají v nějaké formě databáze.

Ta nad daty umí provádět různé operace, díky kterým se dají efektivně získávat a

manipulovat s nimi. S databází dále většinou pracuje nějaká backendová aplikace, která vytváří logickou vrstvu, jenž je uzpůsobena přímo dle případu použití. S tou poté

komunikuje frontendová aplikace, která již vytváří uživatelské rozhraní, které by mělo být pro uživatele přívětivé.

Implementace datové vrstvy a komunikace s backendovou aplikací na té frontendové je základní problém moderních webových aplikací, které jsou rozdělené právě na tyto dvě části. Bez tohoto kroku by koncept dvou (či více) rozdělených aplikací nemohl fungovat.

Jeho nesprávná implementace může zásadně negativně ovlivnit rychlost načítání webové stránky a zároveň ztížit další vývoj frontendové aplikace.

Cílem této práce je implementovat datovou vrstvu a komunikaci s backendovou aplikací na frontendové částí webová aplikace Adgame, která je vyvíjena na Vysoké škole

ekonomické v Praze na fakultě informatiky a statistiky. Ta je vytvořena v javascriptovém frameworku Vue.js.

Na počátku mé práce byla frontendová aplikace Adgame s použitím metafory „tělem bez duše“. Dala se sice otevřít ve webovém prohlížeči a proklikávat její jednotlivé stránky, ale nenaplňovala svůj účel (účel aplikace se bude dále rozebírat v kapitole o aplikaci Adgame).

Toho by nešlo dosáhnout bez propojení aplikace s backendovou částí pro získání dat, tedy s API rozhraním a s rozhraním pro sockety, které slouží pro obousměrnou komunikaci.

Zajištění oboustranné komunikace bylo v tomto případě nezbytné. Jedná se totiž o týmovou hru, ve které sdílí stejná data více hráčů a při úpravě těchto dat jedním hráčem tuto změnu v tom stejném okamžiku musí vidět i všichni jeho týmoví spoluhráči. Bez toho by jejich spolupráce nebyla možná a vzájemně by si data přepisovali, aniž by o tom věděli.

Stejně tak bylo třeba do frontendové části aplikace implementovat datovou vrstvu, která by všechna získaná data z backendové části udržovala na jednom centralizovaném místě a umožňovala je získávat skrze celou aplikaci. Zároveň by skrze ni aplikace mohla s daty manipulovat jak na frontendové části, tak na té backendové.

(9)

1. Moderní webové aplikace

Webové aplikace jsou oborem, který se neustále vyvíjí. Pro vytvoření webové aplikace, která obstojí ve své době musí být její vývojáři seznámeni s moderními postupy a nástroji, které zajistí efektivitu fungování aplikace a její přívětivosti používání pro uživatele. Velký důraz je například kladen na rychlost načítání obsahu, protože vzhledem k neustále se zvětšujícímu množství informací, které lidé zpracovávají, se zároveň zmenšuje jejich doba, po kterou udrží pozornost a s tím tak i jejich trpělivost. (1) Právě rychlost načítání obsahu je jedním z důležitých faktorů při zpracovávání této práce. V průběhu hry Adgame se načítá a zpracovává velké množství dat a neefektivní nakládání s nimi by mohlo zážitek ze hry znehodnotit.

1.1. Způsoby interakce frontendu a backendu

Způsob interakce frontendová a backendové části souvisí se základním problémem této práce, a proto budou v této kapitole popsány dvě architektury, které se k tomu využívají.

Frontendová část aplikace se interpretuje, a tedy i zobrazuje uživateli ve webovém prohlížeči a ten s ní může interagovat. Říká se jí také klientská. Základními využívanými jazyky je HTML, CSS, a JavaScript. HTML definuje strukturu a obsah dokumentu, CSS obsah stránky styluje do žádoucí podoby a JavaScript přidává interakci pro prvky, které se na webu nacházejí.

Backendová část naopak běží na serveru a uživatel k ní nemá přímý přístup. Komunikuje s ní skrze frontendovou část. Tato část může běžet na široké škále programovacích jazyků, jako příklad lze uvést například PHP, Node.js nebo Java. Pro ukládání, získávání a manipulaci dat většinou pracuje s nějakým druhem databáze, například MySQL, PostgreSQL nebo MongoDB.

Jedním z aspektů interakce frontendu a backendu je způsob renderování webové stránky.

V následujících kapitolách budou popsány dvě základní architektury renderování. Prvním způsobem je aplikace renderovaná na serveru a tím druhým aplikace renderovaná přímo na klientské části.

1.1.1. Aplikace renderované na serveru (tradiční přístup)

Renderování obsahu na serveru se dá považovat za tradiční přístup. V tomto případě se slovo renderování chápe jako generování obsahu HTML stránky. Dále se tento obsah renderuje na klientovi pomocí prohlížeče do grafické podoby. Mnoho takových tradičních webů bylo psáno v jazyce PHP. Při otevření webu tohoto typu se vytvořil požadavek na server a ten zkompiloval veškerý kód a data, aby webovému prohlížeči doručil zpracovaný HTML soubor, který již byl pak jen zobrazen. Prohlížeč dále stáhnul závislosti, které byly v HTML definovány, jako jsou například CSS a JavaScript soubory.

(10)

Ačkoliv tento způsob může být rychlejší při prvním načtení stránky, méně efektivním se stává při překlikávání na stránky další (2). Pokaždé, když se totiž vytvoří nový požadavek se celá stránka musí na serveru znovu zkompilovat a znovu inicializovat spolu se styly a JavaScriptem. To může vést k prodlevám.

Dříve by se obecně dalo tvrdit, že aplikace renderované na serveru byly v podobě jedné robustnější aplikace, která se zároveň starala o logickou backendovou část a zároveň o renderování. Data získaná z backendu tak bylo přímo předána šabloně, jenž byla vyrenderována. Dnes již však mohou být na serveru renderované i frontendové aplikace, a tak již není faktem, že aplikace renderovaná na serveru nemusí komunikovat s backendem skrze požadavky na nějaký druh API. Proto bude dále popsán i koncept samostatné frontendové aplikace.

1.1.2. Aplikace renderované na klientské části

V případě renderování na klientské části webový prohlížeč od serveru obdrží jediný HTML soubor, který kromě závislostí v podobě CSS a JavaScriptu neobsahuje žádný obsah. Obsah webové stránky tímto způsobem se totiž renderuje přímo ve webovém prohlížeči za pomocí JavaScriptu. Tento způsob se stal více používaným až s příchodem JavaScriptových frameworků, jako je například React.js nebo Vue.js (3). Právě Vue.js je využit v aplikaci Adgame.

Výhodou tohoto přístupu je dynamika obsahu, možnosti interakce a rychlosti změny obsahu a překlikávání stránek. Takové aplikace mají většinou svůj vlastní systému routování, který při změně adresy nevytváří hned požadavek na server. (3; 2) Místo toho pouze přerenderuje obsah, který se má změnit. Nemusí se tak znovu kompilovat a načítat celá stránka. Pokud se vytváří požadavek na server, získává se pouze obsah samotný, nikoliv znovu celá HTML stránka, která by se potom opět musela inicializovat.

V minulosti byla nedostatkem tohoto řešení podpora SEO. Vzhledem k tomu, že je stránka po načtení prázdná, nedokázali roboti vyhledávacích nástrojů její obsah správně zaznamenat, pokud byl získáván asynchroně. V nynější době již však roboti v případě aplikace renderované na klientské části počkají na to, až se stránka v prohlížeči vyrenderuje a až poté ji zachytí. (4) Není to tedy již nadále problém.

1.2. Samostatná frontendová aplikace

Frontendová část Adgame je typu samostatné frontendové aplikace. To znamená, že frontendová a backendová část je rozdělena na dvě či více aplikací. To má za výhodu vzájemnou nezávislost. Pro jednotlivé aplikace mohou být použité rozdílné technologie a ty mohou být zároveň kdykoliv změněny, aniž by ovlivnily aplikace ostatní. Dalšími výhodami je jejich jednodušší udržitelnost, přehlednost a typicky efektivnější vývojové prostředí než pro jednu společnou aplikaci.

Protože samostatná frontendová aplikace nemá sama o sobě přístup k datům, pokud nejsou staticky uloženy ve zdrojovém kódu, při renderování data načítá z nějakého druhu API

(11)

pomocí HTTP požadavku. API je rozhraní s jedním nebo více endpointy, které vrací nějakou odpověď dle druhu endpointu a požadavku. Zároveň je skrze ni typicky možné s daty manipulovat. Nejčastěji využívanou architekturou pro webové služby a zároveň architektura již využívá API rozhraní backendové aplikace Adgame je REST API (5).

1.2.1. Vytváření HTTP požadavků

Je více způsobů, jak požadavek na API rozhraní vytvořit. Dříve byl pro HTTP požadavky používán XMLHttpRequest (6), který je nativně podporován prohlížeči. Ten je však poměrně těžkopádný a v této době zastaralý. Nahradil ho standard Fetch API (6), který je taktéž nativně dostupný. Jeho použití je pro základní požadavky jednoduché. Nevýhodou je však nekompatibilita se staršími prohlížeči a obecně Internetem Explorerem (7).

Alternativou pro nativní Fetch API je knihovna Axios. Co se týče Vue.js je nejčastěji používanou a v oficiální dokumentaci doporučováno. (8) Jedná se o javascriptového HTTP klienta, který je založen na „promise“ přístupu a je tedy asynchronní. „Promise“ přístup při požadavku vytvoří „příslib“, který čeká na dokončení požadavku (9). Pokud neselže, typicky se po jeho dokončení provede nějaká operace s případně získanými daty.

Hlavní výhodou Axiosu je jeho jednoduchost a efektivnost použití. Zároveň nemá problémy s kompatibilitou jako Fetch API. Je vytvořena proto, aby vývojářům usnadňovala vývoj, co se týče HTTP požadavků. Vzhledem k tomu, že se jedná o celého klienta, se dá na začátku jeho instance konfigurovat dle potřeby. V Adgame je například většina požadavků dostupná pouze přihlášenému uživateli a je tak třeba do hlavičky přikládat Bearer token. Toho lze skrze konfiguraci snadno docílit a ta zároveň nabízí další usnadnění, jako definování základní URL adresy REST API. S každým požadavkem tedy není třeba tuto celou adresu vypisovat.

Všech těchto nastavení by pochopitelně šlo dosáhnout i za použití Fetch API, nicméně vyžadovala by to napsání vlastní funkcionality a zabralo více řádku kódu. Pro efektivnější vývoj a z důvodů kompatibility je proto pro HTTP požadavky zvolena knihovna Axios.

(12)

2. Vue.js

Frontendová část aplikace Adgame je vyvíjena ve frameworku Vue.js v2. Ačkoliv platí při implementaci datové vrstvy některá obecná pravidla, je vždy specifická v závislosti na použitých technologiích. Bez znalosti tohoto frameworku by tak nebylo možné implementaci správně provést.

Vue.js je javascriptový framework pro vývoj uživatelských rozhraní. Přišel do světa s již zaběhlými rivaly, jako je například React.js nebo Angular, ale díky svým vlastnostem se stal populárním a nyní ho používají i velké společnosti, jako například Netflix, Adobe nebo GitLab (10).

Jednou z jeho výhod je dobře napsaná dokumentace a jeho jednoduchost učení i tvorby nového projektu (11). Značně vývojářům usnadňuje práci, protože mnoho funkcionalit, které by jinak zabraly mnoho řádků tento framework řeší jednoduše a elegantně.

Oproti tradičním přístupům jako je třeba jQuery slouží v tomto frameworku HTML DOM pouze k zápisu. Žádná data by se z něj tedy neměla kromě výjimek číst. (12) V jQuery by se například pro zjištění stavu nějakého rozbalitelného divu přečetly jeho třídy. Pokud by obsahovaly třídu „expanded“, zjistilo by se, že je otevřený. Tento přístup odporuje přístupům ve Vue.js. V tom je jediným zdrojem pravdy logika za komponenty. Jedná se o modely dat v podobě objektů, které v paměti udržují jejich stav. Pro zjištění, zda je div rozbalený by poté stačilo pouze přistoupit k vytvořené proměnné, například „isExpanded“.

Tato proměnná se zároveň využívá v šabloně komponenty, kde se reflektuje její stav.

2.1. Znovupoužitelné komponenty

Vue.js je framework s modulární architekturou (13). Ta dává důraz na znovupoužitelnost kódu. Toho lze efektivně dosáhnout pomocí znovupoužitelných komponent, což je základní koncept Vue.js. Vývojář by tak měl k vývoji přistupovat dle tohoto konceptu a nenechat se mást těmi tradičními. Správný návrh znovupoužitelných komponent je velmi důležitý pro další rozvoj celé aplikace, ale i pro implementaci dat, a tedy tuto práci. Porušení principů znovupoužitelných komponent bude na příkladu popsáno ve fázi implementace, protože mi ji ztěžovalo.

Komponenta se v instanci Vue.js zaregistruje pod nějakým jménem a pod tím lze poté používat v rámci šablonovacího systému. K běžným tagům jako je například „h1“ tedy přidává i vlastní tagy, které vykreslí danou komponentu. Pomocí atributů těmto komponentám lze i předávat data.

Nejběžnější možností jak komponentu vytvořit je ve svém vlastním souboru s koncovkou

„.vue“. Ten má strukturu rozdělenou na tři části, kterými jsou šablona, styl a logika.

Výpis 1 Příklad prázdné Vue.js komponenty (vlastní zpracování)

(13)

<template></template>

<style></style>

<script>export default {}</script>

Níže budou detailněji popsány všechny tři části a zároveň mnou demonstrovány na jednoduchém příkladu počítadla. To bude mít ve svém lokálním stavu dat hodnotu počítadla. Přes parametry bude nastavena tato defaultní hodnota a hodnota cílová. Pomocí metody bude zvyšována. Skrze „computed“ proměnnou bude vypočítávaná zbývající hodnota k cíli. Vše se bude vypisovat v šabloně.

První bude popsána část šablony, která se nachází uvnitř tagu „template“. Ve verzi Vue 2 musí být uvnitř vždy pouze jeden kořenový element. V rámci šablony je možné využít pro interpolaci syntax „Mustache“ (13), který je v podobě dvou složených závorek. V tom lze přistoupit k logice za šablonou a vypsat tak data nebo zavolat metodu. Zároveň je v nich možné psát čistý JavaScript.

Kromě interpolace jsou v šabloně dostupné direktivy (13). Ty se dají rozpoznat dle prefixu

„v-“. Pomocí těch lze například provádět kondicionální renderování nebo naslouchat eventům jednotlivých prvků. Pro zpracování kliknutí na tlačítko se k němu přidá „v- on:click=’nazevMetody’“ nebo zkráceně „@click=’nazevMetody’“. Metoda z logiky komponenty se poté vždy po kliknutí na tlačítko zavolá.

Výpis 2 Příklad šablony komponenty počítadla (vlastní zpracování)

<template>

<div>

<p>Aktuální hodnota: {{ counter }}</p>

<button @click="increase">+1</button>

<button @click="increase(5)">+5</button>

<p>Zbývá: {{ remaining }}</p>

</div>

</template>

Druhá část je styl komponenty, který se klasicky zapisuje do tagu pro styl, tedy „style“. Po přidání atributu „scoped“ se však styl bude aplikovat jen v rámci této komponenty, nikoliv globálně, což ulehčuje proces stylování. Zároveň podporuje atribut „lang“, v němž je možné upřesnit způsob zápisu stylu, například v jazyce SASS, který CSS rozšiřuje.

Výpis 3 Příklad stylu komponenty počítadla (vlastní zpracování)

<style scoped lang="scss">

p {

font-size: 2em;

}

</style>

Poslední částí je javascriptový objekt, který se pomocí ES6 modulu ze souboru exportuje.

Ten obsahuje logiku komponenty. Takovými základními atributy logické části komponenty jsou „props“, „data“, „methods“ a „computed“.

(14)

Výpis 4 Příklad struktury logické části komponenty ve Vue.js (vlastní zpracování)

<script>

export default { props: {}, data: () => {}, computed: {}, methods: {}, }

</script>

„Props“ jsou parametry, které lze komponentě předat pomocí vlastních atributů přímo na HTML tagu. Ty musí být definovány v logice komponenty a můžou být zapsanými například následující formou, kde klíčem je název parametru a hodnotou poté objekt s typem dat a defaultní hodnoty. Props by se nikdy neměly v rámci komponenty mutovat.

Výpis 5 Příklad „props“ komponenty počítadla (vlastní zpracování) props: {

defaultValue: { type: Number, default: 0, },

target: {

type: Number, default: 100, },

},

Pod klíčem „data“ by se měla nacházet funkce, jenž vrací objekt s daty. Ty jsou pro tuto komponentu lokální. Mohou zároveň přistupovat k props, jako je uvedeno v následujícím příkladu. Defaultní hodnota počítadla tak bude z props převzata.

Výpis 6 Příklad "data" komponenty počítadla (vlastní zpracování) data() {

return {

counter: this.defaultValue }

},

„Methods“ je objektem, který obsahuje funkce. Těm mohou být předávány argumenty.

V methods lze měnit lokální data komponenty, jak je uvedeno v následujícím příkladu.

Výpis 7 - Příklad "methods" komponenty počítadla (vlastní zpracování) methods: {

increase(value = 1) { this.counter += value;

} },

„Computed“ proměnné jsou objektem, který opět obsahuje funkce. Tyto však musí vždy vracet nějakou hodnotu. Přistupuje se k nim stejným způsobem, jako ke getteru, tedy bez závorek, jako kdyby se přistupovalo k obyčejné proměnné. Jsou však reaktivní a kdykoliv se

(15)

změní nějaká jejich část, znovu se přepočítá. V tomto případě tedy vždy, když se změní cíl počítadla nebo jeho stávající stav, přepočítá se, kolik ještě zbývá do cíle.

(16)

Výpis 8 Příklad "computed" komponenty počítadla (vlastní zpracování) computed: {

remaining() {

return this.target - this.counter;

}, },

Takto hotová komponenta by poté byla v jiné komponentě naimportována a zaregistrována mezi dostupné komponenty pomocí „components“. Poté již může být pod svým jménem použita v podobě tagu v šabloně spolu s přidanými parametry.

Výpis 9 Příklad zaregistrování a výpisu komponenty počítadla (vlastní zpracování)

<template>

<Counter :defaultValue="1" :target="20"/>

</template>

<script>

import Counter from './Counter' export default {

components: {Counter}, }

</script>

Všechny výše zmíněné části logiky komponenty jsou dostupné skrze ní v kontextu „this“, ale i v šabloně. Velkou výhodou je automatická reaktivita. Jakmile se změní nějaká proměnná z logiky využitá v šabloně, automaticky bude na webu překreslena na její aktuální hodnotu.

Jakmile dochází k jakémukoliv přerenderování, stará se o to virtuální DOM.

2.2. Virtuální DOM

Vue.js využívá princip virtuálního DOMu. DOM jako takový (Document Object Model) je struktura dokumentu v podobě stromu, ve kterém jsou uspořádány jednotlivé prvky. (14) Jeho problémem však je, že nebyl zamýšlen jako dynamický model a při přímém zasahování do něj se stává problémem rychlost překreslování. (15)

Z toho důvodu byl vytvořen koncept virtuálního DOMu. Ve Vue.js se jedná o javascriptový objekt, který je abstraktní verzí toho skutečného (15; 16). Vzhledem k tomu, že se jedná pouze o objekt je jeho změna mnohem rychlejší. Tím se však ještě změna neprojeví. Poté, co se změní virtuální DOM se teprve porovná se stavem toho skutečného a na základě toho se v něm přerenderuje pouze ta část, která je v tom virtuálním rozdílná. Díky této technice je přerenderování efektivnější a rychlejší (15; 16).

Na první pohled se tato informace nemusí zdát důležitá. Opak je však pravdou, protože při vývoji aplikace ve Vue.js toto musí brát vývojář na vědomí a dle toho přistupovat k vývoji.

Je obecným pravidlem, oproti frameworku jako je třeba jQuery, že by se až na výjimky nemělo přímo zasahovat do DOMu. Veškeré změny by tedy měly probíhat v logice komponent pomocí reaktivních dat a kondicioálního renderování, nikoliv pomocí přímé modifikace elementů v DOMu. Porušení tohoto pravidla by mohlo vést k různým bugům a nekonzistnostem.

(17)

3. Datová vrstva

Samostatná frontendová aplikace typu Adgame je závislá na datech, které získává z backendové části pomocí REST API rozhraní nebo socketů. REST API má definované mnoho druhů endpointů, na které se dle situace volají požadavky. V projektech tohoto rozměru je důležité mít pro všechna tato data jeden centralizovaný zdroj, ze kterého se všechny požadavky volají a zároveň se do něj ukládají výsledky. Bez takového řešení by docházelo ke zbytečně opakovaným požadavkům a opakovaném kódu v každé části aplikace, která potřebuje určitá data.

Přístupů k práci se stavem dat ve Vue.js aplikaci je více. Nejčastěji využívanou variantou ve Vue.js 2 je knihovna Vuex. Pro jednoduché aplikace menších rozměru pravděpodobně Vuex potřeba implementovat není, protože se to dá vyřešit jednodušším způsobem. V takovém případě by naopak mohl Vuex při vývoji překážet svými pravidly a složitostí. Jakmile se však jedná o aplikaci většího rozměru, řešení jako je Vuex je více než na místě a v dlouhodobém časovém horizontu se rozhodně vyplatí.

V následujících kapitolách budou popsány různé přístupy implementace datové vrstvy ve Vue.js.

(18)

3.1. Správa dat pomocí lokální datové vrstvy

V jednoduchých aplikacích malého rozměru je možné centralizovaný zdroj dat úplně vynechat. S daty se tak pracuje pouze na úrovni lokální, tedy v rámci jednotlivých komponent. V hlavních komponentách, kde jsou data potřeba, se tak získají například pomocí API rozhraní.

Tato data se poté mohou dalším podřazeným komponentám předávat pomocí parametrů.

Parametry by se však v rámci komponent neměly mutovat a z toho důvodu, pokud chce podřazená komponenta data nějak upravovat, měla by zavolat metodu „emit“. Tato metoda přijímá název akce a volitelně parametr, v tomto případě nový stav dat. Nadřazená komponenta na tuto akci naslouchá a přijatá nová data uloží do svého stavu, který se tak zároveň automaticky promítne i do podřazené komponenty.

Obrázek 1 Diagram komunikace komponent (zdroj: https://blog.usejournal.com/the- perfect-wrapper-components-in-vue-2-6-and-soon-vue-3-0-41520cd4c3f2)

Tento způsob však může být efektivní pouze v opravdu jednoduchých aplikacích. Jakmile struktura komponent sahá do větší hloubky, je obtížné a zdlouhavé data předávat a upravovat. Uvedený diagram by se musel opakovat pro každou komponentu zanořenou o úroveň níže relativně od hlavní komponenty. Ve třech úrovních by komponenta nejníže musela své nadřazené komponentě předat akci o změně dat a ta by tuto akci musela předat zase své nadřazené komponentě. Kromě toho by správa dat byla nepřehledná.

Z uvedených důvodů tento způsob implementace není vhodný pro aplikaci rozsahu, jaký má Adgame.

(19)

3.2. Vlastní řešení centralizované datové vrstvy

Z předchozí kapitoly vyplývá, že u složitějších aplikací je výhodné využívat nějaké formy centralizované datové vrstvy. Pro jednodušší případy datové vrstvy je možné vytvořit vlastní centralizovanou datovou vrstvu, napsanou přímo pro potřeby aplikace.

Toho lze docílit vytvořením objektu, který by udržoval stav dat. Pomocí „Vue.observable“ se tento objekt může stát reaktivním, což je nápomocné pro automatické přepisování dat v rámci komponent. Pro správu dat by poté byly přidány funkce, jenž by s tímto objektem pracovaly. Vše dohromady by bylo vyexportováno jako modul, který může být naimportován v jednotlivých komponentách. Díky tomu by měly přístup k datům a k funkcím, pomocí kterých by mohly data upravovat.

Obrázek 2 Diagram centralizované datové vrstvy. (zdroj:

https://vuejs.org/v2/guide/state-management.html?#Simple-State-Management-from- Scratch)

Tímto způsobem je již zdroj dat centralizovaný. Komponenty k němu mohou přistoupit odkudkoliv a pracovat s ním předem definovaným způsobem. Pro Adgame by se nad touto volbou dalo uvažovat. Vzhledem ke složitosti Adgame by však tento způsob mohl vyústit v méně přehlednou datovou vrstvu. Hlavní nevýhodou by poté bylo debuggování, které by bylo mnohem náročnější než při volbě knihovny Vuex.

(20)

3.3. Vuex

Vuex je oficiální knihovna pro Vue.js od stejného autora samotného frameworku, která slouží jako centralizovaný zdroj dat (17). Ten je dostupný v celé aplikaci a ve všech komponentách. Ve své dokumentaci má jasně popsané konvence práce s tímto zdrojem dat.

Obsahuje výhody zmíněné v předchozí kapitole a k tomu přidává již předem připravené funkcionality, které značně ulehčují vývoj a debuggování. S nainstalovaným rozšířením

„Vue Devtools“ přibyde v prohlížeči panel Vue, ve kterém lze nalézt i Vuex. Tam je možné prozkoumávat stávající stav dat, ručně ho měnit, sledovat kdy a z jakého zdroje byly volány mutace či se vracet v čase. To je nesmírně cenný nástroj při správě velkého množství dat, jako tomu je u Adgame.

Z těchto důvodů je jako implementační volba datové vrstvy pro tuto práci zvolen Vuex.

3.3.1. Koncept Vuexu

Vuex store je objekt, jenž obsahuje čtyři základní části. Těmi jsou „state“, „getters“, „actions“

a „mutations.“

Výpis 10 Příklad struktury Vuex store (vlastní zpracování) export default {

state: () => ({}), getters: {},

actions: {}, mutations: {}, }

State je stav dat. Jedná se o objekt, který je však díky Vuexu reaktivní. Stav dat by neměl nikdy být přímo modifikován. K tomu slouží dle konvencí mutace, což jsou v praxi metody, které pomocí kontextu stav dat mění. Mutace jsou pouze synchronní a z toho důvodu jsou dalším typem metod akce. Akce již mohou být asynchronní, a právě zde se například volají požadavky na REST API. Získaná data se poté pomocí mutace uloží do stavu dat.

K samotným datům se poté v aplikaci může buďto přistupovat přímo skrze stav dat, nebo tak může být učiněno skrze gettery. Gettery jsou metody, které na výstupu vracejí data, jenž mohou být nějak upravena. V prvním argumentu mají vždy předaný od Vuexu state. Jejich využívání předchází opakování kódu.

Pro příklad bude nyní navázáno na počítadlo z kapitoly o Vue.js. Ve stavu dat by byla definována aktuální a cílová hodnota.

(21)

Výpis 11 Příklad stavu dat počítadla ve Vuex (vlastní zpracování) state: () => ({

counter: 1, target: 10, }),

Pro zjištění, kolik ještě zbývá odpočítat lze využít getter.

Výpis 12 Příklad getterů počítadla ve Vuex (vlastní zpracování) getters: {

remaining: (state) => state.target - state.counter },

Pro úpravu dat je třeba definovat mutace.

Výpis 13 Příklad mutací počítadla ve Vuex (vlastní zpracování) mutations: {

INCREASE(state, value) { state.counter += value },

},

Na konec se vytvoří akce, jenž mutaci zavolá pomocí „commit“. V tomto případě se může akce zdát trochu zbytečná, ale ve složitějších případech má své opodstatnění. Akce samotná by se skrze Vuex store zavolala pomocí „dispatch“ funkce na příslušném místě v aplikaci.

Výpis 14 Příklad akcí počítadla ve Vuex (vlastní zpracování) actions: {

increase({commit}, value = 1) { commit('INCREASE', value) }

},

Vzhledem k tomu, že celý store je pouze jedním objektem, v jedné úrovni objektu by se data a metody různých druhů mohla začít plést a v kódu by byl nepořádek. Od toho slouží ve Vuexu koncept modulů. Pro každý druh dat může být tak vytvořen jeho vlastní modul, který obsahuje svůj stav dat, mutace, akce a gettery. V případě Adgame budou tak například vytvořeny vlastní moduly pro kampaně a produkty.

(22)

4. Obousměrná komunikace

Adgame je týmová hra pro více hráčů, kteří ve stejném čase provádějí ve hře různé

operace, jenž mění jejich herní týmová data. Každý je přihlášen na svém vlastním zařízení a účtu a jejich operace je potřeba vzájemně synchronizovat. Z toho důvodu je nezbytné využít kromě REST API jako druhý druh komunikace i oboustrannou komunikaci.

Hlavním důvodem, proč nelze pro tento druh komunikace využít REST API je fakt, že REST API je jednosměrnou komunikací založenou na požadavku a odpovědi. Klient vytvoří požadavek na API přes HTTP protokol a ta mu vrátí odpověď. REST API však klienta nikdy sama od sebe nekontaktuje (18). Klient by tedy musel mít nastaven časový interval, po kterém by vždy vytvořil požadavek a zkontroloval, zda jsou od posledního požadavku nějaké nové změny v datech. To by bylo velmi neefektivní, protože takový HTTP požadavek na REST API je poměrně časově náročný. Zároveň by vznikalo zpoždění v závislosti na intervalu opakování (19).

Tento problém však řeší web sockety. Ty využívají HTTP protokol pouze při inicializaci spojení. Poté již obousměrná komunikace běží na TCP spojení (20; 18). Toto spojení si drží svůj stav, tedy je aktivní tak dlouho, dokud není jednou ze stran zrušeno. Klient se přihlásí k odběru na specifické URL adrese a na tuto adresu poté server průběžně posílá signály, kterým klient naslouchá. Ty mají nějaký název a volitelně i mohou přenášet data. Stejně tak může signály posílat klient. Díky tomu se o událostech klienti dozví v tom stejném okamžiku, kdy je provedena.

Přes sockety se typicky neposílají velké objemy dat a dají se libovolně kombinovat s REST API. Když se například klient dozví, že na serveru proběhla nějaká významná událost, vytvoří si požadavek na REST API, ze které získá data nová.

Na frontendové části mohou být obecně webové sockety implementovány více způsoby. Při volbě technologie je však třeba brát na zřetel technologii použitou na backendové části a ty si musí vzájemně odpovídat, jinak by spojení nemuselo fungovat.

Na backendové části Adgame je využita technologie SockJS s protokolem STOMP. Tyto technologie je tedy nutné implementovat i na frontendové části.

SockJS je javascriptová knihovna, jenž poskytuje podobné rozhraní jako nativní WebSocket. Výhodou je nízká latence, a hlavně kompatibilita skrze různé webové prohlížeče, a to i pro takové, které nepodporují nativní WebSockety. Nejprve se sice nativní WebScockety pokusí použít, ale pokud nejsou dostupné, nahradí je abstrakcí jim podobnou (21).

STOMP protokol je poté textově orientovaná nadstavba protokolu WebSocket, jenž ho rozšiřuje o HTTP zprávy typu „CONNECT“, „SUBSCRIBE“ a další (22). To usnadňuje navázání vzájemné komunikace klienta a serveru.

(23)

5. Webová aplikace Adgame

Adgame je projekt, jenž je vyvíjen na Vysoké škole ekonomické v Praze na fakultě multimédií. Má sloužit jako pomůcka při výuce žáků této školy ale zároveň pro firemní či jiné školení. Uživatelé v týmech vytvářejí produkty a propagují je pomocí různých druhů reklam ve vybraných lokacích za použitím přiřazeného rozpočtu. V průběhu by se měli hravou formou naučit zpracovávat a analyzovat data, která tato hra poskytuje. Jenom touto cestou můžou najít nejefektivnější cestu propagace a se svým týmem tak hru vyhrát.

Po technické stránce se skládá z mnoha jednotlivých částí, které spolu interagují. Před počátkem mé práce bylo již z části připraveno ve frontendové části uživatelské rozhraní, které bylo vytvořeno v javascriptovém frameworku Vue.js.

Pro tuto práci tedy je ze všech částí podstatná pouze ta frontendová a poté REST API rozhraní a rozhraní pro Web Sockety. Pro REST API a Web Sockety byla napsána dokumentace a pro REST API zároveň vygenerována dokumentace ve Swaggeru. To bylo podstatné pro implementaci komunikace s backendovou částí.

5.1. Koncept hry Adgame

Z uživatelského manuálu Adgame:

AdGame je simulátor nákupu reklamního prostoru ve fiktivním městě. Hráči reprezentují firmy prodávající jídlo a jejich cílem je vydělat co nejvíce peněz pomocí propagace jejich produktů. Města se skládají z několika lokací, mezi kterými se pohybují jeho obyvatelé. Ti se dělí do různých skupin, dle svých příjmů, preferencí typů a kvality jídla, případně i dalších parametrů. Správného zacílení reklamy hráči dosáhnou především díky analýze dat s informacemi o obyvatelích města. Pomocí těch mohou nastavit parametry produktů, jako typ kuchyně nebo kvalita a umístění reklam do správných částí města. AdGame má několik obtížností, reprezentovaných základními městy.

V rámci jedné hry hrají všichni hráči v tom samém městě, tudíž si mohou, a budou, vzájemně konkurovat. Proto může být vhodné v průběhu hry měnit nastavení svých produktů, případně vytvářet produkty jiné a snažit se je propagovat jiným skupinám obyvatel. Jednotliví obyvatelé mají vždy alokované množství peněz na jedno herní kolo, skládající se ze sedmi dnů. Každý den si může obyvatel koupit produkt - musí na něj ale mít dostatek peněz a musí po něm mít dostatečně vysokou poptávku vytvořenou reklamami hráčů. Pokud nejsou obě tyto podmínky splněny, část ze svých peněz obyvatel utratí, aby si “vařil sám doma”.

(24)

5.2. Náležitosti frontendové části Adgame

Frontendová část Adgame je poměrně rozsáhlá a obsahuje různé sekce a požadavky na funkcionalitu. Pro úspěšnou implementaci datové vrstvy a komunikace s backendovou částí je nejprve třeba tyto náležitosti pochopit. Samotné studování toho, jak se má Adgame chovat a fungovat bylo první částí procesu mé implementace.

Základní funkcionalitou je přihlášení a registrace uživatele, bez kterých by se uživatel do hry vůbec nedostal. Tato část nabízí i zapomenuté heslo.

Po přihlášení je v levém bočním panelu zobrazen jeho uživatelský účet, u kterého může kliknout na ikonu, která vyvolá modalové okno s nastavením jeho účtu, kde si může změnit uživatelské jméno nebo heslo. Pod touto ikonou nalezne i tlačítko, pod kterým se může odhlásit ze svého účtu.

Další části aplikace se liší dle role uživatele, a proto budou rozděleny na dvě kapitoly.

Obrázek 3 Ukázka přihlášení do Adgame (z grafického návrhu Adgame)

(25)

5.3. Z pohledu uživatele jako hráče

5.3.1. Seznam her a lobby

Běžný uživatel se po přihlášení dostane na úvodní stranu, která mu nabízí připojení se do hry. To je v podobě textového pole na kód hry a dále seznamu her, do kterých je zapojen a seznamu otevřených veřejných her.

Do otevřené veřejné hry se může pomocí tlačítka připojit. Druhým způsobem je připojení se přímo pomocí kódu specifické hry, která může být i privátní, tedy v seznamu nezačleněná.

Jakmile je uživatel připojen v lobby, může si buďto vytvořit svůj vlastní tým, nebo se přidat do týmu existujícího. Tým může samozřejmě později změnit nebo se z něj odpojit. V této fázi již přichází do hry komunikace v reálném čase, protože vždy po připojení nového uživatele nebo připojení či opuštění týmu by se měly změny ukázat všem již připojeným uživatelům.

Připojený uživatel poté vyčká až se do hry připojí všichni účastníci kurzu a administrátor hry ji spustí. Tímto se přesune již do sekce samotné hry. Pokud by se v této fázi nebo v průběhu hry z nějakého důvodu odpojil, jeho aktivní hra bude viditelná na úvodní stránce v seznamu jeho her a může se do ní opět připojit.

Obrázek 4 Ukázka seznamu her Adgame (z grafického návrhu Adgame)

(26)

5.3.2. Hra

V sekci již spuštěné hry je na úvodní stránce přehled celé hry pro uživatelův tým.

V jednotlivých boxech se mu zde zobrazí prodané produkty za minulé kola, vytvořené kampaně, koupená data, žebříček týmů dle stavu peněz, finanční přehled a jeho tým v podobě jmen týmových spoluhráčů.

V levém bočním panelu by se mu měl zobrazovat vždy aktuální rozpočet. Zde se i nachází menu, ve kterém se může dostat na další stránky.

Obrázek 5 Ukázka herního přehledu Adgame (z grafického návrhu Adgame)

(27)

5.3.3. Správa produktů

Na stránce správy produktů může uživatel vytvořit nový produkt či editovat nebo smazat stávající. U každého produktu se nastavuje jeho kategorie, která má vliv na náklady. Tyto kategorie spolu se svými náklady je třeba získat skrze REST API z nastavení hry. Dále je třeba vyplnit jméno, kvalitu a prodejní cenu. Kvalita také ovlivňuje náklady na výrobu produktu.

Může se stát, že stejný produkt začne upravovat v tu stejnou chvíli více uživatelů najednou.

Proto je důležité, aby při dokončení úpravy produktu byl ostatním uživatelům zrušen editovací mód a indikovány nové změny. V opačném případě by si nebyli vědomi, že přepsali někým jiným právě potvrzené změny.

Obrázek 6 Ukázka správy produktů Adgame (z grafického návrhu Adgame)

(28)

5.3.4. Správa kampaní

Na stránce pro správu kampaní se nejprve vybere produkt, pro který má být kampaň vytvořena. K tomu se poté přidává libovolný počet typů reklamního média. Pro každé reklamní médium je třeba určit jednotlivé časy v rámci dnů týdne, kdy bude reklama probíhat, a lokace, na kterých bude umístěna. Jaké druhy reklamních médií budou k dispozici je opět záležitost nastavení hry. Reklamní médium má nastavenou svou základní cenu a poté ceny časů a lokací, která se vypočítávají v závislosti na počtu vybraných časů a lokací.

Kampaně jsou narozdíl od produktů aktivní pouze na jedno kolo a po jeho uplynutí se přesunou do archivovaných. Vytvořené kampaňe mohou být duplikovány pro rychlejší vytvoření kampaně nové ať již jsou aktivní nebo archivované.

Obrázek 7 Ukázka správy kampaní Adgame (z grafického návrhu Adgame)

(29)

5.3.5. Nákup herních dat

Na straně nákupu dat si mohou uživatelé nakoupit různé druhy dat, které by jim díky jejich analýze měly pomoct určovat další strategii. Zakoupená data se také zobrazují na přehledové stránce. Tato data je možné stáhnout jako excelovský soubor.

Obrázek 8 Ukázka nákupu herních dat Adgame (z grafického návrhu Adgame)

5.3.6. Průběh herních kol

V horním panelu v sekci hry lze pozorovat číslo kola a celkový počet kol. Vedle toho se odpočítává zbývající čas. Všechny tyto faktory jsou opět získávané z nastavení hry. Ve chvíli, kdy je hráč spokojen se svými akcemi a již v tomto kole žádné jiné dělat nehodlá, může kliknout na tlačítko v horním panelu „Ready for next round“, které hře indikuje, že je hotový. Ve chvíli, kdy jsou všichni hráči hotoví nebo uplynul časový limit se hra přepne do dalšího kola a zobrazí výsledky prodejů z kola předchozího.

V případě, že právě skončilo poslední kolo hra vypočítá pořadí týmů a všem se zobrazí finální žebříček. Po jeho odkliknutí je hráč přesměrován zpět na úvodní stránku, kde se může připojit do další hry.

5.3.7. Týmová spolupráce

Všechny výše popsané části sekce aktivní hry podléhají spolupráci více hráčů v rámci každého týmu. Proto je nezbytné, aby byla přítomná komunikace v reálném čase a každá změna hráče se okamžitě projevila všem ostatním spoluhráčům týmu.

(30)

5.4. Z pohledu uživatele jako administrátora

Uživatel s rolí administrátora narozdíl od toho běžného není hráčem. Místo toho má své uzpůsobené prostředí. Podobně jako hráči vidí na své úvodní stránce seznam jeho vytvořených her rozdělených do aktivních, neaktivních a archivovaných. Na stejné má možnost vytvořit hru novou a upravit nastavení dle potřeby.

Ve správě určité hry poté vidí připojovací kód v případě privátní hry a seznam týmů a jejich hráčů. V případě potřeby má právo na to jakýkoliv tým smazat nebo hráče ze hry vyhodit.

Když jsou všichni hráči připraveni, může hru spustit.

U spuštěné hry může sledovat žebříček hráčů dle stavu rozpočtu a poté pro každý tým jejich finanční přehled. Když se tak rozhodne, může se hrou i v jejím průběhu manipulovat. Mezi operace dostupné v době psaní této práce patří předčasné ukončení kola nebo celé hry, prodloužení stávajícího kola o určený čas, změna počtu kol nebo změna trvání všech jednotlivých kol. Pro rozhodnutí mu může být nápomocný i přehled, ve kterém vidí, kteří hráči jsou již hotoví a kteří ještě ne.

Po ukončení hry vidí stejný finální žebříček jako hráči, a tak ji s nimi může po konci diskutovat.

Obrázek 9 Ukázka z administrace hry Adgame (z grafického návrhu Adgame)

(31)

6. Akademické práce zabývající se podobnou problematikou

6.1. Software pro agregaci vzdělávacích akcí (Bc. Jakub Voráček, 2020)

Bakalářská práce Software pro agregaci vzdělávacích akcí se k této práci vztahuje použitím podobné frontendové technologie a svou implementací komunikace s backendovou částí.

Frontendová aplikace byla sice vytvořena v Nuxt.js, ale ten je postaven na Vue.js a tak je velmi podobný. Backend byl poté řešen s AWS Amplify a API byla typu GraphQL. Tato práce sice využívá REST API, ale přesto některé procesy implementace zůstávají společné.

6.2. Problémy implementace platformy využívající sdílenou ekonomiku (Ing. Josef Doškář, 2019)

Diplomová práce Problémy implementace platformy využívající sdílenou ekonomiku z části řeší téma implementace dat a komunikace s backendovou částí velmi podobným způsobem, jako tato bakalářské práce. Frontendová aplikace je zde vytvořena v totožné technologii, tedy Vue.js. Pro management datové vrstvy je stejně tak využita knihovna Vuex a jsou v ní zachovávány podobné konvence, jako v této práci.

6.3. Testování UX pro výukový simulátor AdGame ( Bc. Michael Veis, 2021)

Bakalářská práce Testování UX pro výukový simulátor AdGame přímo souvisí s touto bakalářskou prací, neboť se zabývá stejným projektem, pouze z jiné části jeho vývoje a její realizace probíhala ve stejnou dobu, jako tato. Frontendovou aplikaci Adgame testovala z pohledu UX, tedy z pohledu uživatelské přívětivosti, ale i z pohledu celkového designu.

Výsledky testování a analýz poté byly předávány na vývojářský tým, tedy i na mě. Já jsem na jejich základě frontendovou aplikaci postupně zdokonaloval.

(32)

6.4. Automatizované testování frontendu webové aplikace Adgame (Bc. Dominik Renč, 2020)

Bakalářská práce Automatizované testování frontendu webové aplikace Adgame má k této bakalářské práci stejný vztah, jako předchozí uvedená práce. Hlavním rozdílem však bylo, že zde probíhalo testování automatizovaně a testována byla hlavně správná funkčnosti frontendové aplikace. Testování bylo uskutečněno za pomoci nástroje Selenium IDE.

(33)

7. Implementace datové vrstvy a komunikace s backendovou částí

Na úplném počátku implementace jsem si musel důkladně nastudovat podklady pro Adgame. Podklady byly různých typů, ale nejčastěji jsem čerpal z backendové dokumentace pro REST API a webové sockety, abych si udělal jasno v tom, jakou

strukturu budou data mít. Pro správnou implementaci bylo třeba pochopit celý proces hry i z pohledu uživatele. Na to jsem využíval připravené grafické návrhy ve Figmě, které se daly proklikávat v logické návaznosti. V průběhu celého procesu byla velmi nápomocná i komunikace s týmem Adgame, kde jsem si ujasňoval veškeré náležitosti.

Dále jsem v rámci Vue.js zvolil technologie, které se dle mého průzkumu jevily jako ty nejvhodnější. Nejpodstatnější technologickou volbou byla technologie pro frontendovou datovou vrstvu, protože ta ovlivňuje celý proces nejvíce. Důvody pro zvolení každé technologie bylo popsáno v předchozích kapitolách. Pro tuto práci byla však volba přístupů k implementaci stejně důležitá jako volba technologií. Adgame je svou velikostí totiž rozsáhlá aplikace a začít bezhlavě programovat by bylo nemoudré z pohledu

dlouhodobé udržitelnosti.

Celý proces implementace je závislý na komunikaci s backendem, na získávání datech a na posílání požadavků. Jako první jsem se tedy rozhodl zaměřit na tuto část. Před vývojem jsem se zároveň snažil zamyslet nad nejlepšími běžnými přístupy pro vývoj v dané problematice, v angličtině zvané „best practices“. Jejich dodržením se snižuje riziko případných problémů, které mohou při vývoji vznikat.

Jedním z nejdůležitějších konvencí pro tento projekt je fakt, že jediným zdrojem pravdy je centralizovaná datová vrstva v podobě Vuex store. Komponenta si nikdy sama o sobě nepřistupuje k datům přímo z backendu a ani s nimi nemanipuluje. Tak lze dosáhnout konzistentnosti dat skrze celou aplikaci a vyvarovat se problémům.

Dalším z těchto pravidel je „don’t repeat yourself“, které se zaměřuje na navržení kódu tak, aby byl co nejvíce znovupoužitelný a neobjevoval se v aplikaci duplikovaně. To má za účel zefektivnění vývoje, větší přehlednost a jednodušší debuggování. S pamatováním na toto pravidlo jsem se jako první rozhodl vytvořit rozhraní pro komunikaci s REST API.

7.1. Frontendové rozhraní pro komunikaci s REST API

Požadavky na REST API je možné za pomocí axiosu vytvářet kdekoliv v aplikaci. Různé endpointy je však možné volat vícekrát na různém místě, a tak by docházelo k opakování toho stejného kódu. Kdyby pak například došlo ke změně endpointu, musel by se tento endpoint opravit na každém místě, kde byl využit. Z těchto důvodů jsem se rozhodl vytvořit za tímto účelem rozhraní.

Toto rozhraní přímo reflektuje dokumentaci dle Swaggeru a usnadňuje tak další postup při vývoji. Díky jasně definovaným funkcím a jejich argumentům toto rozhraní nabízí automatické doplňování kódu v podobě názvů dostupných funkcí včetně jejich argumentů.

(34)

V případě potřeby zavolání stejného endpointu na dvou různých míst se díky tomuto rozhraní předchází duplicity kódu.

Swagger obsahuje endpointy roztříděné do jednotlivých modulů, které byly seskupeny dle logické souvislosti. Ve frontendové aplikaci byla vyvořena samostatná složka „api“ a v rámci ní byl pro každý takový modul vytvořen vlastní soubor s odpovídajícím názvem.

V rámci každého takového souboru je defaultně vyexportována funkce, která přijímá první argument v podobě instance Axiosu a druhý volitelný pro nastavení URL cesty pro daný modul.

Instance axiosu je vytvářena ve svém vlastním souboru, ze kterého je defaultně exportována.

Samotná knihovnu Axios byla nainstalována pomocí NPM balíčkovacího systému a z toho i naimportována. Při vytváření instance je jí předáván parametr „baseUrl“, jenž nastavuje základní URL, na kterou se požadavky mají volat. Díky tomu již ji není třeba specifikovat při každém požadavku. Další customizací je rozšíření každého požadavku o logiku přidání zabezpečovacího tokenu, v tomto případě typu Bearer. Ten se získává z localStorage, kam se zapisuje po přihlášení a v případě jeho existence se připojil do hlavičky autorizace. Takto vytvořená instance se poté v „api/index.js“ souboru importuje a předává do všech naimportovaných zavolaných funkcí jednotlivých modulů API. Ty se na závěr vyexportují v podobě objektu, aby byly jednoduše přístupné.

Na výstupu každé funkce API modulu je objekt. Ten obsahuje jednotlivé funkce, jejichž klíč odpovídá názvům ze Swaggeru a pomocí instance axiosu volá na API požadavek s daným endpointem, včetně předaných argumentů. Výsledek tohoto požadavku poté pouze vrátí na výstupu a nijak s ním dále nepracuje. K endpointu se přidává již zmíněný druhý argument cesty, který je zpravidla společný a nemusí se tak při každém požadavku opakovat.

Vzhledem k tomu, že požadavek na API je asynchronní operací, všechny funkce jsou definované jako „async“, jinak by se při jejich zpracování nebralo ohled na jejich asychronicitu a v kódu nebylo možné počkat na jejich dokončení.

Výpis 15 Ukázka kódu api rozhraní pro získání týmových produktů (vlastní zpracování) export default (axios, path = '/product') => ({

findSoldProductsForTeam: async (teamId) => {

return await axios.get(`${path}/team/${teamId}/purchases`) },

Výpis 16 Zjednodušená ukázka kódu importování a exportování API modulů (vlastní zpracování) import axios from '../axios'

import Product from './product' export default {

product: Product(axios), }

(35)

Obrázek 10 Struktura adresáře api rozhraní (vlastní zpracování)

7.2. Implementace datové vrstvy v podobě Vuex

Tou náročnější částí tohoto projektu bylo správné navrhnutí datové vrstvy, ve které by se ukládala a spravovala data skrz celou frontendovou aplikaci. Pro dosažení konzistentnosti jsou veškeré požadavky na API volané v této části skrze připravené rozhraní popsáno v předchozí kapitole.

Největším problémem samostatných frontendových aplikací z pohledu datové vrstvy je udržení synchronního stavu dat jak na frontendové části, tak na té backendové. Obě tyto části si totiž drží svůj vlastní stav dat.

Datová vrstva je na frontendové části řešena v podobě knihovně Vuex. Ta je do aplikace registrována přímo při vzniku její instance a díky tomu je v rámci ní dostupná skrze kontext

„this“.

Vuex podporuje rozdělení store na moduly, čehož bylo v tomto projektu využito. Při menší složitosti dat jich není třeba využívat. V Adgame jsou však data rozdělena do mnoha logických celků. Kdyby store na moduly rozdělen nebyl, jeho stav by fungoval v jedné úrovni. To by bylo samo o sobě velkou nevýhodou, protože by spolu byl seskupený veškerý state, mutace, akce i gettery. Výsledkem by byl opravdu dlouhý a nepřehledný soubor, který by vůbec neulehčoval ve vývoji. I kdyby tedy moduly využity nebyly, bylo by třeba store rozdělit alespoň do vlastních souborů, které by se poté dohromady importovaly. Další nevýhodou by poté byla případná duplicita názvů. Díky tomu, že moduly jsou samostatné, se při práci s nimi bere ohled pouze na ten určitý modul a ostatní mu nepřekáží. Je však možné k nim přistupit, pokud to je žádoucí.

Moduly se obecně rozdělují tak, aby spolu byla seskupená data stejné stejného logického smyslu. Toto rozdělení již bylo vytvořeno backendovým týmem Adgame při vytváření REST

(36)

API. Stačilo tedy dodržovat toto již dané rozdělení, což mělo i svoje další výhody. Díky této pokračující konzistentnosti s dokumentací na Swaggeru mohou totiž další vývojáři rychleji pochopit strukturu a rozdělení datové vrstvy.

Pomocí „forEach“ cyklu je ke každému modulu přidaná funkce, jenž resetuje stav dat. To je globálně v tomto místě definováno pro předejití opakování kódu v každém modulu a převážně se užívá při dokončení hry. Stav dat by si její data pamatoval a je třeba každý modul resetovat pro předejití chyb při spuštění hry nové.

Každý modul má specifikován svůj základní stav v podobě objektu s názvem proměnné

„defaultState“, který má definované jednotlivé klíče a nastavené jejich prázdné hodnoty, které jsou určeny v závislosti na předpokládaném datovém typu. Tento počáteční stav se v případě zavolání resetovací funkce přepíše za stávající. Ten je při inicializaci modulu nastaven jako „state“, což je aktuální stav dat.

Dále mají moduly definované své akce, mutace a gettery. V projektu je aplikována konvence, dle které se veškeré úpravy stavu dat z komponent aplikace volají pomocí akcí, nikoliv přímo skrze mutace. Mutace jsou využity až v akcích. Tato konvence je důležitá z toho důvodu, aby bylo jasně definováno, kde se co odehrává. Uživatel svým kliknutím vždy chce docílit nějaké akce. Až samotná akce by měla změnu dat vyvolat. Samotná komponenta nemusí vědět, jak se bude stav dat upravovat, nebo do tohoto procesu zasahovat. Díky tomu jsou data vždy upravována předem definovaným způsobem a komponenta si se stavem dat nemůže dělat, co se jí zachce.

Struktura adresáře datové vrstvy je uvedena na následujícím obrázku. Store je rozdělen do složek místo jednotlivých souborů za účelem možnosti dělitelnosti kódu. Pokud by nějaký modul byl příliš obsáhlý, dal by se tak v rámci složky rozdělit na další jednotlivé soubory, jako třeba „actions.js“, „mutations.js“ a tak podobně, které by se dohromady naimportovaly opět v souboru store.js.

(37)

Obrázek 11 Struktura adresáře Vuex store (vlastní zpracování)

7.3. Implementace oboustranné komunikace

Komunikace s backendovou částí v reálném čase je řešena za pomocí webových socketů. Její implementace byla prováděna za pomocí API dokumentace o web socketech, jenž byla vytvořena autorem API.

Webové sockety lze využívat pro oboustrannou komunikaci, tedy z klienta na server i ze serveru na klienta. V případě Adgame však jsou využívány pouze pro jednosměrnou komunikaci, a to ze serveru na klienta.

Za účelem kompatibility s backendem byla pro implementace webových socketů využita technologie SockJS. Za pomocí balíčkovacího systému NPM byly nainstalovány knihovny

„sockjs-client“ a „@stomp/stompjs“. Ty byly ve vlastním souboru naimportovány a poté byla vytvořena nová instance klienta STOMP. Tomu se pro práci s webovými sockety nastavil SockJS pomocí „webSocketFactory“. Tímto způsobem byl připravený klient pro web sockety kompatibilní s backendovým API.

Aby mohl server klientovi nějaké zprávy posílat, je třeba nejprve ze strany klienta navázat spojení. Kvůli bezpečnosti může úspěšné navázání komunikace proběhnout pouze, pokud

(38)

je na frontendovém požadavku připojen v hlavičce Bearer token, jenž je získán po přihlášení.

Se socketovým klientem je potřeba pracovat v aplikaci na různých místech, a proto je ze svého souboru exportován opět v podobě objektu. Tento objekt slouží jako rozhraní pro práci s ním. Kromě samotného klienta totiž obsahuje další mnou napsané funkce, které s ním ulehčují práci.

Pokud je uživatel přihlášen, zavolá se na tomto rozhraní funkce „connect“ a klient naváže spojení se serverem. Toto spojení nějakou dobu trvá a na to je třeba brát ohled, jinak může docházet ke chybám. To bylo ve fázi vývoje zajímavou problematikou.

Jako příklad lze uvést fázi vývoje lobby. Pokud se uživatel přihlásil a ihned vybral hru, do které se chtěl připojit, z REST API mu přišla aktuální data o tomto lobby a ta se mu zobrazila. Chvilku poté se však mohl do hry připojit další hráč, který by se mu v lobby měl ukázat. Tato aktualizace již však nepřišla z REST API, ale skrze webové sockety. Pokud se však mezitím toto socketové spojení nestihlo navázat, zpráva klientovi nedorazila a ten tak nového hráče neviděl.

Z toho důvodu jsem implementoval asynchronní funkci „waitForConnection“, jenž vrací Promise, který je vyřešen až po navázání spojení. Požadavek na REST API je proveden až po spojení a díky tomu jsou data vždy aktuální.

Výpis 17 Ukázka kódu funkce vyčkání na socketové spojení (vlastní zpracování) waitForConnection: async () => {

return new Promise((resolve) => { if (stompClient.connected) { resolve()

} else {

stompClient.onConnect = resolve }

}) },

Server sám o sobě připojenému klientovi žádné zprávy neposílá. Zprávy totiž posílá na určité URL adresy, ke kterým se klient může přihlásit k odposlouchávání. V době mé implementace této práce byly dva typy adres odběru. Prvním typem byla hra a druhým tým.

Odběr hry probíhal na adrese „/game/{ID hry}“, kde „{ID HRY}“ bylo nahrazeno za ID hry, do které se uživatel připojil. Tento odběr se inicializoval ihned po připojení do lobby, protože již tam je komunikace v reálném čase potřeba pro synchronizaci hráčů, týmů a spuštění hry.

V průběhu již spuštěné hry se stará o přepínání jednotlivých kol, oznamuje manipulaci hry administrátorem a ukončení hry.

Odběr týmu se provádí na adrese „/team/{ID týmu}“ po spuštění hry a slouží ke všem týmovým aktualizacím. Těmi jsou nové produkty a kampaně, jejich úpravy či smazání a zobrazení nově zakoupených dat.

Oba tyto odběry je nutné udržet po celou dobu hry a v případě odpojení a znovupřipojení opět navázat. Neméně důležité je se z odběru po konci nebo opuštění hry odhlásit.

Odkazy

Související dokumenty

Cílem této práce byla implementace aplikace pro hraní logických her, která bude spustitelná na zařízeních se systémem android.. Práce zabývá systémem Android

Tématem této bakalářské práce je aplikace povinností zakladatele společnosti s ručením omezeným. Cílem bylo založení fiktivní firmy na základě aplikace

Cílem této bakalářské práce bylo charakterizovat způsob komunikace ve společnosti Hilti, přiblížit současný stav a navrhnout způsob marketingové komunikace

Cílem bakalářské práce bylo řešení implementace datové vrstvy a komunikace s backendovou aplikací na frontendové části webové aplikace ADgame.. Aplikace je vytvořena

Cílem práce bylo implementovat datovou vrstvu a komunikaci s backendovou aplikací na frontendové částí webová aplikace Adgame.. Ačkoli se práce nezakládá na

Název práce: Návrh a vývoj frontendové webové aplikace v Angularu Řešitel: Bc..

Cílem posuzované bakalářské práce byl návrh a implementace webové aplikace, která má sloužit pro jednoduchou administraci webové prezentace pro příspěvkovou organizaci

Hlavním cílem této práce je implementace prototypu aplikace pro propojení projektů, technologií a zaměstnanců založeném na technologii GraphQL, která bude