Everything about Business Rule Engine

Everything about Business Rule Engine

What is business rule engine

While building any application, the crux or the core part of it is always business logic or business rules. And as with any application, there always comes a time when some or a lot of the rules or policies change in the system. But with that change, comes a lot of rework like changing design or creating a new module altogether to code in the changes in the rules, regression testing, performance testing etc. The rework along with debugging if required amounts to a lot of unnecessary work which can otherwise be utilized for other work, thus reducing the engineering cycle by drastic amounts.

This is library is built on top of Microsoft rule engine library. In this library, we have abstracted the rules so that the core logic is always maintained while the rules change can happen in an easy way without changing the code base. Also, the input to the system is dynamic in nature so the model need not be defined in the system. It can be sent as an expando object or any other typed object and the system will be able to handle it.

Use Case

  • When condition are business driven or changed dynamically then rule engine can be used
  • In case the condition are very complex, we can use business rule engine to simplify the logic

 

How it works

octocat

Rule Engine

This component is the Rules Engine private library/NuGet package being referenced by the developer

Rules Store

As shown in Rules Schema, we need rules in a particular format for the library to work. While the rules structure is rigid, the data itself can be stored in any component and can be accessed in any form the developer chooses. It can be stored in the form of json files in file structure or blob, or as documents in cosmos db, or any database, azure app configuration or any other place the developer thinks is going to be appropriate based on the project requirements.

Input

The input(s) for the system can be taken from any place as well like user input, blobs, databases, service bus or any other system.

Wrapper

This library sits as a black box outside the project as a referenced project or NuGet package. Then the user can create a wrapper around the library, which will get the rules from the rules store and convert it into the WorkFlowRules structure and send it to the RulesEngine along with the input(s). The RulesEngine then computes and give the information to the wrapper and the wrapper can then do whatever the logic demands with the output information.

Integration in application

Privately accessible interfaces, models, methods and schemas

As with any library/package there are public interfaces with which we interact with that library/packages. There are a few public interfaces in this package as well. The interface which will be used to access this package is IRulesEngine, with four overloaded methods for executing rules. To understand the methods, we need to go through some of the models/schemas first.

Rules

The rules used in this system is mostly comprising of lambda expressions. Anything that can be defined in a lambda expression can be used as a rule in this library.

Rules Schema

Rules schema shown below The workflow rules are how we store the rules in the system. In our system, the name of the model typed in the library is WorkflowRules. An example json would be –

[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "Output": "new (10 as Discount)",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor <= 2 
  AND input1.totalPurchasesToDate >= 5000
  AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount20",
        "Output": "new (20 as Discount)",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor == 3 
  AND input1.totalPurchasesToDate >= 10000
  AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
      {
        "RuleName": "GiveDiscount25",
        "Output": "25",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country != \"india\" AND input1.loyalityFactor >= 2 
  AND input1.totalPurchasesToDate >= 10000
  AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 5"
      },
      {
        "RuleName": "GiveDiscount30",
         "Output": "30",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyalityFactor > 3 AND input1.totalPurchasesToDate >= 50000
  AND input1.totalPurchasesToDate <= 100000
AND input2.totalOrders > 5 AND input3.noOfVisitsPerMonth > 15"
      },
      {
        "RuleName": "GiveDiscount35",
        "Output": "35",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.loyalityFactor > 3 AND input1.totalPurchasesToDate >= 100000 
  AND input2.totalOrders > 15 AND input3.noOfVisitsPerMonth > 25"
      }
    ]
  }
]
  • Output    

 The rule output can  also be defined as lambda expressions.

  • Expression

The rule lambda expression to check the condition

RuleResultTree

This model is the output of the Rules Engine. Once the execution of the Rules Engine is completed and the Engine has gone through all the rules, a list of this type is returned. What this model include is –

  • Rule

This is the rule that is currently being referred. It is of a custom model type and has information of that rule which ran on the input.

  • IsSuccess

This is a Boolean value showcasing whether the given rule passed or not.

  • ChildResults

In the case, the rule has child rules, this variable gets initialized else it is null. This is a nested list of RuleResultTree type to showcase the response of the children rules.

  • Input

This is the input that was being checked upon while the rules were being verified on this object. In case of multiple inputs, it takes up the first input.

IRulesEngine

IRulesEngine is the main interface which is used to handle all the executions. This interface has four overloaded methods to execute rules –

List<RuleResultTree> ExecuteRule(string workflowName, IEnumerable<dynamic> input, object[] otherInputs); 
List<RuleResultTree> ExecuteRule(string workflowName, object[] inputs); 
List<RuleResultTree> ExecuteRule(string workflowName, object input); 
List<RuleResultTree> ExecuteRule(string workflowName, RuleParameter[] ruleParams); 
List<RuleResultTree> ExecuteAllRuleOrderBy(string workflowName, object[] inputs);

 

One Rules Engine can take in multiple workflows and the workflows can be distributed based on the logic dictated by the system you are building.

In the first definition –

  • workflowName is the name of the workflow you want to take up.
  • input is a list of dynamic inputs which is being entered.

In the second definition –

  • workflowName is the name of the workflow you want to take up.
  • input is a single dynamic input which is being entered.

In the third definition –

  • workflowName is the name of the workflow you want to take up.
  • ruleParams is an array of RuleParameters as explained in RuleParameter.

Initiating the Rules Engine

To initiate the Rules Engine instance to be used for executing rules, the workflow rules need to be injected into the library. The details of constructor is below –

 
public RulesEngine(WorkflowRules[] workflowRules, ILogger logger)

Summary

Rule engines are a useful tool that can be used to externalize business logic, allow business users to write rules, or solve certain classes of problems in an efficient way. When compared to other approaches, there are tradeoffs, so it's important to approach this decision in a methodical manner

In general, you might consider a business rule solution if you need to externalize business rules, support rapid change and empower business users to change business rules. You'll get the most out of a rule engine if you accept the new paradigm by relinquishing flow control, using fine-grained rules and objects, avoiding cross-products, and understanding the combinatorics and recursion that a rule approach can create.

Author

Talk To Our Experts