Wstęp do DSL

Po przeczytaniu komentarza Jacka Laskowskiego na temat sposobów popularyzacji zadadnień tworzenia narzędzi eclipsowych, koncepcji MDD (Model Driven Development) czy DSM/DSL (Domain Specific Modeling) postanowiłem coś zrobić w tym temacie. Myślę że dobrym początkiem może być prosty tutorial.

Co jednak zaprezentować by jednocześnie wytłumaczyć podstawy zagadnienia a przy okazji wzbudzić zainteresowanie tematem? Jedno jest pewne - nie może to być generacja pustych interfejsów :) W internecie można znaleźć setki prostych kursów jak wygenerować schemat klas, bazy danych z modelu etc. Nuda. Postanowiłem pokazać coś innego, co moim zdaniem pozwoli lepiej reprezentować powyższe koncepcje. Zamiast modelować kod strukturalny stwórzmy kod logiki. Naszym zadaniem będzie utworzenie miniaturowego systemu który biznesowy opis (reguły rozsyłania wiadomości) przekształci w działający kod.

Wymagania dla zadania wyglądają następująco. Musimy utworzyć narzędzie pracujące na poziomie problemu (biznesowy opis zachowania) które będzie potrafiło generować coś zrozumiałego dla maszyny (kod wykonywalny). Czy to możliwe? Zobaczymy...

Jako platformę docelową wybrałem prosty silnik świadczący usługę rozsyłania wiadomości pomiędzy nazwanymi kolekcjami (taki uproszczony wzorzec rozsyłania wiadomości z EAI). Nasz silnik oczekuje jako swojej konfiguracji klas reprezentujących zasady działania (interfejs IRule). Reguły te modelowane będą za pomocą edytora pracującego według zasad opisanych poprzez pewien model (meta-model). Żeby nie komplikować wykorzystamy dynamiczny edytor Ecore. Nie jest to oczywiście rozwiązanie produkcyjne jednak na potrzeby prostego tutoriala wystarczy. Osoby zainteresowane tematem budowy własnych edytorów DSL odsyłam do swojej prezentacji z EclipseCamp 2008 (trzeba jakoś reklamować swojego bloga).

Przykładowy meta-model naszego języka zawiera zaledwie dwie proste reguły:
- skopiuj wszystko z kolekcji źródłowej do kolekcji docelowej
- rozbij kolekcję źródłową na podzbiory na podstawie wartości parametru.



Jak widać model nie jest zbyt zaawansowany. Fragment opisujący wyrażenie można nazwać co najwyżej "edukacyjnym", całość pozbawiona jest też nadrzędnego kontekstu. Podział oraz integracja modeli to temat złożony, wykraczający poza ramy tego kursu. Myślę jednak że na nasze potrzeby prosty meta-model w zupełności wystarczy.

Korzystając z edytora dynamicznego (opcja "Create Dynamic Instance") tworzymy dwie proste reguły:
- pobierz listę z kolekcji 'src' do kolekcji 'dst'
- pobierz listę klientów z kolekcji 'customers' i dorosłych umieść na 'adults', dzieci na 'children', nieprawidłowe elementy na 'unknown'



W trybie tekstowym utworzona instancja modelu powinna wyglądać następująco:



Ostatni krok to utworzenie szablonu generacji kodu. Nie jest to trudne. Kod który zostanie wygenerowany musi wykonywać operacje opisane przez meta-model. Utworzona instancja zawiera przykładowe wartości parametrów których użyjemy podczas testów. W naszym przypadku musimy zaimplementować prosty interfejs reguły (IRule) naszego silnika.



Pisanie szablonu rozpoczynamy od utworzenia testów. Ważne jest by nie starały się one weryfikować formatowania generowanego kodu ale logikę jego wykonania. Kod ten wielokrotnie może ulegać zmianom (optymalizacja etc.) jednak kontrakt z pozostałymi elementami systemu powinien być zachowany. W związku z tym w testach opisujemy tylko zasady interakcji z otoczeniem (nie tworzymy implementacji silnika etc.) Przykładowy test wygląda następująco:



Tworzenie testów pomaga nam lepiej zrozumieć problem jaki staramy się rozwiązać. Są one także niezmiernie pomocne w tropieniu literówek etc. Mając testy oraz przykładową instancję modelu bez trudu tworzymy prosty szablon kodu.



Testy zadziałały - zadanie zakończone ;D

Bardziej szczegółowe informacje znaleźć można na stronach www.eclipse.org/modeling. Jeżeli temat kogoś zainteresował fajnie byłoby gdyby dodał jakiś komentarz, będę wiedział czy warto go kontynuować (polecam także tutorial z AST jako wstęp do zagadnienie budowy notacji tekstowej dla modeli).