Ráth István: Domain-specifikus nyelvek, 5perc++
Istvánt a novemberi meetup-on tartott előadásához kapcsolódó kérdésekkel kerestük meg. Reméljük, hogy a cikk alapján mindenkinek könnyebb lesz eldönteni, hogy használ-e ilyen eszközöket egy-egy konkrét projektben. Ha valaki nem látta volna az előadást, itt pótolhatja: videó, slideshow.
Másodlagos célunk ezzel a cikkel, hogy kipróbáljuk hogy tudná a blog kiegészíteni azt a bizonyos szűkös öt percet. Így nem csak Istvánnak, de mindannyiunknak tanulságosak lesznek a visszajelzések. Csapjunk is bele…..
- Egy általános módszert mutattál be nekünk a meetup-on, felsorolnád szerinted melyek a legfontosabb eszközök, amelyek domain specifikus nyelveket használnak?
Válasszuk ketté a kérdést. Domain-specifikus nyelvekkel sokféle eszközben találkozhatsz, ezek közül említettem is néhány példát az előadáson — a legnépszerűbbek a különféle grafikus felület tervezők (pl. a Visual Studioba integrált winforms designer, vagy Eclipse-ben a Visual Editor). Ide tartoznak a relációs adatbázis séma szerkesztők, stb. Gyakorlatilag bármi, ahol grafikus felületen valamilyen speciális szabályrendszer szerint szerkeszteni. Ebből is látszik, hogy itt nem egy forradalmi újdonságról van szó, hanem sokkal inkább egy már létező technológia továbbgondolásáról, “felokosításáról” — mint az általában igaz az informatikai fejlesztésekre.
Ez az “okosítás” pedig pontosan abban áll, hogy lehetővé tesszük a felhasználó (aki itt elsősorban fejlesztő, programozó) számára, hogy a saját problémájához, alkalmazási területéhez saját nyelvet, grafikus környezetet hozzon létre. Ezt persze az alapokról kezdve megtehetnénk a kedvenc programnyelvünkön is — a lényeg a _magas szintű_ támogatáson, a kész és követhető mintákon van, ettől lesz könnyű és egyszerűen használható a végtermék, ettől lesz a domain-specifikus nyelvek fejlesztését támogató környezet több, mint egy általános fejlesztő eszköz. Manapság szinte az összes népszerű fejlesztő környezethez elérhető ilyen támogatás:
- az IBM-es és open source világból származó Eclipse rendszer egyik alapeleme az Eclipse Modeling Framework, és az arra építő Graphical Modeling Framework. Ma, az ipari megoldások közül ezek nyújtják a legmagasabb szintű domain-specifikus modellezési támogatást. Segítségükkel könnyen, kattintgatással összerakhatunk egy editort szinte bármilyen nyelvhez — persze a szép megjelenéshez és egyéb finomságokhoz azért szükséges némi további programozás.
- a Microsoft “zászlóshajója”, a Visual Studio is tartalmaz ilyen támogatást, ott DSL Tools-nak hívják. Ez egyszerűbb megoldás az Eclipse-s technológiáknál, viszont - a Microsoftra véleményem szerint általában jellemző módon - nagyon szépen kidolgozott a grafikus megjelenést magas szinten támogató modul. Ezzel a nyelvi elemeink megjelenését a legapróbb részletekig testre szabhatjuk a Visual Studioba integrált kattintgatós felületen.
- újabban a Sun-féle NetBeans eszközben is találkozunk DSM-ekkel. A NetBeans GraphLib elsősorban a konkrét megjelenítés (gráf vizualizáció) segítésére szolgál, a modell tárolás (perzisztencia) megoldása metamodell alapon NetBeansben MDR-rel oldható meg. Itt tehát elég sokat kell programozni, ha valaki editort akar készíteni.
Az akadémiai eszközök közül (amelyeket nyilván sokkal kevesebben ismernek) a Vanderbilt University GME eszközét, és a McGill University AToM3-jét emelném ki. A BME-n pedig két társaság is foglalkozik ezzel a területtel, az egyik az Automatizálási és Alkalmazott Informatikai Tanszék, az ő eszközük a VMTS, a másik pedig mi, a Méréstechnika és Információs Rendszerek Tanszék, mi a VIATRA-t fejlesztjük (amely hivatalosan is az Eclipse egyik alprojektjének, a GMT-nek a része. Azonban mi (én
még adósak vagyunk egy rendes honlappal, de ezt hamarosan pótolni fogjuk.
- A fentiekhez képest mit tud az általatok fejlesztett rendszer?
Az összes tool tudja az “alapokat”, azaz meghatározhatod a nyelv elemeit és a létrehozási, szerkesztési szabályokat — ez alapján már egy alap grafikus szerkesztő automatikusan előáll. A toolok az erre épülő, extra szolgáltatásokban különböznek. A mi eszközünk specialitása abban rejlik, hogy kihasználjuk a mi szerkesztőnk alatt futó automatikus gráfmanipulációs rendszert olyan szolgáltatásokhoz, mint például egy dinamikus nyelv szimulációja (erről mindjárt többet), a kódgenerálás, vagy éppen az összetettebb nyelvi kényszerek vizsgálata.
Ezekről mondanék néhány szóval többet, egy kicsit messzebbről indulva. A domain-specifikus nyelvek önmagukban nem rosszak, hiszen az adott problématerület szabályai alapján rajzolhatunk velük grafikus modelleket. Szerintem a legjobb példa, ahol ez jól jön, a prototipizálás. Mindenki dolgozott már olyan megrendelővel, akinek van valamillyen “határozott” elképzelése arról, hogy mit akar. Ilyenkor mindenki rajzolgatni szokott, skiccelni, stb. A DSM-mel a skicceknek adhatunk egy erős technológiai alapot, illetve azokat rendesen kidolgozva készíthetünk olyan modellezési környezeteket, amelyekben olyan szakemberek is dolgozhatnak, akik a szoftverhez csak kevéssé értenek, viszont a problémát, amit a szoftverrel meg akarunk oldani, meg nagyon jól ismerik.
Egy értelmes továbblépés innen, hogyha meg akarjuk oldani, hogy a modelleket valahogyan fel is tudjuk használni a fejlesztés során. Tipikus feladat például, hogy a tervezők skicceiből a dokumentációba berakható UML modelleket készítsünk (pl. usecase, komponens, vagy akár osztálydiagramokat). Itt jön a képbe a modellek átalakítása, vagy ahogy mi hívjuk, a modelltranszformáció. Itt arról van szó, nagyon tömören, hogy az egyik fajta gráfból (domain-specifikus magas szintű modell) egy másikat készítünk (pl. UML modell, vagy adatbázis séma), programozott gráfmanipulációs műveletekkel. Ez így elsőre bonyolultan hangzik, és másodikra is
Azonban a gyakorlatunk azt mutatja, hogy ezt a feladatot még mindig egyszerűbb gráfátrajzolásként felfogva, egy speciális, erre kifejleszett programozási nyelvvel megoldani, mint mondjuk alacsonyszintű Java vagy C# programokkal (a kézi megoldás csak nagyon kicsi rendszereknél jön szóba). Ez a speciális nyelv a mi eszközünkben a VIATRA transzformációs nyelv, amely egy általános, deklaratív és imperatív elemeket is tartalmazó, nagy kifejező erejű nyelv. A deklaratív elemek alatt gráfmintákat kell érteni (mely a modellgráf egy apró részletét írja le, melynek előfordulásait a rendszer képes megtalálni), az imperatív elemek pedig műveleteket definiálnak, melyekkel átrajzolhatjuk a gráfot. Az egész alatt egy erős típusosságot támogató, hatékony modelltároló található, mely egyszerre képes többféle nyelvnek megfelelő modellgráfokat tárolni — ez kell ahhoz, hogy pl. kétféle ilyen modellezési nyelv között tudjunk “fordítani”. Itt kell megjegyezzem, hogy ez a rendszer önmagában is megállja a helyét, sőt
Sok kutatási projektünkben a modelltranszformáció sokkal hangsúlyosabb szerepet kap, mint a modellezés.
Na, és akkor hogy a hosszú gondolatmenet végére érjek: a domain-specifikus modellezés környékén előjön pár olyan nyitott kérdés, vagy technológiai kihívás, amely elég jól megfogalmazható ilyen modelltranszformációs feladatként. Az alapvető példa a kódgenerálás: ekkor egy magas szintű gráfmodell valamilyen szöveges megfelelőjét állítjuk elő. Egy népszerű példa, amire persze senki sem gondolna alapból modelltranszformációként: az XML fa szöveggé sorosítása. Ez úgy történik, hogy valahogyan bejárjuk a modellgráfot (XML fát), és az egyes elemekhez tartozó szöveget a kimenetre írjuk (pl. <elem attr1=”érték1″ attr2=”érték2″ />” stb).
A kódgenerálás ennek az általánosítása, ott ugyanis sokszor nem tisztán fa szerkezetű, hanem valamilyen bonyolultabb gráfot alkotó modellt kell (akár többször) bejárni, és előállítani a kimenetet. Példa: UML osztálydiagramból Java vagy C# kód generálása. Adatbázis séma diagramból SQL-DDL nyelvű leírás generálása. Ezek ugye az egyes eszközökben általában elérhető szolgáltatások, de mi van akkor, ha én a saját, mondjuk, az alkalmazásom képernyőit leíró mininyelvből szeretnék pl. Mobile Java kódot generálni? Előkaphatok valamilyen template engine-t, vagy mondjuk, ha már ott van a modellező környezetbe beépítve, a VIATRA rendszert, és írhatok egy néhány soros programot, ami végigmegy a gráfon és kiírja amit kell. Ilyen szolgáltatás - integráltan - tudtommal egyik napjainkban elérhető DSM modellező rendszerben sincs, az igazsághoz persze hozzá tartozik, hogy egy template engine-t, mellyel Java vagy C# szinten dolgozhatjuk fel a modelleket, bármelyik (nyílt) környezethez hozzá lehet illeszteni.
A modelltranszformáció persze nem csak erre használható. Definiálhatok vele a modelljeim (diszkrét) időbeli viselkedését leíró szabályrendszert (példa: rendszer állapotváltozásainak követése, felhasználó lépked a weboldalak között, stb), amelyet megfelelően bekonfigurálva a keretrendszer fel tud arra használni, hogy az editorban szimulációs lépéseket is tudjak tüzelni. Ez olyanoknak fontos, akik dinamikus rendszereket terveznek (pl. beágyazott vezérlők, egyszerű robotok), és ahol fontos, hogy már tervezés közben lehessen próbálgatni, hogy hogyan is fog a rendszer működni. Ilyen támogatás szintén ismeretlen a mai toolokban, a mienkben egy alap változat már működik.
Végezetül az összetett kényszerek kiértékelését említeném. Az alap módszerekkel, amelyeket az előadásban mutattam (metamodell) nem lehet minden szabályt leírni, amely a nyelvünkben betartandó. Például metamodellezéssel nem lehet olyat mondani, hogy a felhasználók életkora legalább 18, vagy hogy egy képernyőn egyszerre a rendelkezésre álló 25 féle elemből csak 3 félét használhatunk. Egyszerűen a metamodellezési technika kifejező ereje nem elég ehhez, pedig a gyakorlatban ezek igenis fontosak. Ezért a metamodelleket szokás kiegészíteni valamilyen kényszer leíró nyelvvel, amelyen ezeket a feltételeket is leírhatjuk (példa erre az Object Constraint Language, az OCL, amely UML modellekben használatos). Ezeket a kényszereket mi a VIATRA nyelven írjuk le, és a rendszer ellenőrizni tudja őket a modelleken — ez nem egyedülálló már, hiszen újabban az Eclipse környezetbe integrált EMF is tud OCL kényszereket ellenőrizni, és a VMTS is képes erre.
- Fel tudnál sorolni pár éles alkalmazást, amiben ezt a módszert alkalmaztátok?
A kutatócsoportunk fő profilja a különböző EU-s kutatási projektekben való részvétel (jelenleg hét ilyen projektben veszünk részt). Bizonyos fokig csalás azt mondani, hogy mindben felhasználtuk már valamilyen szinten, hiszen eleve olyanokra pályázunk, amelyek passzolnak a mi kompetenciánkhoz. Azonban mégis megemlítenék ezek közül egyet, a DECOS-t (Dependable Embedded Components and Systems), amely egy beágyazott rendszerek fejlesztésével foglalkozó, akadémiai és erős európai ipari partnerek bevonásával mostanra már végéhez ért projekt. Ebben kifejlesztettünk egy komplett tool-chaint, amely autó és repülőipari beágyazott rendszerek modell-alapú fejlesztését segíti domain-specifikus modellezési nyelvek és automatikus transzformációk segítségével. Az ebben összegyűlt tudást a gyakorlatban is használják olyan cégek mint például az AirBus, Audi, Hella, Infineon, Thales, vagy éppen a Liebherr.
Ipari alkalmazásban készítettünk már domain-specifikus modellezési környezetet munkafolyamat-optimalizáláshoz, illetve folyamatban van egy autóipari fejlesztésben érdekelt céggel közösen egy speciális modellezési környezet kialakítása is. Ezen kívül sok kisebb “magán” projektben alkalmaztam már ezt a technológiát.
- Mesélted, hogy a petri hálók készítését támogató eszközt a keretrendszeretekben pár szabály felvételével el lehet készíteni. Be tudnád mutatni, hogy megy ez pontosan? Jó lenne képernyőmentésekkel.
A petri háló kissé “akadémiai példa”, de emiatt ne rettenjetek rögtön meg
Ez egy amolyan “állatorvosi ló”, mivel elég egyszerű, tartozik hozzá dinamikus modellezés is, illetve egyéb, speciális tulajdonságai is vannak a nyelvnek, amivel a DSM eszközöket be lehet mutatni. A petri hálók nyelve egy nagyon egyszerű páros gráfot ír le, amelyben kétféle csomópont található: helyek és tranzíciók. Ezek között élek futnak, de mivel a gráf páros, ezért él csak hely és tranzíció között futhat, hely és hely, tranzíció és tranzíció között nem. Az előbb szándékosan hazudtam, van a gráfban egy harmadik féle csomópont is, a token, ezek a helyekben lehetnek — tehát a gráf hierarchikus, mert itt van benne egy tartalmazási viszony is. (A tokeneket nem mindig szokás külön csomópontként felvenni, sokszor csak azt tartjuk nyilván a helyek egy attribútumaként, hogy ott éppen hány darab token található). Az egész arra jó, hogy egy diszkrét állapotokkal rendelkező rendszer működését modellezzük vele, hiszen van a nyelvnek ún. dinamikus szemantikája, amely egy tüzelési szabályt ír le: hogyha egy tranzícióba mutató összes él kiinduló helyében van token, akkor a tranzíció tüzelése engedélyezett; a tüzelés után ezek a tokenek átkerülnek a tranzícióból kimutató élek célhelyeibe. Tehát ez egy ún. “token-game” nyelv, amely a rendszer állapotait (ha úgy tetszik, a rendszerváltozók értékeit) az egyes helyekhez rendelt tokenekkel reprezentálja. Hülyén hangzik, de hasznos nyelv: sokféle analízis módszert kifejlesztettek hozzá, amelyekkel megmondhatjuk például egy összetett, sok komponensből álló rendszer meghibásodási valószínűségét, vagy akár áteresztő képességét is.
És akkor a konkrét példa. Tegyük fel, hogy egy ilyen petri háló gráfokat szerkesztő és szimuláló környezetet akarunk készíteni. Első lépés a nyelvi metamodell felvétele (01_metamodel.png).
Ezen a képen az Eclipse rendszerben futó szerkesztőnket láthatjátok. Ez egy multitab szerkesztő, az egységes modellteret a Viatra modelspace, a domain-specifikus nézeteit (ahol csak az adott nyelvhez tartozó modellek láthatók és szerkeszthetők) a többi tab-ban lehet látni (pl. PetriNet, Sensoria, stb). Hozzá tartozik még az Outline és Properties nézetek. A képen látható tree view alapú szerkesztőben éppen a petri háló metamodellt nyitottam meg. Az egyes elemek neve mellett szögletes zárójelben látható, hogy pl. a Place az az általános gráf “Node” fogalmából származik, azaz ő egy csomópont (hasonlóan az OutArc — a petri hálóban a helyből tranzícióba vezető él — egy Edge, azaz él). A metamodell tartalmaz még néhány attribútumot is (properties) azonban ezekkel most nem foglalkozunk. A fentiek alapján világos a [containment] jelentése: egy olyan kapcsolatot jelöl (pl. a Place és Token között) amely tartalmazási viszonyt jelent (az egyes elemeknél a -> név az él célját jelöli, pl OutArc (-> Transition) jelentése: az OutArc típusú él csak Transition típusú csomópontba mutathat).
Ha ezzel megvagyunk, akkor rögtön előáll egy domain-specifikus tree view szerkesztő (mindenféle generálási stb lépés nélkül — ez a legtöbb eszközben nem így van, szinte mindig kódot kell generálni), amelyet a második képen láthatunk.
Ebben a domain-specifikus nézetet látjuk (az ikonokat persze azért meg kellett rajzolni hozzá :), amelyben a metamodellnek megfelelő szerkesztési műveleteket alkalmazhatunk csak.
Például, ahogy a képen is látszik, egy Place-be csak Token tehető, illetve felvehetünk egy belőle kiinduló OutArc élet — mást nem. Ez garantálja, hogy a felhasználó, a metamodell értelmében véve, csak helyes modellgráfokat rajzolhat. Ez nagyon fontos előny egy általános modellező eszközhöz képest, hiszen ha például a petri hálókat UML osztálydiagramként, az egyes osztályokat mondjuk place1, place2 stb-nek nevezve próbálnám megrajzolni, “hülyeséget” is rajzolhatnék (rossz helyre behúzott élek mint kapcsolatok, stb). Ez talán erőltetettnek hangzik, hiszen ki próbálna ilyet, de a gyakorlatban sokszor jobb híján az UML modelert veszik elő akkor, ha gyorsan rajzolgatni kell.
Ha a tree view alapú szerkesztés nem elég, akkor a következő lépés a grafikus szerkesztés. Ehhez a metamodell alapján már majdnem minden adott, az egyes elemek konkrét megjelenésének testre szabásához azonban egy kicsit programozni kell. A mi keretrendszerünk elég általános, ezért tkp. bármilyen, Eclipse-ben támogatott megjelenítő könyvtárat felhasználhatunk, a képen látható példa a Draw2D libraryvel készült. Ebben pl. a petri háló hely megjelenését (kör, benne és felette egy-egy label) összerakó kód kb 15 sor. Ha ez megvan, akkor van egy grafikus szerkesztőnk, amely szintén betartatja a metamodellben felvett szabályokat — például nem lehet csak úgy akárhova éleket behúzni.
Innentől jönnek az extrák. A fenti esetben szimulátort akartunk készíteni. Ehhez a nyelvhez tartozó tüzelési szabályt meg kell írni a VIATRA gráfmanipulációs nyelven, amelyből egy rövid példát láthattok az 5-ös képen.
Ez a program néhány gráfmintával és egyszerű vezérlési szerkezetekkel leírja azt a szabályt, amit fentebb elmondtam, és ezt megfelelően a keretrendszerbe bekötve kaphatunk egy szimulátort, amelyet a videón láthattok: itt. A videón egy egyszerű, konkurens műveleteket tartalmazó program viselkedését modellező petri háló látható; a tervező “live” próbálgathatja a szabályok elsütésével, hogy a rendszer hogyan is viselkedik.
A petri hálós példához konkrétan nem készítettem kódgenerátort, de hogy arról is legyen egy példa, nézzétek meg a 6-os képet.
Ezen a SENSORIA nevű EU-s projektünkhöz készített domain-specifikus editor és kódgenerátor egy részlete látható, amely szoftver-interfész leírásokat generál a komponenseket leíró modellgráfokból. A részletek itt nem érdekesek, a lényeg, hogy a generált kód ugyanabban a környezetben látható (Eclipse code output buffer view), amiben a programozó dolgozik, nem kell külső eszközöket hívogatni.
- Biztos gondolkoztál már rajta mi az a legtipikusabb feladat egy egyszerű fejlesztési projektben, amire érdemes bevetni az eszközötöket. Mi lenne az?
Bár ez nem jó önreklám, de hadd mondjam azt, hogy nem elsősorban a mi (kutatási) eszközünk bevetését javasolnám, hanem inkább magát a DSM technológiáét. Mostmár, ahogy a bevezetőben említettem, szinten minden népszerűbb környezetben elérhető ez a technológia, és azokhoz a megoldásokhoz jóval több support és dokumentáció tartozik, mint az akadémiai toolokhoz. Majd egyszer talán a mienkből is “termék” lesz, azonban ez az idő még nem jött el.
A kérdésre válaszolva: saját tapasztalatom alapján tudom, hogy a “kisebb” fejlesztések esetén ritka az, amikor az ember rendesen nekiáll tervezni, és dokumentálni. Ennek a fő oka az időhiány illetve a követelmények gyors változása (és az “informális” specifikáció, azaz ha a megrendelő naponta rádtelefonál és átvariálja az igényeket). Ilyenkor, a prototipizálási fázisban célszerű gyorsan összedobni egy mininyelvet, ami lefedi legalább azokat a területeket, ami az alkalmazás legfontosabb működéséhez tartozik, és ami a leggyorsabban változik. Ezt az editort aztán a közös megbeszéléseken lehet használni és akár a megrendelő kezébe is adható. Egy példa: amikor a BlueSpotot csináltuk, elgondolkodtam azon, hogy milyen jó lenne egy eszköz, amit András (interakció tervező) kezébe adva ő maga variálhatja át a képernyő terveket, és aztán nekem abból már csak minimális munkával generálni kell a képernyő kód nagy részét. Aztán persze időhiány miatt ez sem valósult meg
De azért egy fokkal kevésbe idő és erőforrás-megszorított projektben úgy gondolom, hogy van már létjogosultsága ennek a technológiának.
- Köszönjük, és reméljük hallunk még rólatok / tőletek
Akinek maradt még kérdése tegye fel itt, vagy keresse Istvánt. Elérhetőségei itt.





