DSL & IoC - Combining powerful concepts
I was just writing this line of code:
DslExecuter<SchedulingDslEngine>.Create(“validateWebSiteIsUp”)
When it occurred to me that this looks a look like an IoC resolve call. Which got me thinking about combining both concepts together, which gave me the shakes.
The idea is that we can expose those dependencies like this:
customers as ICustomerRepository fraudService as IFraudService alerts as IAlertService for customer in customers.FindAll(With.Orders): for order in customer.Orders: if fraudService.IsFraud(order): alerts.ForFaurdOn(order) if customer.Important: alerts.NotifyCustomerAboutFraud(customer)
Leaving aside the mountain slope code*, consider what is going on here. We are exposing dependencies by specifying the types that we need. We can then get them through the IoC and execute the code in hand.
This means that the DSL has full access to everything in the application, and is subject to the same rules and behavior as all the other components. From my point of view... sweeeeeet.
* First example that popped to mind, yes, I know it is a bad one.
Comments
Wow, I'm in love.
Is not the IOC a DSL that is working at the same meta level on your domain as your 'DSL'?
Joe, I don't follow, can you rephrase?
Cool, never thought about this.
Which brings the idea of IoC as a (not-DS) language level concept:
public class FraudAlert {
using implicit ICustomerRepository customers;
...
A rose is a rose, by any other name it will still be a rose!
2 + 1 (infix)
2 1 + (postfix)
all of the above are 'functionally equivalent'.
If you have a torus and a coffee cup with handle, they are isomorphic. Every point on a torus can be mapped to the cup.
I like this example:
Unit Test Frameworks are a DSL
Mocking Frameworks are a DSL
What levels are each of these at?
Can you have unit tests without mocking?
Can you have mocking without unit testing?
By adding mocking you are actually extending the domain language of the unit testing. Unit testing is at a higher level.
Another way to look at this is to see which directions the dependencies flow.
A nice blog on this can be found at:
http://fragmental.tw/research-on-dsls/layering-domains/
Joe,
of the postfix, prefix and infix, what kind can you do in your head immediately? What happens if I add a few more operations
prefix (relearning CLisp) and infix.
let us go ahead and add those operations:
A = (+( + 1 1)(+ 1 1))
B = (* 4 1)
B operator can be nothing more than a composition of the previous operator.
How many times are you going to code using A, before you implement B.
Maybe this will help.
Let us create a domain (D). D = { 1, 2, 3, 4, 5, 6, ... }
Now let us define some operators on this domain:
De = emit_even(D)
where De = { 2, 4, 6, ... }
Do = emit_odd(D)
where Do = { 1, 3, 5, ... }
Dp = pop(D)
where Dp = { 1 }
Dr = rest(D)
where Dr = { 2, 3, 4, 5, 6, ... }
D1 = De + Dp
where D1 = D
D2 = pop(emit_odd(D)) + pop(emit_even(D))
D3 = pop(D) + pop(rest(D))
where D2 and D3 are equal { 1, 2 }
Last operator:
D_first_odd_even = get_first_odd_and_even(D)
where Done_odd_even = { 1, 2 }
This last operator can be implemented with either D2 or D3. Your preference.
You noticed how the new Relations, I defined were composed of previous Relations.
Another thing, the emit_odd and emit_even can also be implemented with composites of the pop and rest operators. I decided to implement them as first class operators. My choice.
The real question is how do you create a DSL where not only a domain expert user can utilize your DSL, but a novice domain user can utilize you DSL and learn to become an expert.
See:
http://www.laputan.org/selfish/selfish.html
especially low surface to volume ratio
Comment preview