Voi începe acest articol prin a defini acronimul DSL, care înseamnă Domain Specific Language, adică un limbaj creat pentru a lucra pe un domeniu specific, restrâns, de probleme. Un limbaj DSL contrastează cu un limbaj general GPL (General- Purpose Language), cu ajutorul căruia putem aborda orice tip de problemă, și nu doar o categorie de probleme. Pentru a concretiza, amintesc aici DSL-uri precum: HTML, grep, sed, GraphViz versus GPL-uri: C++, Java, Ruby etc.
Un anumit tip de DSL
De la început, țin să menționez că scopul articolului este de a vă semnala această opțiune, această perspectivă în abordarea unor domenii specifice, și sper ca imaginea de ansamblu creată să fie suficientă pentru a vă impulsiona să folosiți un DSL atunci când sunteți într-un context adecvat, în care un DSL se pretează mai mult decât un GPL.
Voi continua prin a preciza că mă voi axa aici în special pe un anumit tip de DSL, și anume acela de tip domain-specific modeling. Un astfel de DSL, de regulă, implică existența unor generatoare de cod sursă având ca sursă de generare codul DSL. Acest cod sursă generat este integrat în codul existent al aplicației.
De ce DSL?
Am acumulat experiență profesională activând în industrii în care software-ul dezvoltat era bazat, aș estima, în proporție de 99% pe limbajele convenționale, de tip GPL, C++ și Java.
În acest context profesional am cunoscut avantajele imense al folosirii unui DSL:
- reducerea complexității;
- creșterea vitezei de dezvoltare;
- producerea unui număr mult mai mic de erori în programare;
- o decuplare totală între business-logic și implementare.
Reducerea complexității
După cum sugerează și imaginea de ansamblu, codul sursă DSL, datorită faptului că limbajul DSL este anume conceput doar pentru un domeniu, este, de regulă, foarte compact.
Acest lucru aduce cu sine, inevitabil, o complexitate redusă. Având un grad de libertate oferit de limbaj mai redus, putem crea structuri de cod mult mai simple și, deci, mai puțin complexe.
Creșterea vitezei de dezvoltare
În principiu, investiția într-un DSL se pretează atunci când limbajul DSL combinat cu generatoarele de cod se folosește în mod repetat. Această reutilizare a DSL-ului se poate atinge în cazul folosirii lui de către mai mulți ingineri în cadrul firmei de dezvoltare de soluții software și/sau, de-a lungul timpului, de către mai mulți utilizatori ai produsului finit dezvoltat de firmă.
Inițial, e nevoie de un grup restrâns de experți pentru a face designul DSL-ul și a scrie generatoarele de cod, pentru ca apoi acest tool să poată fi folosit în mod repetat. Investiția din faza inițială se amortizează prin codul generat ulterior, prin calitatea codului generat și timpul redus de corectare a eventualelor bug-uri care ar apărea atunci când același cod ar fi scris de o multitudine de ingineri de software.
Producerea unui număr mult mai mic de erori în programare
Având în vedere că DSL-ul va fi scris de un grup restrâns de experți, care cunosc aplicația foarte bine, și erorile infiltrate în codul generat vor fi mult mai puține, semnificativ mai puține decât dacă același cod ar fi fost scris de ingineri, utilizatori care nu știu să interacționeze cu aplicația sau cu API-ul oferit de aplicație.
Decuplare între business-logic și implementare
Un alt aspect foarte important este că utilizatorii DSL-ului se vor putea concentra exclusiv asupra business-logic. Nivelul de abstracție oferit de DSL este unul foarte ridicat, iar codul de tip boilerplate code, de infrastructură, care să nu se referă la business- logic, va fi minim în DSL.
Aspectele de implementare sunt lăsate în proporție de 100% în seama celor ce au dezvoltat DSL-ul, grupului de experți.
Când se pretează folosirea unui DSL?
Criteriul obligatoriu în folosirea unui DSL este formalizarea, modelarea domeniului pe care urmează să se lucreze. La baza DSL-ului stă un entity model, un model static de obiecte peste care se vine cu un set de operații ce se aplică în mod frecvent și repetitiv.
Pe scurt, criteriile de orientare spre un DSL sunt:
- existența unui entity model;
- definirea unor operații peste model;
- aplicarea operațiilor în mod repetitiv.
Am să vă prezint acum o serie de tipare de aplicații care ne indică oportunitatea folosirii acestei rețete de dezvoltare de software:
- în primul rând, sunt aplicațiile care folosesc deja explicit un entity model într-o formă oarecare, cum ar fi: baza de date SQL, non-SQL, XML, EMF (Eclipse Modelling Framework) etc. Acest model este, de obicei, o formă de modelare a elementelor de business-logic, dar conține, în cele mai multe cazuri, și aspecte interne de implementare. În acest caz se poate evolua mai ușor spre o concentrare exclusivă pe business-logic printr-un DSL.
- aplicațiile care vor să ofere utilizatorilor un engine de procesare, un limbaj restrâns
de scripting. Acest engine de procesare poate fi scris complet în DSL. În acest caz sunt soluții DSL, cum vom vedea apoi, care oferă out of the box și un editor specializat pentru DSL, în speță pentru engine-ul oferit. - aplicațiile care vor să ofere o alternativă la API-ul standard existent în GPL unor utilizatori mai puțin familiarizați cu mediile de dezvoltare de software, dar care vor să interacționeze cu aplicația prin dezvoltare de biblioteci, extensii de aplicații.
Cum dezvoltăm un DSL?
Deși există pe piață mai multe alternative ce permit dezvoltarea unui DSL, mă voi concentra aici pe o soluție care a ajuns la o anumită maturitate, are o comunitate online semnificativă și oferă suport pentru multe aspecte conexe cu un DSL. Această soluție se numește Xtext.
Xtext
În Xtext, modul standard de lucru este de a defini gramatica limbajului DSL. Există și
posibilitatea de a importa modele existente. Ca exemplu, eu am folosit un proiect ce vine deja cu Xtext, și anume Home Automation, pe care l-am modificat ușor. Gramatica pentru acest DSL arată în felul următor:
Aici se definește o entitate Device care poate avea mai multe stări. Limbajul DSL va avea drept cuvinte cheie „Device”, „can”, „be”.
Xtext va genera automat din această gramatică un editor specific DSL-ului pe care tocmai îl definim. Acest editor vine cu o serie de facilități specifice editoarelor moderne pentru limbaje de programare, cum ar fi: syntax coloring, error checking, auto-completion, formatting, go to declaration etc. Deci zero efort pentru a obține un editor foarte puternic al DSL-ului.
În plus, acest editor, ca și foarte multe alte facilități, poate fi reconfigurat de noi, Xtext oferind numeroase hook-uri în acest sens.
În figura următoare aveți un screenshot al editorului generat automat:
Un alt aspect foarte important este generatorul de cod. Xtext vine la pachet cu un motor de generare de cod foarte puternic și ușor de utilizat, bazat pe Xtend. Xtend este o extensie a limbajului Java. După cum observați în screenshot, generatorul de cod a generat pentru fiecare Device o clasă în Java. Acest cod se poate integra într-o aplicație. În același timp, putem avea mai multe generatoare care pot genera cod sursă pentru alte limbaje sau chiar documentație în format HTML.
La fel de important este faptul că aceste generatoare de cod se pot integra ușor într-un build process ce va include codul generat într-o aplicație existentă.
Concluzie
Cu cât se atinge un nivel de abstracție mai ridicat și mai apropiat de business-logic, cu cât se scrie mai puțin cod, cu atât se va lucra mai eficient, se vor face mai puține greșeli și vom avea o flexibilitate mai mare. Un DSL bine conceput ne permite să atingem astfel de țeluri. În cele mai multe cazuri, nu vom folosi doar un DSL pentru dezvoltarea unor soluții, dar el poate complementa un GPL în care se va dezvolta aplicația.