kpi

Magazín KPI

№ 7 / júl 2019

Doménovo-špecifický jazyk pre vývoj webových aplikácií

Spôsob vývoja dnešných webových aplikácií založený na trojvrstvových architektúrach pozostávajúcich zo serverovej a klientskej časti aplikácií prináša problémy s duplicitou kódu. Každá časť aplikácie môže byť implementovaná pomocou iného webového rámca. Nástroj BFI (Backend Frontend Interface), vyvinutý v rámci diplomovej práce, rieši problém s duplicitou dátového modelu generovaním jeho definície pre jednotlivé rámce na základe jednej špecifikácie a prináša so sebou aj ďalšie výhody ako napríklad generovanie komunikačného rozhrania, ktorým sa prenášajú dáta definované v tomto dátovom modeli.

Opis problému

Problémom pri vývoji webovej aplikácie, ktorej implementácia pozostáva z dvoch alebo viacerých častiach aplikácie, je duplicita kódu pri definovaní dátového modelu. Ak sú v rôznych častiach aplikácie použité rozličné webové rámce, ktoré sú napísané v rozličných programovacích jazykov, je nutné v každom z nich definovať dátový model a taktiež aj komunikačné rozhranie pre komunikáciu medzi nimi.

Duplicitne definovaný dátový model vnáša do aplikácie problém už v počiatočných fázach vývoja. Ako príklad je možné uviesť zmenu názvu entity alebo len zmenu názvu vlastnosti entity. Znamenalo by to zmeniť názov v klientskej aj v serverovej časti aplikácie a prispôsobiť zmenám aj komunikačné rozhranie. Ak by bola len jedna definícia, tak by bolo možné spraviť zmenu len na jednom mieste.

Backend Frontend Interface

Navrhnuté riešenie nazvané BFI (Backend Frontend Interface) rieši vyššie popísané problémy. Riešenie je implementované pomocou doménovo-špecifického jazyka BFI, ktorý umožňuje definovať jednotnú reprezentáciu dátového modelu. Na základe tejto definície a implementácie generátorov pre konkrétne webové rámce dokáže riešiť problém s duplicitou dátového modelu. Na základe definícií dátových modelov dokáže generovať aj komunikačné rozhranie.

Riešenie pozostáva z nasledujúcich častí:

  • jazyk BFI pre definíciu dátového modelu spolu s implementáciou editora,
  • šablónovací jazyk BFI,
  • rámec BFI, ktorý obsahuje implementáciu generátorov pre serverovú a klientskú časť aplikácie.

Konceptuálny model

Celkové riešenie popisuje diagram na nasledujúcom obrázku. Entita predstavuje definíciu dátového modelu, ktorá vstupuje do generátora implementovaného pomocou rámca BFI. Generátor na základe konfigurácie vytvorí dva projekty reprezentujúce serverovú a klientskú aplikáciu. Aplikácie budú používať rôzne webové rámce založené na architektúre MVC, ktoré podporuje generátor.

Konceptuálny model
Konceptuálny model

Generovaný kód sa generuje vždy po zmene definície dátového modelu. Zaujímavejší je však špecifický kód, tento kód sa vygeneruje len raz a to len v prípade, že ešte neexistuje, takže nebude nikdy prepísaný generátorom. Špecifický kód rozširuje funkcionalitu generovaného kódu (dedí od neho) a takto umožňuje programátorovi zmeniť alebo rozšíriť generovaný kód. Všade, kde sa má použiť generovaný kód, tak sa to robí prostredníctvom špecifického kódu.

Príklad

Následujúci zdrojový kód implementovaný v jazyku BFI pre definovanie dátového modelu prezentuje dve entity. Entita „User“ obsahuje vlastnosti ako napríklad „firstName“, „lastName“ a iné. Entita obsahuje aj vlastnosť odkazujúcu na entitu „Group“. Každá z vlastností entity pozostáva z jedinečného názvu v rámci entity, typu, popisu (label) a editoru. Vlastnosť okrem týchto atribútov môže obsahovať atribút „virtual“, ktorý hovorí o tom, že táto vlasnosť bude spracovávaná na základe funkcionality definovanej vo webovom rámci. Napríklad hodnota vlastnosti „fullName“ bude pravdepodobne vo webovom rámci vyskladaná z vlastností „firstName“ a „lastName“.

User
    firstName: string label="First name" editor=string
    lastName: string label="Last name" editor=string
    fullName: string label="Full name" editor=string virtual
    group: N:M(Group) label="Group name" editor=multiselec

Group
    name: string label="Group name" editor=string
    description: string label="Group descriptions" editor=string

Ako príklad je možné uviesť použitie dátového modelu vo webovom rámci Symfony. Vývojár dostal za úlohu implementovať vlasnosť „fullName“ entity „User“. Generovaný dátový model je reprezentovaný triedou „UserGenerate“. Zdrojový kód tejto triedy sa znovu vygeneruje pri každej zmene definícií dátového modelu. Existuje však trieda „User“, ktorá rozširuje triedu „UserGenerate“ a táto trieda sa vygeneruje len v prípade, ak neexistuje. Vývojár môže do triedy „User“ pridať definíciu algoritmu pre výpočet hodnoty novej vlastnosti „fullName“, ktorá bude používať vlastnosti „firstName“ a „lastName“. Tento princíp popisuje aj diagram generovaných tried zobrazený nižšie. Diagram prezentuje aj používanie vzťahov medzi jednotlivými dátovými entitami. Ak nejaká entita obsahuje vlastnosť, ktorá predstavuje vzťah s inou entitou, tak táto vlasnosť sa odkazuje výlučne na špecifický kód prezentujúci dátovú entitu v danom webovom rámci.

Diagram generovaných tried v rámci Symfony
Diagram generovaných tried v rámci Symfony

Vyššie popísaný princíp zaručuje používateľom BFI flexibilitu a dáva im možnosť nepriamo modifikovať funkcionalitu generovaného kódu prostredníctvom špecifického kódu. Implementáciu v špecifickom kóde generátor za žiadnych okolností nebude modifikovať.

Projekčný editor

Pre jednoduchšie používanie jazyka bol vyvinutý projekčný editor, ktorý je možné importovať ako rozšírenie do IDE od JetBrains. Editor bol vytvorený v JetBrains MPS, čo je vývojové prostredie pre vývoj jazykov a ich editorov. Projekčné editory, narozdiel od klasických textových editorov, upravujú priamo syntaktický strom a textová (alebo iná) reprezentácia kódu je iba jeho projekciou. Nástroj MPS bol vybraný hlavne pre jednoduchú integráciu s IDE od JetBrains, ktoré sú pri vývoji webových aplikácií často používané. Používanie projekčného editora prináša používateľom dobré predpoklady na naučenie sa syntaxe nového jazyka. Kontextové menu, zobrazené na nasledujúcom obrázku, poskytuje možnosť interakcie editora s používateľom. Zobrazený prvok „Generate Auth“ v kontextovom menu predstavuje možnosť vyvolania procesu generovania pre skupinu dátových modelov „Auth“, ktorá pozostáva okrem iných modelov aj z modelu „Group“.

Projekčný editor pre jazyk BFI na definovanie dátového modelu
Projekčný editor pre jazyk BFI na definovanie dátového modelu

Šablónovací jazyk

Šablónovací jazyk BFI je odlišný v závislosti od použitého webového rámca na klientskej strane aplikácie. Jazyk je však len rozšírenie HTML jazyka o elementy a atribúty s prefixom „bfi-“. Prostredníctvom týchto elementov a atribútov je umožnené referovať na vlasnosť dátového modelu a využívať pritom definície atribútov. Nasledujúci zdrojový kód ilustruje šablónovací jazyk BFI v implementácii využívajúcej rámec Angular:

<div class="row">
    <bfi-input bfi-model="User" bfi-field="name"></bfi-input>
</div>

Po spracovaní tejto šablóny sa vygeneruje nasledujúci kód prezentujúcu šablónu vo webovom rámci Angular:

<div class="row"> 
 <div>
  <label for="name">User name</label>
  <input type="text" name="name" id="name" [(ngModel)]="user.name">
 </div> 
<div>

Generovanie

To, čo bude BFI rámec generovať, určuje konkrétny generátor implementovaný pre daný webový rámec. Pre overenie použiteľnosti riešenia boli vytvorené dve implementácie pre webové rámce. Klientskú časť aplikácie zastúpil rámec Angular a serverovú časť rámec Symfony.

Pre rámec Angular sa generuje pre každý model celý komponent spolu so službami, ktoré obsahujú implementáciu pre klientskú stranu komunikácie REST. Používateľ BFI (vývojar) musí implementovať šablóny pre komponenty, prípadne vytvoriť ďalšie komponenty a použiť pripravené služby. Na implementáciu šablóny je možné použiť šablónovací jazyk BFI, v ktorom je možné sa odkazovať na vlastnosti modelu.

Pre webový rámec Symfony sú vygenerované nasledujúce časti:

  • Entity — dátový model,
  • Repository — triedy pre prácu s dátami,
  • Form — formuláre,
  • Controller — kontroléry.

Na základe dátového modelu, dokáže rámec vygenerovať databázové migrácie. Po spustení týchto migrácií sa vytvoria v databáze tabuľky, do ktorých je možné ukladať dáta reprezentované pomocou dátového modelu definovaného v jazyku BFI. Po vygenerovaní aplikácií v rámci Symfony bude mať používateľ k dispozícií rozhranie typu REST, ktoré však môže mimo generovaného kódu upravovať podľa potrieb.

Je možné implementovať generátory aj pre iné webové rámce, ak budú splnené nasledujúce predpoklady:

  1. Programovací jazyk, v ktorom je implementovaný rámec, musí podporovať objektové programovanie.
  2. Rámec použitý na serverovej časti musí poskytovať nástroj pre vytváranie databázových migrácií z entít.
  3. Použité rámce musia používať architektúru MVC.

Stiahnutie rámca

Rámec BFI je možné stiahnuť z repozitára na GitLabe KPI. K dispozícii je tiež systémová príručka opisujúca možnosť rozširovania o ďalšie implementácie pre webové rámce. Pre použitie už existujúcich implementácií (Symfony, Angular) pomôže používateľom príručka, ktorá obsahuje postupnosť krokov pri vytváraní a spúšťaný aplikácie implementovanej za pomoci BFI.

Ako príklad použitia je možné uviesť implementovanú aplikáciu „To-Do List“, ktorá bola implementovaná v BFI. Aplikácia pozostáva z troch častí:

  1. serverová časť implementovaná v rámci Symfony,
  2. klienstká čast implementovaná v rámci Angular,
  3. BFI časť, obsahujúca konfiguráciu, dátový model definovaný v jazyku BFI a použité generátory.

Záver

Toto riešenie bolo testované v spoločnosti GrownApps, ktorá sa venuje vývoju webových aplikácií. Ing. Tomášovi Putnoky (CTO spoločnosti) sa podarilo vytvoriť pomocou BFI jednoduchú aplikáciu „To-Do List“ za menej ako dve hodiny.

Weboví vývojári, ktorým bolo prezentované BFI si myslia, že používanie BFI v praxi na reálnych projektoch webových aplikácií by im ušetrilo čas, zefektívnilo ich prácu a zjednodušilo údržbu a ďalší vývoj aplikácií.

Používanie nástroja BFI prináša môže priniesť nasledujúce výhody:

  • rieši problém s duplicitou dátového modelu,
  • generuje komunikačné rozhranie medzi aplikáciami,
  • poskytuje možnosť odkazovania sa na vlastnosti dátového modelu pri implementácii grafického zobrazovania komponentov,
  • umožňuje generovanie kódu pre viaceré webové rámce,
  • umožňuje zmenu šablóny použitej pri generovaní bez zásahu do generátora.