Wednesday, December 13, 2006

Duck typing and business rules

Rules engines have long had the concept of the "head" of a fact - this is basically some kind of a type indicator to tell the engine how to handle the fact.

Imagine we had 2 facts: Accident, and Driver - which represent elements of an insurance claim. It wouldn't make sense to apply the same tests and constraints to each and every fact. For instance, and Accident probably doesn't have an "age" attribute. In rule engine terms (going back a ways) you would represent these facts via a deftemplate, or an ordered fact. In either case, it is a structure that has a name: so the rule engine knows what path to send "accidents" down etc, for efficiency (and also what fields/slots are valid). In the OO world with objects, the equivalent is Class, or type. This is fine in statically typed languages like Java, a strong type is part of your everyday life for better or worse. However, in ruby typeis more rubbery: duck typing is so common no one even calls it duck typing ! A class is almost just a loose contract or construct of convenience more then anything else.

So how to handle this with rule engines? I see 3 options: 1) make people use classes to identify a type, 2) have each fact respond to a certain method to tell an interested part what its "rule type" or "template" is, or 3) use a construct for the rules similar to the olde deftemplate idea: where you define the fields up front that the rule will operate on. You then check facts to work out what template it is closest to.

I am leaning towards 3, by having a template concept, it is both simple, and makes it convenient for duck types. It has the added benefit of allowing the rules to be restricted to methods/accessors indicated in the template construct, rather then exposing the object naked. With some metaprogramming magic its quite easy to achieve too. The only down side is possibly that it may be ambiguous what template a fact conforms to, we will see...

1 comment:

Johan Lindberg said...

I think it's interesting that you've chosen the deftemplates instead of "native" classes/types. When I decided on that question for pyRete (which uses python) I went with #1 because I didn't want there to be any (or at least as small as possible) difference between python objects and facts.

Another reason I went with #1 is because I couldn't think of a nice pythonic way for the user to define fact templates. It'll be interesting to see how you've solved it.

Hope you have the time to release a first version soon.