Your SlideShare is downloading. ×
DSL - DYI
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

DSL - DYI

417
views

Published on

Prezentacja pokazana na Confitura 2011

Prezentacja pokazana na Confitura 2011

Published in: Technology

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
417
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. DSL DYI...Domain Specific Languages Maciek Próchniak mpr@touk.pl 13 czerwca 2011
  • 2. DSL - Plan Co to jest DSL i do czego może się przydać Rodzaje DSL - dlaczego wewnętrzne, statycznie typowane? Klocki do budowy DSL Co dalej? Gdzie się zatrzymać?
  • 3. Maciek Próchniak Niedoszły topolog algebraiczny Kontrybutor Activiti Integracja: Servicemix, Camel, Drools, OSGi, BPEL... Rzeczy mniej przyjemne: GWT, Smartclient, ... Last but not least - TouK ;)
  • 4. DSL Domain Chcemy móc opisać obiekty, reguły z naszej dziedziny Specific Nie zaprzątając sobie głowy resztą świata Language W jakimś języku (programowania)
  • 5. DSL - czy nie mamy już wystarczająco dużo języków?
  • 6. GPL vs. DSL
  • 7. DSL - po co? Opisywanie reguł biznesowych Łatwiejesze przełożenie wymagań na kod Współpraca z ekspertami Zwiększona produktywność
  • 8. Kto korzysta z DSL? Programiści/Deweloperzy? PO/Eksperci biznesowi?
  • 9. Cobol fallacy ”Now we can get rid of programmers and have business people specify the rules themselves” - Cobol Fallacy wg. Martina Fowlera
  • 10. Znajomość czynna i znajomość bierna Znajomość bierna: ”Java je jedn´ z nejpouˇ´ ejˇ´ programovac´ jazyk˚ na ım zıvanˇ sıch ıch u svˇtˇ. Podle Tiobe indexu je Java nejpopul´rnˇjˇ´ programovac´ ee a e sı ı jazyk. (...) Dne 8. kvˇtna 2007 Sun uvolnil zdrojov´ kódy Javy (cca e e 2,5 milión˚ ˇ´dk˚ kódu) a Java bude d´le vyv´ u ra u a ıjena jako open source.” - http://cs.wikipedia.org/wiki/Java (programovac´ jazyk) ı Znajomość czynna? To już trudniejsze...
  • 11. DSL - po co? Opisywanie reguł biznesowych Łatwiejesze przełożenie wymagań na kod Współpraca z ekspertami Zwiększona produktywność
  • 12. Ale przecież mamy DDD? Bogaty model domenowy to podstawa DSL - ”widok” na model domenowy Model domeny to trudniejszy fragment
  • 13. Inny zestaw reguł Przy budowaniu DSL zwykle łamiemy ”żelazne” zasady: metody globalne/statyczne? CQS? prawo Demeter? ”małe” klasy?
  • 14. Inny zestaw reguł Potrzebne warstwy:
  • 15. DSL - ale jaki? zewnętrzny (external) SQL Regexp css schematy XML? wewnętrzny (embedded, DSEL) - jest osadzony w GPL Apache Camel Mockito JMock Rails
  • 16. Dlaczego wewnętrzne? Dostajemy ”za darmo”: Parser Kompilator Wsparcie IDE Rozszerzanie i obsługa niestandardowych przypadków
  • 17. Przykład: WS HumanTask Schemat XML opisu zadań do wykonania przez człowieka W typowym projekcie zadania są podobne Problem: jak zdefiniować typy właściwe dla konkretnego projektu
  • 18. Przykład: WS BPEL Schemat XML opisu działania procesu biznesowego Konieczność ujęcia wielu rodzajów akcji Problem: język staje się GPL
  • 19. Przykład pośredni: Drools Własny język definicji reguł Konieczność ujęcia wielu rodzajów akcji Korzyści: połączenie wyrażalności zewnętrznego DSL i możliwości Javy 1 r u l e AcceptOrder 2 when 3 $ c l i e n t : C l i e n t ( s t a t u s==APPROVED) 4 $ o r d e r : O r d e r ( s t a t u s== NEW, c l i e n t==$ c l i e n t ) 5 then 6 orderService . acceptOrder ( $order ) 7 end
  • 20. Dlaczego statycznie typowane? Języki dynamiczne oferują duże możliwości, ale: Wsparcie IDE Możliwości odkrywania API Każdy projekt trafi w końcu do studentów...
  • 21. Przykład - Apache Camel Implementacja wzorców EIP: router, splitter, aggregator, lista odbiorców, ... Definiowanie przepływów komunikacji Przykład: 1 c l a s s JamRouteBuilder extends R o u t e B u i l d e r { 2 public void c o n f i g u r e () { 3 from ( ” f i l e : / tmp/ i n ” ) 4 . convertBodyTo ( S t r i n g . c l a s s ) 5 . bean ( ” r e c i p i e n t R e p o s i t o r y ” ) 6 . r e c i p i e n t L i s t ( property (” recipients ” )); 7 } 8 }
  • 22. Płynny interfejs - klucz do sukcesu DSL Płynny interfejs Klasyczny model obiektowy
  • 23. Płynny interfejs - rozszerzony budowniczy 1 makeOrder (NORMAL) 2 . w i t h P r i c e ( new B i g D e c i m a l ( 2 2 . 0 0 ) ) 3 . w i t h D a t e ( ”2011−11−12” ) 4 . finish (); 1 p u b l i c O r d e r B u i l d e r makeOrder ( OrderType t y p e ) { 2 r e t u r n new O r d e r B u i l d e r ( t y p e ) ; 3 } 4 //w k l a s i e O r d e r B u i l d e r 5 public OrderBuilder w i t h P r i c e ( BigDecimal p r i c e ) { 6 this . price = price ; 7 return this ; 8 }
  • 24. Płynny interfejs - problem stopu 1 makeOrder (NORMAL) 2 . w i t h P r i c e ( new B i g D e c i m a l ( 2 2 . 0 0 ) ) 3 . w i t h D a t e ( ”2011−11−12” ) 4 . finish (); 1 p u b l i c Order f i n i s h ( ) { 2 return this . build () 3 }
  • 25. Płynny interfejs - problem stopu 1 makeOrder (NORMAL) 2 . w i t h P r i c e ( new B i g D e c i m a l ( 2 2 . 0 0 ) ) 3 . w i t h D a t e ( ”2011−11−12” ) 4 . withClientId (1334); Id klienta jest wymagane: 1 p u b l i c Order w i t h C l i e n t I d ( long l ) { 2 clientId = l ; 3 return this . build ( ) ; 4 }
  • 26. Płynny interfejs - wymuszanie kolejności 1 2 interface ClientPhoneBuilder { 3 S t r e e t B u i l d e r w i t h P h o n e ( S t r i n g phone ) ; 4 S t r e e t B u i l d e r withoutPhone ( ) ; 5 } 6 7 interface StreetBuilder { 8 ClientApartmentBuilder livingOn ( String street ); 9 C l i e n t homeless ( ) ;10 }11 ... 1 2 . w i t h P h o n e ( ” 2245556 ” ) . l i v i n g O n ( ” J e r o z o l i m s k i e ” ) .
  • 27. Płynny interfejs - zagnieżdżanie Możliwości: hierarchiczne buildery dodatkowe buildery
  • 28. Zagnieżdżanie builderów - hierarchie 1 . f i l t e r () 2 . x p a t h ( ” // o r d e r I d ” ) 3 . isEqualTo (15) 4 . send ( ” http : / / . . . ” ) 1 class RouteBuilder { 2 ... 3 ExpressionBuilder f i l t e r () { 4 t h i s . f i l t e r = new E x p r e s s i o n B u i l d e r ( t h i s ) ; 5 return this . f i l t e r ; 6 } 7 v o i d s e n d ( S t r i n g where ) { 8 ... 9 }
  • 29. Zagnieżdżanie builderów - hierarchie 1 . f i l t e r () 2 . x p a t h ( ” // o r d e r I d ” ) 3 . isEqualTo (15) 4 . send ( ” http : / / . . . ” ) 1 c l a s s E x p r e s s i o n B u i l d e r <T> { 2 3 T parent ; 4 5 E x p r e s s i o n B u i l d e r xpath ( S t r i n g xpath ) { 6 t h i s . e x p r e s s i o n = new X P a t h E x p r e s s i o n ( x p a t h ) ; 7 return this ; 8 } 9 T isEqualTo ( String value ) {10 t h i s . a s s e r t i o n = new E q u a l i t y ( v a l u e ) :11 return parent ;12 }13 }
  • 30. Zagnieżdżanie builderów - oddzielne buildery 1 2 c la s s SenderRouter extends RouteBuilder { 3 ... 4 . filter ( 5 x p a t h ( ” // o r d e r I d ” ) . i s E q u a l T o ( 1 5 ) 6 ) . send ( ” http : / / . . . ” ) 7 ... 8 E x p r e s s i o n B u i l d e r xpath ( S t r i n g xpath ) { 9 r e t u r n new X P a t h B u i l d e r ( x p a t h ) ;10 }11 } Obiekt kontekstu jest lepszy niż funkcje globalne 1 class XpathBuilder extends ExpressionBuilder { 2 Expression isEqualTo ( String value ) { 3 t h i s . a s s e r t i o n = new E q u a l i t y ( v a l u e ) : 4 return build ( ) ; 5 }
  • 31. Płynny interfejs - zagnieżdżanie hierarchiczne buildery lepszy dostęp do kontekstu lepsze podpowiedzi IDE dodatkowe buildery prostsze reużywalność rozszerzalność
  • 32. Co dalej? Cały czas dużo szumu syntaktycznego: 1 from ( ” s e d a : a ” ) 2 . choice () 3 . when ( h e a d e r ( ” f o o ” ) . i s E q u a l T o ( ” b a r ” ) ) 4 . to (” seda : b ”) 5 . otherwise () 6 . p r o c e s s ( new P r o c e s s o r ( ) { 7 p u b l i c v o i d p r o c e s s ( Exchange e x ) { 8 e x . s e t P r o p e r t y ( ” d a t e ” , new Date ( ) ) ; 9 }10 }); Tu kończą się możliwości Javy...
  • 33. Scala comes to the rescue! ”normalny” język: programowanie obiektowe statyczne typowanie można programować funkcyjnie prosty pattern matching dużo lukru syntaktycznego
  • 34. Scala comes to the rescue! uproszczenia składni, przeciążanie operatorów domyślne (implicit) konwersje i parametry funkcje i domknięcia
  • 35. Uproszczenia składni W wielu miejscach kropki i przecinki stają się opcjonalne: 1 order () 2 . s i z e ( 1 1 ) . express ( true ) A więc: 1 order () 2 s i z e 11 3 express true
  • 36. Przeciążanie operatorów Wszystko jest metodą 1 c l a s s Balance ( balance : BigDecimal ) { 2 d e f + ( toAdd : B a l a n c e ) : B a l a n c e = { 3 new B a l a n c e ( b a l a n c e+toAdd . g e t B a l a n c e ) } 4 def getBalance = balance 5 } A więc: 1 println 2 ( ( new B a l a n c e ( 1 0 ) + new B a l a n c e ( 1 0 ) ) . g e t B a l a n c e ) ;
  • 37. Domyślne konwersje Dodawanie metod do klas - monkey patching Języki dynamiczne robią to globalnie Jak można to zrobić bezpieczniej?
  • 38. Domyślne konwersje Dodajemy możliwość autokonwersji w obrębie danej klasy: 1 c l a s s Orders { 2 i m p l i c i t def stringToOrder ( s t r : String ) = 3 new O r d e r B u i l d e r ( s t r ) ; 4 } 5 6 class OrderBuilder ( c l i e n t : String ) { 7 var p r i c e : BigDecimal = 0; 8 def w i t h P r i c e ( newPrice : BigDecimal ) = 9 { p r i c e = newPrice ; b u i l d ; }10 def build = . . .11 }; I możemy napisać: 1 c l a s s VIPOrders extends Orders { 2 ” c l i e n t ” withPrice 1.22 3 }
  • 39. Przekazywanie strategii - funkcje i domknięcia Przekazywanie wyrażeń, predykatów - Java 1 . f i l t e r ( new E x p r e s s i o n ( ) { 2 p u b l i c b o o l e a n e v a l u a t e ( Message message ) { 3 r e t u r n VIP == message . g e t P r o p e r t y ( ” c l i e n t T y p e ” ) ; 4 } 5 }). Scala: 1 . f i l t e r { e x c h a n g e => 2 VIP==e x c h a n g e . g e t P r o p e r t y ( ” c l i e n t T y p e ” ) }
  • 40. Przekazywanie strategii - funkcje i domknięcia Przekazywanie wyrażeń, predykatów - Scala 1 ” d i r e c t : b” == { > 2 when ( . i n == ”< h a l l o />” ) { 3 −−> ( ”mock : b” ) 4 t o ( ”mock : c ” ) 5 } otherwise { 6 p r o c e s s ( e x => e x . s e t P r o p e r t y ( ” d a t e ” , new Date ( ) ) ) 7 } 8 t o ( ”mock : d” ) 9 }
  • 41. 1 case c l a s s SChoiceDefinition2 ( override val target : ChoiceDefinition ) . . . {3 override def otherwise = {4 target . otherwise5 this6 }78 o v e r r i d e d e f when ( f i l t e r : Exchange => Any ) = {9 val predicate = PredicateBuilder . toPredicate ( f i l t e r )10 t a r g e t . when ( p r e d i c a t e )11 this12 }13 }
  • 42. Granice czytelności i wyrażalności Język naturalny:1 Stworz zamowienie2 d l a k l i e n t a ”TouK” Fleksja? Synonimy? Koniugacja?
  • 43. O jeden krok za daleko? Definiowanie 1 class OrderBuilder ( c l i e n t : String ) { 2 var nameField : S t r i n g = ””; 3 def name = { n a m e F i e l d = } 4 def with a = t h i s ; 5 }; By napisać 1 c l a s s VIPOrders extends Orders { 2 ” c l i e n t ” . w i t h a name ” a l a ” ; 3 }
  • 44. Rozwój - rozszerzanie
  • 45. Rozszerzanie - przykład DSL do bardzo prostych procesów stanowych interakcje oparte na Apache Camel 1 s t a r t ( ” d i r e c t : employee ” ) . f o r k ( 2 s t a t e ( ” h r S t a r t ” ) . to ( ” f i l e :/// hr ” ) 3 . w a i t S t a t e ( ” waitingForHR ” , ” f i l e :/// h r I n ” ) 4 . s t a t e ( ” hrEnd ” ) , 5 s t a t e ( ” i t S t a r t ” ) . to ( ” f i l e :/// i t ” ) 6 . waitState (” waitingForIT ” ,” f i l e :/// i t I n ”) 7 . state (” itEnd ”) 8 ) . s t a t e ( ” end ” ) ;
  • 46. Rozszerzanie - przykład Trudno ”wpiąć” się ze swoimi rozszerzeniami Problem: Użycie zagnieżdżonych builderów Możliwe rozwiązania: Używanie oddzielnych builderów i obiektu kontekstu Nadpisanie pewnej części źródłowego DSL - może być skomplikowane
  • 47. Podsumowując... DSL może zwiększyć czytelność i zwięzłość kodu Wewnętrzne DSLe w statycznie typowanych językach mają niski koszt budowy i nauki Korzystając ze Scali możemy zmniejszyć szum syntaktyczny w naszym DSLu Projektując DSL trzeba myśleć o jego rozwoju i możliwościach rozszerzania
  • 48. Literatura
  • 49. I inne zasoby http://weblogs.java.net/blog/carcassi/archive /2010/02/04/building-fluent-api-internal-dsl-java http://pragdave.blogs.pragprog.com/pragdave/2008/03/the- language-in.html http://www.infoq.com/articles/internal-dsls-java
  • 50. Dziękuję.
  • 51. Użyłem Zdjęć: http://www.flickr.com/photos/gibbons/2294375187/ http://www.flickr.com/photos/wwworks/2472232245/ http://www.flickr.com/photos/siomuzzz/2577041081/ http://www.flickr.com/photos/r4n/3049253551/ http://www.flickr.com/photos/neilwykes/3219711243/ http://www.flickr.com/photos/donsolo/3666985941/ http://www.flickr.com/photos/saeba/4214372479/ http://www.flickr.com/photos/maysbusinessschool/4948659050/ http://www.flickr.com/photos/pixelcore/91132699/ A I szablonu LTEXby mcl :)