Obey The Rules: Implementing a Rules Engine in Flex
-
Upload
rj-owen -
Category
Technology
-
view
4.820 -
download
2
description
Transcript of Obey The Rules: Implementing a Rules Engine in Flex
Obey the Rules!Understand business rules processing theory
Review real world case studies on client side rules processing.
Walk through a simple a client-side rules processing engine written in Flex 3.0
What is a rules engine?
Rules engines
• are mechanisms for executing business rules in a runtime production environment.
• separate business rules from application logic (encapsulation!)
• are often deployed on a web application server.
• are packaged as components with the ability to create, define, classify and manage business rules.
• are formalized specifications of business processes
• are statements that define or constrain some aspect an organization
Business rules
Business process: keep stores well stocked.Business rule: If the number of shirts in a store gets below 15, order more.
• Business rules change more frequently than the rest of the application code.
• Business rules require input and management by an organization (human).
• Business rules can be completely externalized from the application (code) or carefully organized
• This is accomplished through good application architecture, which may or may not include a rules engine
Keep ‘em Separated
Why use a rules engine in your application?
• Lower the cost in modifying business logic
• Shorten development time and maintenance time
• Rules are externalized so can easily shared across multiple applications
• Changes can be made faster and with less risk
• Increase productivity and flexibility in your business
• Lots of business-specific code or some well organized XML rules?
How are rules defined and implemented?
Typical workflow from business to technology
The organization defines the business processes.
Typical workflow from business to technology
A business analyst translates business practices into business rule statements, constraints and actions.
Typical workflow from business to technology
The software developer implements the rules engine component in the application.
The actions and triggers are implemented by the developer.
The application is deployed by a developer with the rules externalized
Typical workflow from business to technology
The organization changes some business processes.
Typical workflow from business to technology
If the business process doesn’t require new actions, anyone, including this silly intern with a small desk, can update the rules engine. Win.
Why use a client-side rules engine in your Flex RIA?
• Provide an experience that is more contextual and unique to the user
• Remove server dependencies for processing business rules logic.
• Do not have to recompile your .SWF when business logic changes.
• Quicker response to user input that triggers rules.
How do rules engines work?
Rules Engine Anatomy
• Facts are input to the engine; statements about the system. Often key/value pairs.
• shirts.quantity = 10;
• Conditions are statements about the possible condition of the system that facts are matched against. Conditions are joined using AND, OR, etc. to create complex nodes. The “if” in an “if-then” statement.
• shirts.quantity < 15;
• Actions define possible out comes of a rule and are custom to the rules engine implementation. The “then” in an “if then statement.”
• ...then create an order for more shirts
• Rules combine facts, conditions and actions and can sometimes be nested
• using <facts> as input, if <conditions> then <actions>
Rules Engine Anatomy: t-shirt inventory
Facts
Rules
Conditions
Actions
shirts.quantity = 10;
if ((shirts.quantity < 15)
create an order
Rules Engine Anatomy: clown alarm system
Facts
Rules
Conditions
Actions
clowns.quantity = 10;
if ((clowns.quantity > 5)
OR
(clowns.haveKnives)
call Axe Cop
http://www.axecop.com
Examples!
Real world use case 1FormBuilderUI: AS3 rules engine under the hood
A simple AS3-based rules engine to demonstrate the power and ability of client-side rules engines. Uses dynamic object creation and rules parsing.
Engine Type: ProductionAlgorithm: Basic
The Stack...
The Rules...
<rule id="isFemale"><statement><![CDATA[ @info.sex equalTo 'Female' ]]></statement><actions>
<visibleAction questionIDs="areYouPregnant"/></actions>
</rule>
<rule id="isTeenager"><statement><![CDATA[ @info.age greaterThanOrEqualTo '13' AND
@info.age lessThan '18' ]]></statement><actions></actions>
</rule>
<rule id="isTeenageGirl"><statement><![CDATA[ $isTeenager AND $isFemale ]]></statement><actions>
<urlAction url="http://www.seventeen.com" /></actions>
</rule>
Regular Expressions
public static var andOrTrueFalsePattern:RegExp = /AND|OR|true|false/gi;
public static var ruleTokenPattern:RegExp = /\$([a-zA-Z0-9_]+)/g;
public static var propertyTokenPattern:RegExp = /\@([a-zA-Z0-9_.]+)/g;
public static var nonSpaceGroups:RegExp = /([\$\@a-zA-Z0-9_.'"]+)([^ \n\r])/gi;
public static var quotesPattern:RegExp = /'|"/gi;
Pattern matching a rule...
Boolean parsing using short circuit
var matches:Array = [true, "AND", false, "AND", true, "OR" true];var operator:String; var nextValue:Boolean;var overallValue:Boolean = matches[0];
var i:int = 1;while (i < matches.length - 1) {
operator=matches[i];nextValue=StringUtil.stringToBoolean(matches[i + 1]);
if (isAndOperator(operator)) {overallValue=(overallValue && nextValue);if (overallValue == false)
return false;} else if (isOrOperator(operator)) {
overallValue=(overallValue || nextValue);if (overallValue == true)
return true;}i = i + 2;
}
“...the second argument is only executed or evaluated if the first argument does not suffice to determine the value of the expression...”
Hamcrest API - Matchers:
public static const EQUAL_TO:String = "equalTo";
public static const NOT_EQUAL_TO:String = "notEqualTo";
public static const LESS_THAN:String = "lessThan";
public static const LESS_THAN_OR_EQUAL_TO:String = "lessThanOrEqualTo";
public static const GREATER_THAN:String = "greaterThan";
public static const GREATER_THAN_OR_EQUAL_TO:String = "greaterThanOrEqualTo";
public static const CONTAINS:String = "contains";
Hamcrest API: Get your facts straight!
public static function evaluateCondition(target:*, operator:String, source:*):Boolean {
try {switch (operator) {
case Matchers.EQUAL_TO:assertThat(target, equalTo(source));break;
case Matchers.NOT_EQUAL_TO:assertThat(target, not(equalTo(source)));break;
case Matchers.LESS_THAN:assertThat(Number(target), lessThan(Number(source)));break;
default:throw new RuleError("No matcher found for this operator!”);
}} catch (e:Error) {
if (e.errorID != RuleError.ILLEGAL_OPERATOR_ERROR) {value=false;
} else {_logger.error(e.message, e.errorID);
}}
Type of Rules engines
There are several types of rules engines. For the most part they differ in the manner to which the Rules are scheduled for execution.
• Used to represent behaviors of the type IF condition THEN action.
• "Should this customer be allowed a mortgage?"
• This question can be answered by executing rules of the form "IF some-condition THEN allow-customer-a-mortgage".
• production rule engines execute when a user or application invokes them - facts are explicitly passed in. Often a queue of facts is processed at once.
Engine types: production(inference)
Engine types: reactive
• Also known as Event Condition Action (ECA) rules engines
• detect and react to incoming events and then process event patterns.
• A reactive rule could be used to alert a user when they have reached a negative balance in their bank account
• reactive engines react automatically when events occur.
• some engines have production and reactive capabilities
The core of the rules engine is the algorithm used to process the rules.
We will discuss Basic (naive) and Rete processing algorithms.
Rule Processing Algorithms
Basic Algorithm
• The basic or “naive” algorithm runs each new fact through the list of conditions and processes it appropriately.
• Less memory is required than Rete, but performance can be far worse
• Ideally used when you have a smaller set of rules to execute
• This is the algorithm you will most likely “wander” into if you are unfamiliar with rules systems or similar problems (pattern matching, for example
Basic Algorithm
Fact
condition A
Action
Fact
cB cC cD
ANDOR
Fact
Optimizations can give priority to certain
conditions, wait to process until all facts are run
through conditions, etc.
Rete Algorithm
• more complex implementation than basic.
• will take more time to implement initially
• performs with much greater efficiency
• save future optimization
Rete Algorithm
• divides rules up into pieces
• scatters the pieces along a logical chain
• traverses the chain when new facts are added to the system
• joins operation nodes to produce outcomes
Rete Algorithm
• is FAST - trades memory for performance
• stores rules in a network/tree structure (the “rete”)
• saves state at each node in the rete
• re-evaluates appropriate branches when new facts come in
• is what many other production rules engines are based on:
• Drools, Jess, JBoss Rete
Rete Algorithm
Fact1
condition A
Action
Fact3
cB cC cD
AND
OR
clowns.quantity = 10;
if ((clowns.quantity > 5)
AND condition B
AND (condition C OR D))
call Axe Cop
Fact2
Real world use case 2:Herff Jones Order Manager
EffectiveUI was hired by Herff Jones to rebuild their sales. rep. CMS for managing student class ring, cap and gown and fine papers orders. Herff Jones leads this market. Their sales reps. must have an optimized workflow for entering in large numbers of complex orders quickly and accurately.
Engine Type: ProductionAlgorithm: Rete
Technical Challenges
• Class Rings have an “unruly” number of options for customization. The options include name, engraving, size, color, metal, stone, ect.
• Business rules define what options available based on pre-condtions (i.e. if you choose a stone, then other options are available specific to the stone)
• The sales rep collects printed order forms and must enter the ring orders into the Order Manager Flex application. This process demands efficiency and accuracy
• Potentially hundreds of thousands of combinations for ring options.
• Currently these were in a database on a server in each rep office. The rules apply across the entire business so it makes sense to define them globally
Core Components
• Rule Processing engine for defining user pathways in the ring order form
• Due to the nature and quantity of business rules, the Rete algorithm was used to implement the engine
• The ring pricing is also determined based on external business rules using the same engine
• Certain rules are shared across other parent rules and should not be evaluated more than once in the same execution cycle. We use “Macros” in this case.
Core UI
• The ring order form consists of a standard form with a set of “base” options
• As soon as the base options are selected then the processor is enabled to run each time a form value changes.
• The business rules are passed targets which represent the state of the form and evaluate on that state.
• If a rule evaluates to true it will generally add additonal value options to the target object.
• If a rule evaluates to false then the options are not added
<!-- Rule definition --><rule> <getValue key="Metal Quality"><containsString value="Gold"/></getValue> <addValueOption key="Metal Finish" value="Gold-on-Gold" meta="code:2"/></rule>
Rule XML Sample
Macro XML Sample: pricing a stone
<!-- Macro definition --><defineMacro name="priceStone">
<rule><allOf>
<getValue key="$stoneKey"><equalTo value="$stoneValue"/></getValue><getValue key="$stoneSizeKey"><equalTo value="$stoneSizeValue"/></getValue>
</allOf><addPrice label="$stoneKey: $stoneValue" amount="$amount"/>
</rule></defineMacro>
<!-- Macro implementation --><priceStone stoneKey="Royal Stone" stoneValue="Birthstones - Alexandrite (Jun)" stoneSizeKey="Royal Stone Size" stoneSizeValue="12 Point" amount="4208"/>
Real world use case 3:A Statewide Agency Government Benefits Application (GBA)
EffectiveUI was hired to help with revamping the user experience of an existing forms-driven web application that allows users to apply for state-assisted benefits.
Engine Type: ReactiveAlgorithm: Modified Rete
GBAOverview
GBA allows households to apply for state wide benefits including welfare, food stamps, healthcare, income assistance and more.
QuickTime™ and aAnimation decompressor
are needed to see this picture.
Functionality
• The GBA client should be able to display questions based on previous answers provided in the form.
• The GBA client should be able to update properties on the data model based on answers provided by the user.
• The GBA client should be able to perform other actions such in response to a user asking certain questions.
Technical Challenges
• The State Agency does not allow redeploying SWF files without extensive review and approval cycles
• When an GBA application is submitted to the server it must go through a complex series of server logic and eventually be routed to multiple disparate legacy systems.
• The client must react to user input immediately to provide the proper user experience. We cannot make server calls to process form input through rules.
Core Components
• Rules facts and actions that are declared in external XML files
• Parsing logic to convert that XML into objects used by the processor
• A data model the can be monitored by the processor. All objects were [Bindable]
...Core Components
• An observer to handle listening for property changes on the data model. We used Flex data binding to monitor all the subject data.
• A processor to execute any rule that contains the subject data that has changed.
• A command interface and message model to perform custom actions in the software application.
GBA Rules engine architecture
Fact(change event)
Conditions
Actions
User Questions
Data ModelB
indin
g!
Bin
din
g!
Binding!
Core UI
• Dynamically define all forms and their fields (questions) in xml
• Allow customization of form elements to include validation, formatting
• Option data with sorting and filtering for inclusive questions
• Derived Properties (age derived from birthdate)
<question id="362"controlType="ComboBox"inlineHelp="Does anyone receive money from elsewhere?"label="Other Employment"optionsID="R00013"target="Household.Income.OtherIncome"/>
Question XML
<condition id="hasCurrentEmployment" targetProperty="Individual.HasCurrentEmployment" operator="equalTo" sourceValue="true"/>
<condition id="hasPastEmployment" targetProperty="Individual.HasPastEmployment" operator="equalTo" sourceValue="true"/>
Condition XML
<rule id="doesAnyoneHasOtherEmployment"><statement>$hasOtherEmployment</statement><actions>
<visibleAction questionGroupIDs="income_other"/></actions>
</rule>
<rule id="NoEmployment"><statement>$IsOnStrike OR ($NoFutureEmployment AND
$NoCurrentEmployment AND $NoPastEmployment AND $NoOtherIncome)</statement>
<actions><visibleAction questionIDs="364"/>
</actions></rule>
Rule XML
Data Abstraction
Dynamic Binding using ObjectProxy
• The Flex client needed to support data binding, however the data schema was based on an external XSD.
• So we chose to implement an XMLProxy class by extending ObjectProxy which supports data binding on dynamic objects.
• We then implemented a serializer that would convert the raw XML into XMLProxy objects
• This allows the data model, or the rules to change without having to redeploy a SWF.
• The ObjectProxy class is very expensive and takes up mucho memory
What next?
• Open source Rete and modified basic rules library and form builder library
• Zachary Pinter, other contributors?