Business Rules – The Quest for the Holy Grail
Dr. Paul Dorsey
Dulcian, Inc.
The automated support of business rules has been one of the hottest topics in the Oracle community for the last few years. The industry has tried using general business rule grammars (with no success), extending the Oracle Designer repository (with some success), and has written limited business rule generators (quite successfully).
Until recently, I was of the opinion that the quest for a general business rule generator was probably futile. There was no way that we would be able to get a reasonable set of business rules specified and generated. Business rules are too complex, and always require custom coding. After all, we already have a way of describing complex business rules; we call it PL/SQL.
At the same time, I have been building several limited business rule engines with great success. Each of these engines was more robust than the last, but none of them seemed to come anywhere close to something that I would want to use for trigger generation.
Then it happened. I designed yet another limited engine to support validation of tax returns(to make sure that Line1 + Line2 = Line3 on your tax return). We built the code to parse rules, and generate procedures. While writing up the system documentation for the engine design, it struck me that just as I could validate data in a document, I could validate data in a database.
I am not going to assert that the quest for the ultimate business rule engine has been achieved. We are still only able to generate relatively simple business rules, though we can store and maintain the most complex rules in the system. I still don’t think we can build the perfect business rule code generator, but I think we can get pretty close.
In this paper, I will discuss the design of the Business Rule Integrated Database Generator (BRIG). This was developed for the Lancaster County Tax Collection Bureau (LCTCB) in Pennsylvania. Their vision and willingness to try new ideas made this project possible. Special thanks must go to Tom Baum and Marta Jo Cochran of LCTCB and Dave Heinaman, a senior consultant on the project. First I will discuss the types of rules that we wanted to support along with the other system requirements, then I will describe the design.
Rule Requirements
There are basically five different kinds of business rules that are commonly supported in systems that we design:
Other System Requirements
There were several requirements for the system:
The Design of the Business Rules Information Generator (BRIG)
The first debate occurred about whether or not to store our rules in a repository outside of Oracle Designer. By storing the rules in a separate repository, there were some trade-offs. On the positive side, rules could be stored in a complex structure not easily supported through user extensions. (We considered extending the repository to store the rules, but we wanted to have the system in production for a while before we made that decision.) We were interested in writing very complex code against repository extensions for a first version. On the negative side, we would be storing many of our business rules outside of the Oracle Designer Repository. This would put our business rules in two places.
We decided to build a separate rules repository. The rationale was that our projects are not built to simply support a set of rules; rather, they are built to support a class of rules. That is to say, the flexible business rules are part of the implementation, not the design.
BRIG has had a profound impact on our design process. Now, business requirements are placed directly in the repository late in the analysis phase. This tends to blur the line between analysis and development. As soon as rules are placed in the repository, they can be generated. No additional coding is required.
The system had made us much more secure in our design process. If we decide that rules are too restrictive, they can be regenerated very quickly. Using BRIG, we can support a much larger percentage of our business rules without custom coding.
We made several key design decisions:
We noted that rules fell into four categories for implementation:
We had to support each type of constraint differently. Check constraints were limited to lists of values and ranges. Conditional triggers supported most complex rules. Redundant columns were supported with triggers (avoiding mutating tables was a significant problem). Recursive rules required a little different thinking.
Recursive Rules
Our models frequently use recursive structures to simplify the data model so enforcing recursive structures was key to the project’s success. We noted that a recursive structure can support several different data types of data. Each required its own rule. The recursive alternatives were:
Multi-Network Any element can be attached to any other element. Parents can have multiple children, children can have multiple parents. More than one independent structure can be stored in the table. Rule: No restriction on elements.
1 network Any element can be attached to any other element. Parents can have multiple children, children can have multiple parents. Only one network structure can be stored in the table. Rule: No restriction on elements. Number of elements connected to any individual element = number of rows in the table (must only issue a warning).
Multi tree Only hierarchical structures allowed. Parents can have more than one child but each child can have only one parent. A tree must have a top (an element with no parent). More than one independent tree is allowed. Rule: All CONNECT BY queries succeed, start with inserted element. (You can use CONNECT BY to detect loops in recursive tables. If there is a loop involving the START WITH element, the query returns an error.)
1 tree Parents can have more than one child but each child can have only one parent. A tree must have a top (an element with no parent). More than one independent tree is allowed. Rule: All CONNECT BY queries succeed, start with inserted element.
To enforce a single tree, there can only be one parent element (note: this can only issue a warning or you would never be able to change the root of a tree).
Multi Lists or Multi Cycles
Either lists or cycles can be stored.
Rule: No duplicate values are allowed on the recursive foreign key column.
1 list or 1 cycle
For all other combinations, you can use the less restrictive rule set. Note that all recursive cases are listed in increasing order of how restrictive they are (with the obvious exception of the last two cases).
It is probably not obvious to the reader how rules are supported in a database structure. Note that we are storing rules using a parse tree. For example, the rule (Col1 + Col2)/2 < Col3 is represented in Figure 1.
Figure 1: Sample Rule Parse Tree
Similarly, compound rules are stored in a separate (but similar) structure. The difference is that instead of combining parameters through operators, we are combining rules through Boolean operators. For example, the compound rule "(RULE1 and RULE2) or (not RULE3)" would be represented as shown in Figure 2.
Figure 2: Sample Compound Rule
Note that for rules, each element is either a function or a column. For compound rules, each element is either a Boolean operator or a rule.
If you are familiar with generic modeling techniques, the data model for BRIG is relatively straightforward. Triggers are related to tables and columns. Both simple data rules and compound rules are simple master detail and recursive structures as shown in Figure 3.
Testing the depth of BRIG™
The first test we set for BRIG™ was to see if it could support the complex data-related business rules for BRIG’s own data structure. Although it is only comprised of a few tables, the BRIG™ repository is quite complex. The following business rules could not be supported through referential integrity and check constraints:
Such rules can be entered into the system and generated. However, attempting to generate these rules points out the limitations in the rule engine. Each of these rules requires that we write a specific function to look up the correct data to make sure that model consistency is enforced.
Some common functions such as summing up the details and storing them in a master (such as for a purchase order) can be classified and generated, but most other complex rules (such as ALL the complex rules for this system) still need custom coding.
In applying the BRIG to a standard OLTP, the results are somewhat better. However, most complex rules require the writing of a custom function.
Conclusion
We have designed a generalized business rule generator (the BRIG system). It works perfectly for almost all simple rules and helps in the maintenance of complex rules (though they still require some custom coding).
My opinion hasn’t changed that a generalized business rule engine that would support all rules can never be built. If someone can build a grammar that will allow generation of rules such as the ones required by the BRIG data structure itself, then I will gladly retire BRIG to the scrap heap. Until then, BRIG stands as a pretty good attempt at a generalized rule engine that generates 100 percent of the code for simple rules and helps to maintain complex rules.
About the Author
Dr. Paul Dorsey is the President of Dulcian, Inc., an Oracle consulting firm that specializes in data warehousing, systems development and products that support the Oracle environment. Paul is co-author with Peter Koletzke of Oracle Press’ Oracle Designer Handbook and with Joseph Hudicka of Oracle Press’ Oracle8 Design Using UML Object Modeling. Paul can be contacted at pdorsey@dulcian.com or through Dulcian’s Website at www.dulcian.com.