SlideShare a Scribd company logo
Guillaume Laforge / Groovy Project Manager / SpringSource

Practical Domain-Specific
Languages with Groovy
All the techniques to create your own DSL.



                                                      1
Guillaume Laforge
• Groovy Project Manager
• JSR-241 Spec Lead
• Head of Groovy Development
    at SpringSource
•   Initiator of the Grails framework
•   Co-author of Groovy in Action
•   Speaker: JavaOne, QCon, JavaZone, Sun TechDays,
    Devoxx, The Spring Experience, JAX, Dynamic
    Language World, IJTC, and more...
A few words about Groovy
• Groovy is a dynamic language for the JVM
 • with a Meta Object Protocol
 • compiles directly to bytecode, seamless Java interop
• Open Source ASL 2 project hosted at Codehaus
• Relaxed grammar derived from Java 5
 • + borrowed good ideas from Ruby, Python, Smalltalk
• Fast... for a dynlang on the JVM
• Closures, properties, optional typing, BigDecimal
  by default, nice wrapper APIs, and more...
a
       d
     n
    e
  g
A            • The context and
                 the usual issues we face
             •   Some real-life examples of
                 Domain-Specific Languages
             •   Groovy’s DSL capabilities
             •   Integrating a DSL
                 in your application
             •   Considerations to remember
                 when designing your own DSL
The context
Subject Matter Experts,
  Business analysts...
Developer producing
           LOLCODE



HAI
CAN HAS STDIO?
I HAS A VAR
IM IN YR LOOP
   UP VAR!!1
   VISIBLE VAR
   IZ VAR BIGGER THAN 10?
KTHXBYE
IM OUTTA YR LOOP
KTHXBYE
Lots of languages...
And in the end...
...nobody understands each other
Expressing requirements...
DSL: a potential solution?
• Use a more expressive language than a general purpose one

• Share a common metaphore of understanding between developers
  and subject matter experts

• Have domain experts help with the design of the business logic of
  an application

• Avoid cluttering business code with too much boilerplate
  technical code

• Cleanly separate business logic from application code

• Let business rules have their own lifecycle
Towards more readibility (1)
Towards more readibility (1)
Towards more readibility (1)



                               20%
Towards more readibility (2)
Towards more readibility (2)
Towards more readibility (2)




                          80%
a
       d
     n
    e
  g
A            • The context and
                 the usual issues we face
             •   Some real-life examples of
                 Domain-Specific Languages
             •   Groovy’s DSL capabilities
             •   Integrating a DSL
                 in your application
             •   Considerations to remember
                 when designing your own DSL
A collection of DSLs

• In our everyday life, we’re surrounded by DSLs
  • Technical dialects
  • Notations
  • Business languages
Technical dialects
SQL
^[w-.]+@([w-]){2,4}$
Notations
1. e4 e5
2. Nf3 Nc6
3. Bb5 a6
L2 U F-1 B L2 F B -1 U L2
Visual!
Business languages
Real-life Groovy examples
• Anti-malaria drug resistance simulation
• Human Resources employee skills representation
• Insurance policies risk calculation engine
• Loan acceptance rules engine for a financial platform
• Mathematica-like lingua for nuclear safety simulations
• Market data feeds evolution scenarios
• and more...
a
       d
     n
    e
  g
A            • The context and
                 the usual issues we face
             •   Some real-life examples of
                 Domain-Specific Languages
             •   Groovy’s DSL capabilities
             •   Integrating a DSL
                 in your application
             •   Considerations to remember
                 when designing your own DSL
A flexible & malleable syntax
• No need to write full-blown classes, use scripts
• Optional typing (def)
 • in scripts, you can even omit the def keyword
• Native syntax constructs
• Parentheses & semi-colons are optional
• Named arguments
• BigDecimal by default for decimal numbers
• Closures for custom control structures
• Operator overloading
Scripts vs classes
• Hide all the boilerplate technical code
 • an end-user doesn’t need to know about classes
  •   public class Rule {
          public static void main(String[] args) {
              System.out.println(“Hello”);
          }
      }

  • println   “Hello”
Optional typing
• No need to bother with types or even generics
 • unless you want to!
• Imagine an interest rate lookup table method
  returning some generified type:

  •   Rate<LoanType, Duration, BigDecimal>[]
           lookupTable() { ... }
      def table = lookupTable()

• No need to repeat the horrible generics type info!
Native syntax constructs
• Lists
 • [Monday, Tuesday, Wednesday]
• Maps
 • [CA: ‘California’, TX: ‘Texas’]
• Ranges
 • def bizDays = Monday..Friday
 • def allowedAge = 18..65
 • You can create your own custom ranges
Optional parens & semis
• Make statements and expressions
  look more like natural languages



 •   move(left);

 •move     left
Named arguments
• In Groovy you can mix named and unnamed
    arguments for method parameters
 •    named params are actually put in a map parameter
 •    plus optional parens & semis

•     take 1.pill,
       of: Chloroquinine,
    after: 6.hours

• Corresponds to a method signature like:
 • def     take(Map m, MedicineQuantity mq)
BigDecimal by default
• Main reason why financial institutions often decide to
    use Groovy for their business rules!
    • Although these days rounding issues are overrated!
• Java vs Groovy for a simple interpolation equation
•   BigDecimal uMinusv = c.subtract(a);
    BigDecimal vMinusl = b.subtract(c);
    BigDecimal uMinusl = a.subtract(b);
    return e.multiply(uMinusv)
            .add(d.multiply(vMinusl))
            .divide(uMinusl, 10, BigDecimal.ROUND_HALF_UP);

•   (d * (b - c) + e * (c - a)) / (a - b)
Custom control structures,
thanks to closures
 • When closures are last, they can be put “out” of the
     parentheses surrounding parameters

 •   unless (account.balance > 100.euros,
         { account.debit 100.euros })

 •   unless (account.balance > 100.euros) {
         account.debit 100.euros
     }

 • Signature def   unless(boolean b, Closure c)
Operator overloading
            • Currency amounts
 a+b          a.plus(b)

                            •
 a-b         a.minus(b)
                                15.euros + 10.dollars
 a*b      a.multiply(b)

                           • Distance handling
 a/b        a.divide(b)
 a%b        a.modulo(b)
                            •   10.kilometers - 10.meters
a ** b       a.power(b)
 a|b            a.or(b)
                           • Workflow, concurrency
 a&b           a.and(b)

                            •
 a^b           a.xor(b)         taskA | taskB & taskC
 a[b]        a.getAt(b)

                           • Credit an account
a << b   a.leftShift(b)
a >> b a.rightShift(b)
                            • account   << 10.dollars
  +a       a.positive()
                                account += 10.dollars
  -a       a.negative()
                                account.credit 10.dollars
  ~a   a.bitwiseNegate()
Groovy’s dynamic heart:

The MOP!
MetaObject Protocol
Groovy’s MOP
• All the accesses to methods, properties, constructors,
    operators, etc. can be intercepted thanks to the MOP
•   While Java’s behavior is hard-wired at compile-
    time in the class
•   Groovy’s runtime behavior is adaptable at
    runtime through the metaclass.
•   Different hooks for changing the runtime behavior
    • GroovyObject, custom MetaClass implementation,
      categories, ExpandoMetaClass
GroovyObject
• All instances of classes created in Groovy implement
  the GroovyObject interface:
  •   getProperty(String name)
  •   setProperty(String name, Object value)
  •   invokeMethod(String name, Object[]
      params)
  •   getMetaClass()
  •   setMetaClass(MetaClass mc)

• A GO can have “pretended” methods and properties
MetaClass
• The core of Groovy’s MOP system
  •   invokeConstructor()
  •   invokeMethod() and invokeStaticMethod()
  •   invokeMissingMethod()
  •   getProperty() and setProperty()
  •   getAttribute() and setAttribute()
  •   respondsTo() and hasProperty()

• MetaClasses can change the behavior of existing third-
  party classes — even from the JDK
ExpandoMetaClass
• A DSL for MetaClasses!
• MoneyAmount.metaClass.constructor   = { ... }
    Number.metaClass.getDollars = { ... }
    Distance.metaClass.toMeters = { ... }
    Distance.metaClass.static.create = { ... }

• To avoid repetition of Type.metaClass, you can pass a
    closure to metaClass { ... }
•   The delegate variable in closure represents the
    current instance, and it the default parameter
The Builder pattern
The Groovy MarkupBuilder
• def mkp = new MarkupBuilder()
  mkp.html {
      head {
          title “Groovy in Action”
      }
      body {
          div(width: ‘100’) {
              p(class: ‘para) {
                  span “Best book ever!”
              }
          }
      }
  }
A builder for HR
• softskills   {
      ideas {
          capture 2
          formulate 3
      }
      ...
  }
  knowhow {
      languages {
          java 4
          groovy 5
      }
      ...
  }
A builder for HR
• softskills   {
      ideas {
          capture 2
          formulate 3
      }
      ...
  }
  knowhow {
      languages {
          java 4
          groovy 5
      }
      ...
  }
Builders
• Builders are...
 • a mechanism for creating any tree-structered graph
 • the realization of the GoF builder pattern at the
      syntax level in Groovy
    • simply a clever use of chained method invocation,
      closures, parentheses omission, and use of the
      GroovyObject methods
•   Existing builders
    • XML, Object graph, Swing, Ant, JMX, and more...
The clever trick
• GroovyObject#invokeMethod() is used to catch all
    non-existing method calls in the context of the
    builder
•   The nesting of closures visually shows the level of
    nesting / depth in the tree
•   builder.m1(attr1:1, attr2:2, { builder.m2(..., {...}) }
    becomes equivalent to
    builder.m1(attr1:1, attr2:2) { m2(...) {...} }
    thanks to parens omission
Adding properties to numbers
• Three possible approaches
 • create a Category
   • a category is a kind of decorator for default MCs
 • create a custom MetaClass
   • a full-blown MC class to implement and to set on
       the POGO instance
 •   use ExpandoMetaClass
     • friendlier DSL approach but with a catch
With a Category
•   class DistanceCategory {
        static Distance getMeters(Integer self) {
            new Distance(self, Unit.METERS)
        }
    }

    use(DistanceCategory) {
        100.meters
    }


• Interesting scope: thread-bound & lexical
• But doesn’t work across the hierarchy of classes
 • ie. subclasses won’t benefit from the new property
With an ExpandoMetaClass
•   Number.metaClass.getMeters = {->
        new Distance(delegate, Unit.METERS)
    }

    100.meters


• Works for the class hierarchy for POJOs, and a flag
    exists to make it work for POGOs too
•   But the catch is it’s really a global change, so beware
    EMC enhancements collisions
Compile-time metaprogramming
• Groovy 1.6 introduced AST Transformations
• Compile-time == No runtime performance penalty!




                 Transformation
AST Transformations
• Two kinds of transformations
 • Global transformations
   • applicable to all compilation units
  • Local transformations
   • applicable to marked program elements
   • using specific marker annotations
Example #1: @Singleton
• Let’s revisit this evil{(anti-)pattern
   public class Evil
  

          public static final Evil instance = new Evil ();
          private Evil () {}
          Evil getInstance() { return instance; }
      }


• In Groovy
      @Singleton() class Evil {}
  




• Also a “lazy” version
      @Singleton(lazy = true) class Evil {}
  
Example #2: @Delegate
Not just for Managers
 • You can delegate to fields of your classes
   •   class Employee {
           def doTheWork() { “done” }
       }
       class Manager {
           @Delegate
           Employee slave = new Employee()
       }
       def god = new Manager()
       assert god.doTheWork() == “done”


 • Damn manager who will get all the praiser...
Global transformations
• Implement ASTTransformation
• Annotate the transfo specifying a compilation phase
•   @GroovyASTTransformation(phase=CompilePhase.CONVERSION)
    public class MyTransformation
        implements ASTTransformation {
        public void visit(ASTNode[] nodes, SourceUnit unit)
        { ... }
    }


• For discovery, create the file META-INF/services/
    org.codehaus.groovy.transform.ASTTransformation
•   Add the fully qualified name of the class in that file
Local transformations
• Same approach as Globale transformations
• But you don’t need the META-INF file
• Instead create an annotation to specify on which
  element the transformation should apply

• @Retention(RetentionPolicy.SOURCE)
  @Target([ElementType.METHOD])
  @GroovyASTTransformationClass(
      [quot;fqn.MyTransformationquot;])
  public @interface WithLogging {...}
Example: the Spock framework
• Changing the semantics of the original code
• But keeping a valid Groovy syntax
• @Speck
  class HelloSpock {
      def quot;can you figure out what I'm up to?quot;() {
          expect:
          name.size() == size

           where:
           name << [quot;Kirkquot;, quot;Spockquot;, quot;Scottyquot;]
           size << [4, 5, 6]
      }
  }
a
       d
     n
    e
  g
A            • The context and
                 the usual issues we face
             •   Some real-life examples of
                 Domain-Specific Languages
             •   Groovy’s DSL capabilities
             •   Integrating a DSL
                 in your application
             •   Considerations to remember
                 when designing your own DSL
Various integration mechanisms
• Java 6’s javax.script.* APIs (aka JSR-223)
• Spring’s language namespace
• Groovy’s own mechanisms
• But a key idea is to externalize those DSL programs
 • DSL programs can have their own lifecycle
 • no need to redeploy an application because of a
      rule change
  •   business people won’t see the technical code
Java 6’s javax.script.* API
• Groovy 1.6 provides its own implementation of the
  javax.script.* API

• ScriptEngineManager mgr =
          new ScriptEngineManager();
  ScriptEngine engine =
          mgr.getEngineByName(“Groovy”);

  String result = (String)engine.eval(“2+3”);
Spring’s lang namespace
• POGOs (Plain Old Groovy Objects) can be pre-
    compiled as any POJO and used interchangeably with
    POJOs in a Spring application
•   But Groovy scripts & classes can be loaded at runtime
    through the <lang:groovy/> namespace and tag
•   Reloadable on change
•   Customizable through a custom MetaClass
•   <lang:groovy id=quot;eventsquot;
        script-source=quot;classpath:dsl/eventsChart.groovyquot;
        customizer-ref=quot;eventsMetaClassquot; />
Groovy’s own mechanisms
• Eval
 • for evaluating simple expressions
• GroovyShell
 • for more complex scripts and DSLs
• GroovyClassLoader
 • the most powerful mechanism
Eval
• Simple mechanism to evaluate math-like formulas
•Eval.me  (                ‘3*4’)
  Eval.x (1,               ‘3*x + 4’)
  Eval.xy (1, 2,           ‘x + y’)
  Eval.xyz(1, 2, 3,        ‘x * y - z’)
GroovyShell
• A Binding provides a context of execution
 • can implement lazy evaluation if needed
• A base script class can be specified
• def binding = new Binding()
  binding.mass = 22.3
  binding.velocity = 10.6
  def shell = new GroovyShell(binding)
  shell.evaluate(“mass * velocity ** 2 / 2”)
GroovyClassLoader
• Most powerful mechanism
 • could also visit or change the AST
 • scripts & classes can be loaded from elsewhere
 • more control on compilation
• GroovyClassLoader gcl =
          new GroovyClassLoader();
  Class clazz = gcl.parseClass(
          new File(“f.groovy”));
  GroovyObject instance =
          (GroovyObject)clazz.newInstance();
  instance.setMetaClass(customMC);
Externalize business rules
• Although Groovy DSLs can be embedded in normal
    Groovy classes, you should externalize them
•   Store them elsewhere
    • in a database, an XML file, etc.
•   Benefits
    • Business rules are not entangled
      in technical application code
    • Business rules can have their own lifecycle,
      without requiring application redeployments
a
       d
     n
    e
  g
A            • The context and
                 the usual issues we face
             •   Some real-life examples of
                 Domain-Specific Languages
             •   Groovy’s DSL capabilities
             •   Integrating a DSL
                 in your application
             •   Considerations to remember
                 when designing your own DSL
Start small, with key concepts
Beware overengineering!
Grow your language progressively
Get your hands dirty
Play with the end-users
Let your DSL fly,
it’s not yours,
it’s theirs!
Tight feedback loop
Iterative process
Stay humble.
You can’t get it right the first time.
Don’t design alone at your desk
Involve the end users from the start
Playing it safe
in a sandbox
Various levels of                 sandboxing


• Groovy supports the usual Java Security Managers
• Use metaprogramming tricks to prevent calling /
  instanciating certain classes

• Create a special GroovyClassLoader AST code visitor
  to filter only the nodes of the AST you want to keep
  • ArithmeticShell in Groovy’s samples
Test, test, test!
 • Don’t just test for nominal cases
  • Explicitely test for errors!
 • Ensure end-users get meaninful error messages
a
       d
     n
    e
  g
A
             • Summary
             • Questions & Answers
Summary
• Groovy’s a great fit for Domain-Specific Languages
 • Malleable & flexible syntax
 • Full object-orientation
• Metaprogramming capabilities
 • Runtime metaprogramming
 • Compile-time metaprogramming
• Groovy’s very often used for mission-critical DSLs
?
I kan haz my cheezburgr naw?
 Or do ya reely haz keshtionz?
Appendix
•   http://www.flickr.com/photos/wheatfields/420088151/sizes/l/
•   http://www.flickr.com/photos/therefromhere/518053737/sizes/l/
•   http://www.flickr.com/photos/romainguy/230416692/sizes/l/
•   http://www.flickr.com/photos/addictive_picasso/2874279971/sizes/l/
•   http://www.flickr.com/photos/huangjiahui/3127634297/sizes/l/
•   http://www.flickr.com/photos/25831000@N08/3064515804/sizes/o/
•   http://www.flickr.com/photos/lanier67/3147696168/sizes/l/
•   http://www.flickr.com/photos/ktb/4916063/sizes/o/
•   http://www.flickr.com/photos/nathonline/918128338/sizes/l/
•   http://www.flickr.com/photos/kevinsteele/39300193/sizes/l/
•   http://commons.wikimedia.org/wiki/File:Brueghel-tower-of-babel.jpg
•   http://commons.wikimedia.org/wiki/File:Platypus.jpg
•   http://www.flickr.com/photos/joaomoura/2317171808/sizes/l/
•   http://www.flickr.com/photos/wiccked/132687067/
•   http://www.flickr.com/photos/xcbiker/386876546/sizes/l/
•   http://www.flickr.com/photos/pietel/152403711/sizes/o/
•   http://www.flickr.com/photos/forezt/192554677/sizes/o/
•   http://keremkosaner.files.wordpress.com/2008/04/softwaredevelopment.gif
•   http://www.jouy.inra.fr
•   http://www.flickr.com/photos/ejpphoto/408101818/sizes/o/
•   http://www.flickr.com/photos/solaro/2127576608/sizes/l/
•   http://www.flickr.com/photos/biggreymare/2846899405/sizes/l/
•   http://www.flickr.com/photos/timsamoff/252370986/sizes/l/
•   http://www.flickr.com/photos/29738009@N08/2975466425/sizes/l/
•   http://www.flickr.com/photos/howie_berlin/180121635/sizes/o/
•   http://www.flickr.com/photos/yogi/1281980605/sizes/l/
•   http://www.flickr.com/photos/dorseygraphics/1336468896/sizes/l/

More Related Content

What's hot

NextJS, A JavaScript Framework for building next generation SPA
NextJS, A JavaScript Framework for building next generation SPA  NextJS, A JavaScript Framework for building next generation SPA
NextJS, A JavaScript Framework for building next generation SPA
Pramendra Gupta
 
nginx 입문 공부자료
nginx 입문 공부자료nginx 입문 공부자료
nginx 입문 공부자료
choi sungwook
 
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
PgDay.Seoul
 
Cross-domain requests with CORS
Cross-domain requests with CORSCross-domain requests with CORS
Cross-domain requests with CORS
Vladimir Dzhuvinov
 
Express js
Express jsExpress js
Express js
Manav Prasad
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentationguest11106b
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Edureka!
 
Building Microservices with gRPC and NATS
Building Microservices with gRPC and NATSBuilding Microservices with gRPC and NATS
Building Microservices with gRPC and NATS
Shiju Varghese
 
Django로 쇼핑몰 만들자
Django로 쇼핑몰 만들자Django로 쇼핑몰 만들자
Django로 쇼핑몰 만들자
Kyoung Up Jung
 
Spring Framework - Validation
Spring Framework - ValidationSpring Framework - Validation
Spring Framework - Validation
Dzmitry Naskou
 
NextJS - Online Summit for Frontend Developers September 2020
NextJS - Online Summit for Frontend Developers September 2020NextJS - Online Summit for Frontend Developers September 2020
NextJS - Online Summit for Frontend Developers September 2020
Milad Heydari
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdf
Hyosang Hong
 
1.Startup JavaScript - 프로그래밍 기초
1.Startup JavaScript - 프로그래밍 기초1.Startup JavaScript - 프로그래밍 기초
1.Startup JavaScript - 프로그래밍 기초
Circulus
 
Introduction to VueJS & Vuex
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & Vuex
Bernd Alter
 
React js
React jsReact js
React js
Rajesh Kolla
 
Groovy Programming Language
Groovy Programming LanguageGroovy Programming Language
Groovy Programming Language
Aniruddha Chakrabarti
 
MongoDB performance
MongoDB performanceMongoDB performance
MongoDB performance
Mydbops
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
boyney123
 
React Server Side Rendering with Next.js
React Server Side Rendering with Next.jsReact Server Side Rendering with Next.js
React Server Side Rendering with Next.js
Jamie Barton 👨🏻‍💻
 
Angular 2 observables
Angular 2 observablesAngular 2 observables
Angular 2 observables
Geoffrey Filippi
 

What's hot (20)

NextJS, A JavaScript Framework for building next generation SPA
NextJS, A JavaScript Framework for building next generation SPA  NextJS, A JavaScript Framework for building next generation SPA
NextJS, A JavaScript Framework for building next generation SPA
 
nginx 입문 공부자료
nginx 입문 공부자료nginx 입문 공부자료
nginx 입문 공부자료
 
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
[pgday.Seoul 2022] POSTGRES 테스트코드로 기여하기 - 이동욱
 
Cross-domain requests with CORS
Cross-domain requests with CORSCross-domain requests with CORS
Cross-domain requests with CORS
 
Express js
Express jsExpress js
Express js
 
Hibernate Presentation
Hibernate  PresentationHibernate  Presentation
Hibernate Presentation
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
 
Building Microservices with gRPC and NATS
Building Microservices with gRPC and NATSBuilding Microservices with gRPC and NATS
Building Microservices with gRPC and NATS
 
Django로 쇼핑몰 만들자
Django로 쇼핑몰 만들자Django로 쇼핑몰 만들자
Django로 쇼핑몰 만들자
 
Spring Framework - Validation
Spring Framework - ValidationSpring Framework - Validation
Spring Framework - Validation
 
NextJS - Online Summit for Frontend Developers September 2020
NextJS - Online Summit for Frontend Developers September 2020NextJS - Online Summit for Frontend Developers September 2020
NextJS - Online Summit for Frontend Developers September 2020
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdf
 
1.Startup JavaScript - 프로그래밍 기초
1.Startup JavaScript - 프로그래밍 기초1.Startup JavaScript - 프로그래밍 기초
1.Startup JavaScript - 프로그래밍 기초
 
Introduction to VueJS & Vuex
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & Vuex
 
React js
React jsReact js
React js
 
Groovy Programming Language
Groovy Programming LanguageGroovy Programming Language
Groovy Programming Language
 
MongoDB performance
MongoDB performanceMongoDB performance
MongoDB performance
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
 
React Server Side Rendering with Next.js
React Server Side Rendering with Next.jsReact Server Side Rendering with Next.js
React Server Side Rendering with Next.js
 
Angular 2 observables
Angular 2 observablesAngular 2 observables
Angular 2 observables
 

Viewers also liked

(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
Alonso Torres
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
Guillaume Laforge
 
DSL's with Groovy
DSL's with GroovyDSL's with Groovy
DSL's with Groovy
paulbowler
 
Groovy workshop à Mix-IT 2013
Groovy workshop à Mix-IT 2013Groovy workshop à Mix-IT 2013
Groovy workshop à Mix-IT 2013
Guillaume Laforge
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013
Guillaume Laforge
 
Practical Domain-Specific Languages in Groovy
Practical Domain-Specific Languages in GroovyPractical Domain-Specific Languages in Groovy
Practical Domain-Specific Languages in GroovyGuillaume Laforge
 
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Guillaume Laforge
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
Paul King
 
Learn Java with Coursera
Learn Java  with  CourseraLearn Java  with  Coursera
Learn Java with Coursera
Ilya Lapitan
 
Groovy DSL
Groovy DSLGroovy DSL

Viewers also liked (10)

(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy(Greach 2015) Dsl'ing your Groovy
(Greach 2015) Dsl'ing your Groovy
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
 
DSL's with Groovy
DSL's with GroovyDSL's with Groovy
DSL's with Groovy
 
Groovy workshop à Mix-IT 2013
Groovy workshop à Mix-IT 2013Groovy workshop à Mix-IT 2013
Groovy workshop à Mix-IT 2013
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013
 
Practical Domain-Specific Languages in Groovy
Practical Domain-Specific Languages in GroovyPractical Domain-Specific Languages in Groovy
Practical Domain-Specific Languages in Groovy
 
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
Groovy DSLs, from Beginner to Expert - Guillaume Laforge and Paul King - Spri...
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
 
Learn Java with Coursera
Learn Java  with  CourseraLearn Java  with  Coursera
Learn Java with Coursera
 
Groovy DSL
Groovy DSLGroovy DSL
Groovy DSL
 

Similar to Practical Groovy DSL

GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume LaforgeGR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails Introduction
Eric Weimer
 
When To Use Ruby On Rails
When To Use Ruby On RailsWhen To Use Ruby On Rails
When To Use Ruby On Rails
dosire
 
Building DSLs On CLR and DLR (Microsoft.NET)
Building DSLs On CLR and DLR (Microsoft.NET)Building DSLs On CLR and DLR (Microsoft.NET)
Building DSLs On CLR and DLR (Microsoft.NET)Vitaly Baum
 
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume LaforgeGroovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Guillaume Laforge
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Development
wolframkriesing
 
Hacking with ruby2ruby
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2ruby
Marc Chung
 
Ruby on Rails Presentation
Ruby on Rails PresentationRuby on Rails Presentation
Ruby on Rails Presentation
Michael MacDonald
 
Groovy Up Your Code
Groovy Up Your CodeGroovy Up Your Code
Groovy Up Your Code
Paulo Traça
 
Web Development: The Next Five Years
Web Development: The Next Five YearsWeb Development: The Next Five Years
Web Development: The Next Five Years
sneeu
 
Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?
Patrick Chanezon
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
peter_marklund
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Railselliando dias
 
Migrating To Ruby1.9
Migrating To Ruby1.9Migrating To Ruby1.9
Migrating To Ruby1.9tomaspavelka
 
javascript teach
javascript teachjavascript teach
javascript teachguest3732fa
 
JSBootcamp_White
JSBootcamp_WhiteJSBootcamp_White
JSBootcamp_Whiteguest3732fa
 
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
Sang Don Kim
 
Android Bootcamp
Android   BootcampAndroid   Bootcamp
Android Bootcampahkjsdcsadc
 
How to build the Web
How to build the WebHow to build the Web
How to build the Web
Simon Willison
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Development
wolframkriesing
 

Similar to Practical Groovy DSL (20)

GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume LaforgeGR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
GR8Conf 2009: Practical Groovy DSL by Guillaume Laforge
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails Introduction
 
When To Use Ruby On Rails
When To Use Ruby On RailsWhen To Use Ruby On Rails
When To Use Ruby On Rails
 
Building DSLs On CLR and DLR (Microsoft.NET)
Building DSLs On CLR and DLR (Microsoft.NET)Building DSLs On CLR and DLR (Microsoft.NET)
Building DSLs On CLR and DLR (Microsoft.NET)
 
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume LaforgeGroovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Development
 
Hacking with ruby2ruby
Hacking with ruby2rubyHacking with ruby2ruby
Hacking with ruby2ruby
 
Ruby on Rails Presentation
Ruby on Rails PresentationRuby on Rails Presentation
Ruby on Rails Presentation
 
Groovy Up Your Code
Groovy Up Your CodeGroovy Up Your Code
Groovy Up Your Code
 
Web Development: The Next Five Years
Web Development: The Next Five YearsWeb Development: The Next Five Years
Web Development: The Next Five Years
 
Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Rails
 
Migrating To Ruby1.9
Migrating To Ruby1.9Migrating To Ruby1.9
Migrating To Ruby1.9
 
javascript teach
javascript teachjavascript teach
javascript teach
 
JSBootcamp_White
JSBootcamp_WhiteJSBootcamp_White
JSBootcamp_White
 
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
 
Android Bootcamp
Android   BootcampAndroid   Bootcamp
Android Bootcamp
 
How to build the Web
How to build the WebHow to build the Web
How to build the Web
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Development
 

More from Guillaume Laforge

Les nouveautés de Groovy 2 -- Mix-IT 2013
Les nouveautés de Groovy 2 -- Mix-IT 2013Les nouveautés de Groovy 2 -- Mix-IT 2013
Les nouveautés de Groovy 2 -- Mix-IT 2013
Guillaume Laforge
 
Groovy 2 and beyond
Groovy 2 and beyondGroovy 2 and beyond
Groovy 2 and beyond
Guillaume Laforge
 
Groovy 2.0 update at Devoxx 2012
Groovy 2.0 update at Devoxx 2012Groovy 2.0 update at Devoxx 2012
Groovy 2.0 update at Devoxx 2012Guillaume Laforge
 
Groovy 2.0 webinar
Groovy 2.0 webinarGroovy 2.0 webinar
Groovy 2.0 webinar
Guillaume Laforge
 
Groovy Domain Specific Languages - SpringOne2GX 2012
Groovy Domain Specific Languages - SpringOne2GX 2012Groovy Domain Specific Languages - SpringOne2GX 2012
Groovy Domain Specific Languages - SpringOne2GX 2012
Guillaume Laforge
 
Groovy update at SpringOne2GX 2012
Groovy update at SpringOne2GX 2012Groovy update at SpringOne2GX 2012
Groovy update at SpringOne2GX 2012
Guillaume Laforge
 
JavaOne 2012 Groovy update
JavaOne 2012 Groovy updateJavaOne 2012 Groovy update
JavaOne 2012 Groovy update
Guillaume Laforge
 
Groovy 1.8 et 2.0 au BreizhC@mp 2012
Groovy 1.8 et 2.0 au BreizhC@mp 2012Groovy 1.8 et 2.0 au BreizhC@mp 2012
Groovy 1.8 et 2.0 au BreizhC@mp 2012Guillaume Laforge
 
Groovy 1.8 and 2.0 at GR8Conf Europe 2012
Groovy 1.8 and 2.0 at GR8Conf Europe 2012Groovy 1.8 and 2.0 at GR8Conf Europe 2012
Groovy 1.8 and 2.0 at GR8Conf Europe 2012Guillaume Laforge
 
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume LaforgeGroovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
Guillaume Laforge
 
Groovy 2.0 - Devoxx France 2012
Groovy 2.0 - Devoxx France 2012Groovy 2.0 - Devoxx France 2012
Groovy 2.0 - Devoxx France 2012
Guillaume Laforge
 
Whats new in Groovy 2.0?
Whats new in Groovy 2.0?Whats new in Groovy 2.0?
Whats new in Groovy 2.0?
Guillaume Laforge
 
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011Guillaume Laforge
 
GPars et PrettyTime - Paris JUG 2011 - Guillaume Laforge
GPars et PrettyTime - Paris JUG 2011 - Guillaume LaforgeGPars et PrettyTime - Paris JUG 2011 - Guillaume Laforge
GPars et PrettyTime - Paris JUG 2011 - Guillaume LaforgeGuillaume Laforge
 
Groovy Update - Guillaume Laforge - Greach 2011
Groovy Update - Guillaume Laforge - Greach 2011Groovy Update - Guillaume Laforge - Greach 2011
Groovy Update - Guillaume Laforge - Greach 2011
Guillaume Laforge
 
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
Guillaume Laforge
 
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
Guillaume Laforge
 
Cloud foundry intro with groovy
Cloud foundry intro with groovyCloud foundry intro with groovy
Cloud foundry intro with groovyGuillaume Laforge
 
Groovy update - S2GForum London 2011 - Guillaume Laforge
Groovy update - S2GForum London 2011 - Guillaume LaforgeGroovy update - S2GForum London 2011 - Guillaume Laforge
Groovy update - S2GForum London 2011 - Guillaume Laforge
Guillaume Laforge
 
Groovy DSLs - S2GForum London 2011 - Guillaume Laforge
Groovy DSLs - S2GForum London 2011 - Guillaume LaforgeGroovy DSLs - S2GForum London 2011 - Guillaume Laforge
Groovy DSLs - S2GForum London 2011 - Guillaume Laforge
Guillaume Laforge
 

More from Guillaume Laforge (20)

Les nouveautés de Groovy 2 -- Mix-IT 2013
Les nouveautés de Groovy 2 -- Mix-IT 2013Les nouveautés de Groovy 2 -- Mix-IT 2013
Les nouveautés de Groovy 2 -- Mix-IT 2013
 
Groovy 2 and beyond
Groovy 2 and beyondGroovy 2 and beyond
Groovy 2 and beyond
 
Groovy 2.0 update at Devoxx 2012
Groovy 2.0 update at Devoxx 2012Groovy 2.0 update at Devoxx 2012
Groovy 2.0 update at Devoxx 2012
 
Groovy 2.0 webinar
Groovy 2.0 webinarGroovy 2.0 webinar
Groovy 2.0 webinar
 
Groovy Domain Specific Languages - SpringOne2GX 2012
Groovy Domain Specific Languages - SpringOne2GX 2012Groovy Domain Specific Languages - SpringOne2GX 2012
Groovy Domain Specific Languages - SpringOne2GX 2012
 
Groovy update at SpringOne2GX 2012
Groovy update at SpringOne2GX 2012Groovy update at SpringOne2GX 2012
Groovy update at SpringOne2GX 2012
 
JavaOne 2012 Groovy update
JavaOne 2012 Groovy updateJavaOne 2012 Groovy update
JavaOne 2012 Groovy update
 
Groovy 1.8 et 2.0 au BreizhC@mp 2012
Groovy 1.8 et 2.0 au BreizhC@mp 2012Groovy 1.8 et 2.0 au BreizhC@mp 2012
Groovy 1.8 et 2.0 au BreizhC@mp 2012
 
Groovy 1.8 and 2.0 at GR8Conf Europe 2012
Groovy 1.8 and 2.0 at GR8Conf Europe 2012Groovy 1.8 and 2.0 at GR8Conf Europe 2012
Groovy 1.8 and 2.0 at GR8Conf Europe 2012
 
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume LaforgeGroovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
Groovy 2.0 update - Cloud Foundry Open Tour Moscow - Guillaume Laforge
 
Groovy 2.0 - Devoxx France 2012
Groovy 2.0 - Devoxx France 2012Groovy 2.0 - Devoxx France 2012
Groovy 2.0 - Devoxx France 2012
 
Whats new in Groovy 2.0?
Whats new in Groovy 2.0?Whats new in Groovy 2.0?
Whats new in Groovy 2.0?
 
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011
Groovy Update, new in 1.8 and beyond - Guillaume Laforge - Devoxx 2011
 
GPars et PrettyTime - Paris JUG 2011 - Guillaume Laforge
GPars et PrettyTime - Paris JUG 2011 - Guillaume LaforgeGPars et PrettyTime - Paris JUG 2011 - Guillaume Laforge
GPars et PrettyTime - Paris JUG 2011 - Guillaume Laforge
 
Groovy Update - Guillaume Laforge - Greach 2011
Groovy Update - Guillaume Laforge - Greach 2011Groovy Update - Guillaume Laforge - Greach 2011
Groovy Update - Guillaume Laforge - Greach 2011
 
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
Gaelyk update - Guillaume Laforge - SpringOne2GX 2011
 
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
Groovy Update, what's new in Groovy 1.8 and beyond - Guillaume Laforge - Spri...
 
Cloud foundry intro with groovy
Cloud foundry intro with groovyCloud foundry intro with groovy
Cloud foundry intro with groovy
 
Groovy update - S2GForum London 2011 - Guillaume Laforge
Groovy update - S2GForum London 2011 - Guillaume LaforgeGroovy update - S2GForum London 2011 - Guillaume Laforge
Groovy update - S2GForum London 2011 - Guillaume Laforge
 
Groovy DSLs - S2GForum London 2011 - Guillaume Laforge
Groovy DSLs - S2GForum London 2011 - Guillaume LaforgeGroovy DSLs - S2GForum London 2011 - Guillaume Laforge
Groovy DSLs - S2GForum London 2011 - Guillaume Laforge
 

Recently uploaded

When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 

Recently uploaded (20)

When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 

Practical Groovy DSL

  • 1. Guillaume Laforge / Groovy Project Manager / SpringSource Practical Domain-Specific Languages with Groovy All the techniques to create your own DSL. 1
  • 2. Guillaume Laforge • Groovy Project Manager • JSR-241 Spec Lead • Head of Groovy Development at SpringSource • Initiator of the Grails framework • Co-author of Groovy in Action • Speaker: JavaOne, QCon, JavaZone, Sun TechDays, Devoxx, The Spring Experience, JAX, Dynamic Language World, IJTC, and more...
  • 3. A few words about Groovy • Groovy is a dynamic language for the JVM • with a Meta Object Protocol • compiles directly to bytecode, seamless Java interop • Open Source ASL 2 project hosted at Codehaus • Relaxed grammar derived from Java 5 • + borrowed good ideas from Ruby, Python, Smalltalk • Fast... for a dynlang on the JVM • Closures, properties, optional typing, BigDecimal by default, nice wrapper APIs, and more...
  • 4. a d n e g A • The context and the usual issues we face • Some real-life examples of Domain-Specific Languages • Groovy’s DSL capabilities • Integrating a DSL in your application • Considerations to remember when designing your own DSL
  • 6. Subject Matter Experts, Business analysts...
  • 7. Developer producing LOLCODE HAI CAN HAS STDIO? I HAS A VAR IM IN YR LOOP UP VAR!!1 VISIBLE VAR IZ VAR BIGGER THAN 10? KTHXBYE IM OUTTA YR LOOP KTHXBYE
  • 9. And in the end... ...nobody understands each other
  • 11. DSL: a potential solution? • Use a more expressive language than a general purpose one • Share a common metaphore of understanding between developers and subject matter experts • Have domain experts help with the design of the business logic of an application • Avoid cluttering business code with too much boilerplate technical code • Cleanly separate business logic from application code • Let business rules have their own lifecycle
  • 18. a d n e g A • The context and the usual issues we face • Some real-life examples of Domain-Specific Languages • Groovy’s DSL capabilities • Integrating a DSL in your application • Considerations to remember when designing your own DSL
  • 19. A collection of DSLs • In our everyday life, we’re surrounded by DSLs • Technical dialects • Notations • Business languages
  • 21. SQL
  • 24. 1. e4 e5 2. Nf3 Nc6 3. Bb5 a6
  • 25. L2 U F-1 B L2 F B -1 U L2
  • 28. Real-life Groovy examples • Anti-malaria drug resistance simulation • Human Resources employee skills representation • Insurance policies risk calculation engine • Loan acceptance rules engine for a financial platform • Mathematica-like lingua for nuclear safety simulations • Market data feeds evolution scenarios • and more...
  • 29. a d n e g A • The context and the usual issues we face • Some real-life examples of Domain-Specific Languages • Groovy’s DSL capabilities • Integrating a DSL in your application • Considerations to remember when designing your own DSL
  • 30. A flexible & malleable syntax • No need to write full-blown classes, use scripts • Optional typing (def) • in scripts, you can even omit the def keyword • Native syntax constructs • Parentheses & semi-colons are optional • Named arguments • BigDecimal by default for decimal numbers • Closures for custom control structures • Operator overloading
  • 31. Scripts vs classes • Hide all the boilerplate technical code • an end-user doesn’t need to know about classes • public class Rule { public static void main(String[] args) { System.out.println(“Hello”); } } • println “Hello”
  • 32. Optional typing • No need to bother with types or even generics • unless you want to! • Imagine an interest rate lookup table method returning some generified type: • Rate<LoanType, Duration, BigDecimal>[] lookupTable() { ... } def table = lookupTable() • No need to repeat the horrible generics type info!
  • 33. Native syntax constructs • Lists • [Monday, Tuesday, Wednesday] • Maps • [CA: ‘California’, TX: ‘Texas’] • Ranges • def bizDays = Monday..Friday • def allowedAge = 18..65 • You can create your own custom ranges
  • 34. Optional parens & semis • Make statements and expressions look more like natural languages • move(left); •move left
  • 35. Named arguments • In Groovy you can mix named and unnamed arguments for method parameters • named params are actually put in a map parameter • plus optional parens & semis • take 1.pill, of: Chloroquinine, after: 6.hours • Corresponds to a method signature like: • def take(Map m, MedicineQuantity mq)
  • 36. BigDecimal by default • Main reason why financial institutions often decide to use Groovy for their business rules! • Although these days rounding issues are overrated! • Java vs Groovy for a simple interpolation equation • BigDecimal uMinusv = c.subtract(a); BigDecimal vMinusl = b.subtract(c); BigDecimal uMinusl = a.subtract(b); return e.multiply(uMinusv) .add(d.multiply(vMinusl)) .divide(uMinusl, 10, BigDecimal.ROUND_HALF_UP); • (d * (b - c) + e * (c - a)) / (a - b)
  • 37. Custom control structures, thanks to closures • When closures are last, they can be put “out” of the parentheses surrounding parameters • unless (account.balance > 100.euros, { account.debit 100.euros }) • unless (account.balance > 100.euros) { account.debit 100.euros } • Signature def unless(boolean b, Closure c)
  • 38. Operator overloading • Currency amounts a+b a.plus(b) • a-b a.minus(b) 15.euros + 10.dollars a*b a.multiply(b) • Distance handling a/b a.divide(b) a%b a.modulo(b) • 10.kilometers - 10.meters a ** b a.power(b) a|b a.or(b) • Workflow, concurrency a&b a.and(b) • a^b a.xor(b) taskA | taskB & taskC a[b] a.getAt(b) • Credit an account a << b a.leftShift(b) a >> b a.rightShift(b) • account << 10.dollars +a a.positive() account += 10.dollars -a a.negative() account.credit 10.dollars ~a a.bitwiseNegate()
  • 39. Groovy’s dynamic heart: The MOP! MetaObject Protocol
  • 40. Groovy’s MOP • All the accesses to methods, properties, constructors, operators, etc. can be intercepted thanks to the MOP • While Java’s behavior is hard-wired at compile- time in the class • Groovy’s runtime behavior is adaptable at runtime through the metaclass. • Different hooks for changing the runtime behavior • GroovyObject, custom MetaClass implementation, categories, ExpandoMetaClass
  • 41. GroovyObject • All instances of classes created in Groovy implement the GroovyObject interface: • getProperty(String name) • setProperty(String name, Object value) • invokeMethod(String name, Object[] params) • getMetaClass() • setMetaClass(MetaClass mc) • A GO can have “pretended” methods and properties
  • 42. MetaClass • The core of Groovy’s MOP system • invokeConstructor() • invokeMethod() and invokeStaticMethod() • invokeMissingMethod() • getProperty() and setProperty() • getAttribute() and setAttribute() • respondsTo() and hasProperty() • MetaClasses can change the behavior of existing third- party classes — even from the JDK
  • 43. ExpandoMetaClass • A DSL for MetaClasses! • MoneyAmount.metaClass.constructor = { ... } Number.metaClass.getDollars = { ... } Distance.metaClass.toMeters = { ... } Distance.metaClass.static.create = { ... } • To avoid repetition of Type.metaClass, you can pass a closure to metaClass { ... } • The delegate variable in closure represents the current instance, and it the default parameter
  • 45. The Groovy MarkupBuilder • def mkp = new MarkupBuilder() mkp.html { head { title “Groovy in Action” } body { div(width: ‘100’) { p(class: ‘para) { span “Best book ever!” } } } }
  • 46. A builder for HR • softskills { ideas { capture 2 formulate 3 } ... } knowhow { languages { java 4 groovy 5 } ... }
  • 47. A builder for HR • softskills { ideas { capture 2 formulate 3 } ... } knowhow { languages { java 4 groovy 5 } ... }
  • 48. Builders • Builders are... • a mechanism for creating any tree-structered graph • the realization of the GoF builder pattern at the syntax level in Groovy • simply a clever use of chained method invocation, closures, parentheses omission, and use of the GroovyObject methods • Existing builders • XML, Object graph, Swing, Ant, JMX, and more...
  • 49. The clever trick • GroovyObject#invokeMethod() is used to catch all non-existing method calls in the context of the builder • The nesting of closures visually shows the level of nesting / depth in the tree • builder.m1(attr1:1, attr2:2, { builder.m2(..., {...}) } becomes equivalent to builder.m1(attr1:1, attr2:2) { m2(...) {...} } thanks to parens omission
  • 50. Adding properties to numbers • Three possible approaches • create a Category • a category is a kind of decorator for default MCs • create a custom MetaClass • a full-blown MC class to implement and to set on the POGO instance • use ExpandoMetaClass • friendlier DSL approach but with a catch
  • 51. With a Category • class DistanceCategory { static Distance getMeters(Integer self) { new Distance(self, Unit.METERS) } } use(DistanceCategory) { 100.meters } • Interesting scope: thread-bound & lexical • But doesn’t work across the hierarchy of classes • ie. subclasses won’t benefit from the new property
  • 52. With an ExpandoMetaClass • Number.metaClass.getMeters = {-> new Distance(delegate, Unit.METERS) } 100.meters • Works for the class hierarchy for POJOs, and a flag exists to make it work for POGOs too • But the catch is it’s really a global change, so beware EMC enhancements collisions
  • 53. Compile-time metaprogramming • Groovy 1.6 introduced AST Transformations • Compile-time == No runtime performance penalty! Transformation
  • 54. AST Transformations • Two kinds of transformations • Global transformations • applicable to all compilation units • Local transformations • applicable to marked program elements • using specific marker annotations
  • 55. Example #1: @Singleton • Let’s revisit this evil{(anti-)pattern public class Evil  public static final Evil instance = new Evil (); private Evil () {} Evil getInstance() { return instance; } } • In Groovy @Singleton() class Evil {}  • Also a “lazy” version @Singleton(lazy = true) class Evil {} 
  • 56. Example #2: @Delegate Not just for Managers • You can delegate to fields of your classes • class Employee { def doTheWork() { “done” } } class Manager { @Delegate Employee slave = new Employee() } def god = new Manager() assert god.doTheWork() == “done” • Damn manager who will get all the praiser...
  • 57. Global transformations • Implement ASTTransformation • Annotate the transfo specifying a compilation phase • @GroovyASTTransformation(phase=CompilePhase.CONVERSION) public class MyTransformation implements ASTTransformation { public void visit(ASTNode[] nodes, SourceUnit unit) { ... } } • For discovery, create the file META-INF/services/ org.codehaus.groovy.transform.ASTTransformation • Add the fully qualified name of the class in that file
  • 58. Local transformations • Same approach as Globale transformations • But you don’t need the META-INF file • Instead create an annotation to specify on which element the transformation should apply • @Retention(RetentionPolicy.SOURCE) @Target([ElementType.METHOD]) @GroovyASTTransformationClass( [quot;fqn.MyTransformationquot;]) public @interface WithLogging {...}
  • 59. Example: the Spock framework • Changing the semantics of the original code • But keeping a valid Groovy syntax • @Speck class HelloSpock { def quot;can you figure out what I'm up to?quot;() { expect: name.size() == size where: name << [quot;Kirkquot;, quot;Spockquot;, quot;Scottyquot;] size << [4, 5, 6] } }
  • 60. a d n e g A • The context and the usual issues we face • Some real-life examples of Domain-Specific Languages • Groovy’s DSL capabilities • Integrating a DSL in your application • Considerations to remember when designing your own DSL
  • 61. Various integration mechanisms • Java 6’s javax.script.* APIs (aka JSR-223) • Spring’s language namespace • Groovy’s own mechanisms • But a key idea is to externalize those DSL programs • DSL programs can have their own lifecycle • no need to redeploy an application because of a rule change • business people won’t see the technical code
  • 62. Java 6’s javax.script.* API • Groovy 1.6 provides its own implementation of the javax.script.* API • ScriptEngineManager mgr = new ScriptEngineManager(); ScriptEngine engine = mgr.getEngineByName(“Groovy”); String result = (String)engine.eval(“2+3”);
  • 63. Spring’s lang namespace • POGOs (Plain Old Groovy Objects) can be pre- compiled as any POJO and used interchangeably with POJOs in a Spring application • But Groovy scripts & classes can be loaded at runtime through the <lang:groovy/> namespace and tag • Reloadable on change • Customizable through a custom MetaClass • <lang:groovy id=quot;eventsquot; script-source=quot;classpath:dsl/eventsChart.groovyquot; customizer-ref=quot;eventsMetaClassquot; />
  • 64. Groovy’s own mechanisms • Eval • for evaluating simple expressions • GroovyShell • for more complex scripts and DSLs • GroovyClassLoader • the most powerful mechanism
  • 65. Eval • Simple mechanism to evaluate math-like formulas •Eval.me ( ‘3*4’) Eval.x (1, ‘3*x + 4’) Eval.xy (1, 2, ‘x + y’) Eval.xyz(1, 2, 3, ‘x * y - z’)
  • 66. GroovyShell • A Binding provides a context of execution • can implement lazy evaluation if needed • A base script class can be specified • def binding = new Binding() binding.mass = 22.3 binding.velocity = 10.6 def shell = new GroovyShell(binding) shell.evaluate(“mass * velocity ** 2 / 2”)
  • 67. GroovyClassLoader • Most powerful mechanism • could also visit or change the AST • scripts & classes can be loaded from elsewhere • more control on compilation • GroovyClassLoader gcl = new GroovyClassLoader(); Class clazz = gcl.parseClass( new File(“f.groovy”)); GroovyObject instance = (GroovyObject)clazz.newInstance(); instance.setMetaClass(customMC);
  • 68. Externalize business rules • Although Groovy DSLs can be embedded in normal Groovy classes, you should externalize them • Store them elsewhere • in a database, an XML file, etc. • Benefits • Business rules are not entangled in technical application code • Business rules can have their own lifecycle, without requiring application redeployments
  • 69. a d n e g A • The context and the usual issues we face • Some real-life examples of Domain-Specific Languages • Groovy’s DSL capabilities • Integrating a DSL in your application • Considerations to remember when designing your own DSL
  • 70. Start small, with key concepts Beware overengineering!
  • 71. Grow your language progressively
  • 72. Get your hands dirty Play with the end-users
  • 73. Let your DSL fly, it’s not yours, it’s theirs!
  • 75. Stay humble. You can’t get it right the first time. Don’t design alone at your desk Involve the end users from the start
  • 76. Playing it safe in a sandbox
  • 77. Various levels of sandboxing • Groovy supports the usual Java Security Managers • Use metaprogramming tricks to prevent calling / instanciating certain classes • Create a special GroovyClassLoader AST code visitor to filter only the nodes of the AST you want to keep • ArithmeticShell in Groovy’s samples
  • 78. Test, test, test! • Don’t just test for nominal cases • Explicitely test for errors! • Ensure end-users get meaninful error messages
  • 79. a d n e g A • Summary • Questions & Answers
  • 80. Summary • Groovy’s a great fit for Domain-Specific Languages • Malleable & flexible syntax • Full object-orientation • Metaprogramming capabilities • Runtime metaprogramming • Compile-time metaprogramming • Groovy’s very often used for mission-critical DSLs
  • 81. ? I kan haz my cheezburgr naw? Or do ya reely haz keshtionz?
  • 83. http://www.flickr.com/photos/wheatfields/420088151/sizes/l/ • http://www.flickr.com/photos/therefromhere/518053737/sizes/l/ • http://www.flickr.com/photos/romainguy/230416692/sizes/l/ • http://www.flickr.com/photos/addictive_picasso/2874279971/sizes/l/ • http://www.flickr.com/photos/huangjiahui/3127634297/sizes/l/ • http://www.flickr.com/photos/25831000@N08/3064515804/sizes/o/ • http://www.flickr.com/photos/lanier67/3147696168/sizes/l/ • http://www.flickr.com/photos/ktb/4916063/sizes/o/ • http://www.flickr.com/photos/nathonline/918128338/sizes/l/ • http://www.flickr.com/photos/kevinsteele/39300193/sizes/l/ • http://commons.wikimedia.org/wiki/File:Brueghel-tower-of-babel.jpg • http://commons.wikimedia.org/wiki/File:Platypus.jpg • http://www.flickr.com/photos/joaomoura/2317171808/sizes/l/ • http://www.flickr.com/photos/wiccked/132687067/ • http://www.flickr.com/photos/xcbiker/386876546/sizes/l/ • http://www.flickr.com/photos/pietel/152403711/sizes/o/
  • 84. http://www.flickr.com/photos/forezt/192554677/sizes/o/ • http://keremkosaner.files.wordpress.com/2008/04/softwaredevelopment.gif • http://www.jouy.inra.fr • http://www.flickr.com/photos/ejpphoto/408101818/sizes/o/ • http://www.flickr.com/photos/solaro/2127576608/sizes/l/ • http://www.flickr.com/photos/biggreymare/2846899405/sizes/l/ • http://www.flickr.com/photos/timsamoff/252370986/sizes/l/ • http://www.flickr.com/photos/29738009@N08/2975466425/sizes/l/ • http://www.flickr.com/photos/howie_berlin/180121635/sizes/o/ • http://www.flickr.com/photos/yogi/1281980605/sizes/l/ • http://www.flickr.com/photos/dorseygraphics/1336468896/sizes/l/