This post originated from an RSS feed registered with Ruby Buzz
by Obie Fernandez.
Original Post: More on Business DSLs in Ruby
Feed Title: Obie On Rails (Has It Been 9 Years Already?)
Feed URL: http://jroller.com/obie/feed/entries/rss
Feed Description: Obie Fernandez talks about life as a technologist, mostly as ramblings about software development and consulting. Nowadays it's pretty much all about Ruby and Ruby on Rails.
He refers to some questions
he left me as comments, asking how writing DSLs in Ruby
different from using XML/XSLT. It's really different actually, but
instead of trying to answer the questions directly (especially since I
don't quite understand where he's coming from with them) I think I'll
just post some sample code and see if it helps.
I will go ahead and say that I believe in breaking down the
distinction between code and data -- the DSL script code below resides
in the database and is invoked dynamically when needed. Since it's in
the database (manipulated as a property on an ActiveRecord class) then
I can use the power of Rails to easily and quickly bolt on all sorts of
wonderful access control, workflow and versioning features, with the
goal of getting business end-users programming the behavior of the
system.
Here is a sample script that I hope illustrates the concepts
I've described. The domain is different to protect the privacy of my
client, but the syntax is close enough that the intent of writing code
this way should be clear. The sample system handles monthly commission
payments for a manufacturer's sales representatives.
In English, the first line reads like "define acme
as the sales rep brand code equal to ACME".
The sales_rep_fact
varible is built-in to the implementation of this DSL. It points to a
database view that joins and flattens all the relevant data
that might be needed to figure out how to pay a sales rep for a given
month. The analyst that is responsible for maintaining this script is
already very familiar with this view since he has been accessing via
SQL every month and pulling his query results into Excel in order to
calculate payouts manually. As you might already have guessed, the
variable definitions are criteria which identify properties of sales
reps we will use in our payment rules, which follow in the
script.
calculate acme, arizona do pay 10.percent_of(month_revenue), contraptions pay 12.percent_of(month_revenue), rockets, employee pay 25.percent_of(month_revenue), rockets, independent end
calculate acme, new_mexico do pay 10.percent_of(month_revenue), employee pay 25.percent_of(month_revenue), independent end
The calculate,pay, and accrue methods are
also built into this DSL implementation and their meaning should be
clear to anyone that's worked on even the most basic accounting
systems. In a followup post (coming soon!) I'll delve into
some of the wildly differing contexts that can be used with this
script, beyond the SQL and XHTML generation that I mentioned in my
original Ruby DSLs post.
In summary, what this sample code illustrates is a DSL
designed specifically for describing the rules governing commission
payments to sales representatives. The goal of this DSL is to enable
the maintainers of the commission payments application to accurately
program the rules needed to calculate payments on a monthly basis.