agile dsl development in ruby
DESCRIPTION
TRANSCRIPT
1
Agile DSL Development in Ruby
Obie Fernandezhttp://obiefernandez.com
ThoughtWorks TechnologistInfoQ.com Ruby Editor
2
• DSL Primer
• Frameworks vs. DSLs
• Implementing DSLs in Ruby
• Real-world lessons learned
Session Topics
jargon: the language, esp. the vocabulary, peculiar to a particular trade, profession, or group
• Designed for a specific domain
• Captures jargon in executable form
• Can be internal or external (as per Fowler)
Domain Specific Languages
Ruby-based DSLs are internal
6
• “Venti half-caf, non-fat, no foam, no whip latte”
• “Route 66, swinging, easy on the chorus, extra solo at the coda, and bump at the end”
Domain Specific Language Examples
7
The coffee example as normal code...
9
depends on an API
That code doesn’t match the way that the
domain is described
It’s difficult to verify too!
Is this right? Hmm
What about DSL style?
Designing Ruby DSLs
• Don’t try to do an abstract metamodel first
• Capture your DSL concepts in valid Ruby syntax, but don’t worry about implementation
• Iterate over your Ruby DSL syntax until authors agree that it faithfully represents the domain, then work on the implementation
18
Let the DSL you devise guide your implementation
Kind of like TDD, don’t do morethan what you need to make your
DSL execute correctly.
DSLs that reflect business documents such as contracts are great
Designing a DSL that’s as close as possible to the document it reflects makes verification of the system much easier!
Agile DSL Development?
• Start with short iterations over the design
• Incorporate end-user feedback, pair with them if possible
• Do TDD your context code
• Do refactor your context code often, but avoid over-engineering it
“The fascinating thing is that, in my experience, most well-written Ruby programs are already a DSL, just by
nature of Ruby’s syntax.”
Jamis Buck, 37signals
Sweet DSL Syntax Sugar
• Optional parentheses
• Symbols
• Blocks
• Literal arrays and hashes
• Variable-length arguments
Most of the time,Rails feels like a DSL for
writing web apps
“the trick to writing DSL’s in Ruby is really knowing what you can and
can’t do with Ruby’s metaprogramming features”
Jamis Buck, 37signals
Different types of Ruby DSL designs
InstantiationYour DSL is simply methods on an object
Class MacrosDSL as methods on some ancestor class, and subclasses can then use those methods to tweak the behavior of
themselves and their subclasses
Top-Level MethodsYour application defines the DSL as top-level methods, and then invokes load with the path to your DSL script. When
those methods are called in the configuration file, they modify some central (typically global) data, which your application uses to determine how it should execute.
Sandboxingaka Contexts
Your DSL is defined as methods of some object, but that object is really just a “sandbox”. Interacting with the
object’s methods modify some state in the sandbox, which is then queried by the application.
Sandboxing is useful for processing user-
maintained scripts kept in your database
Just load up the script and execute it in the sandbox at runtime. Vary behavior by changing the execution context.
You’ll end up coding a metamodel when writing
your sandboxesYour metamodel will be better than if you had tried to
write it first based on pure analysis!
Ruby Features used by DSL implementors
• Symbols, less noisy than strings
• Blocks, enabling delayed evaluation of code
• Modules, for cleaner separation of code
• Splats, for handling parameter arrays
• eval, instance_eval, and class_eval
• define_method and alias_method
It’s a different way of thinking about writing code, and as such needs to be
learned by doing, not by reading. Experimentation is the key!
Jamis Buck, 37signals
Business Natural Language (BNL)
DSLs that are maintained by business users
Incorporating user editable BNL scripts into
your application...How crazy do you want to get?
Programmers can deal with more complexity than domain expertsInternal DSLs might not be the best choice
That wasn’t even valid Ruby syntax!
Hybrid Ruby BNLs
• Our experiment with an external DSLs
• Business rules are stored in the database as text
• Pre-parser appends an underscore to each word, replaces white space with '.' and changes each number to be an argument to a method that stores the numeric values
• Once the preparse has executed, each line is instance_eval’d to create rule objects
• Rule objects are then evaluated using the appropriate context
Real-world lessons learned doing BNLs
• Keep the language consistent
• Creating a language that can execute a line at a time greatly simplifies syntax checking
• Keep the language simple. Subject matter experts get fussy about complexity.
• BNL code is DAMP, not DRYDescriptive and Maintainable Phrases
More on Ruby DSLs
• obiefernandez.com
• jayfields.com
• weblog.jamisbuck.org
• onestepback.org