John Pingel, a consultant with CoreLogic, recently emailed me with some good questions related to quality metrics for rule projects. Each of these questions deserves a chapter of a book, but I will take a stab at some answers -- please don't hesitate to comment if you have other ideas.
What design/authoring quality metrics can JRules gather for an IRL rule-based system?
Here John was imagining something similar to the common software complexity metrics, such as calculated by the popular JDepends library. Let's see how each could be applied to a rules-based system:
Number of classes and interfaces:Here we can easily calculate the statistics for the rule project, in terms of the complexity of the BOM, VOC, B2X as well as the rules: from Rule Studio export a rule project statistics report.
Afferent Couplings:The way I interpret this is the relative responsibility of a given rule or rule package. I.e. how many rules can a given rule enable?
For example, given the two rules below:
Rule: bar.setDaniel if the name of 'the customer' contains "Smith" then set the name of 'the customer' to "Daniel Selman"; Rule: foo.isSelman if the name of 'the customer' contains "Selman" then print "Hello Dan!";
You can create the following query to discover the data-driven relationship between the rules:
Find all business rules such that each business rule may disable "bar.setDaniel" or each business rule may enable "bar.setDaniel"
As you'd expect, the result of the query is bar.isSelman because the action of the rule will only be fired if the setDaniel rule has been triggered.
Unfortunately we don't currently have queries at the package level or support wildcards in the rule name in the query, so you have to create a query for each rule in your package and then aggregate the results. It should be possible to create a Rule Studio plugin that runs the "each business rule may enable" query on each rule within a package and rolls the results up at the package level. A good starting point for such a plugin is the studio/samples/brmmanagement/queryexecution sample.
An easier way to run the query manually is to right-click on a rule and select "Find Dependencies":
This is essentially the inverse of the above (for this simple example...), showing which rules can cause a given rule to become enabled. E.g.
Find all business rules such that each business rule may enable "foo.isSelman"
I don't think this is relevant for rules.
Here we can use the sample definition as for code: the ratio of efferent coupling (Ce) to total coupling (Ce + Ca) such that I = Ce / (Ce + Ca). This metric is an indicator of the package's resilience to change. The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package.
Distance from the Main Sequence (D)
I don't think this is relevant as we do not have the concept of abstractness.
Package Dependency Cycles
We can interpret this as loops in the "enable/disable" relationships.
If we introduce a third rule:
Rule: baz:setDan if the name of 'the customer' contains "Selman" then set the name of 'the customer' to "Dan Selman";
And for all three rules we run "Find Rule Dependencies > Rules which may enable or disable this rule" we get the following graph:
To detect such cycles our custom plugin would have to walk the dependency graph pushing rules or packages onto a stack. If a rule or package already exists on the stack then we have detected a cycle.
In subsequent posts I will try to address John's other questions:
- What are common design/authoring “smells” in rule-based systems, and what are the recommended ways of refactoring these “Rule-smells” into better designs? (This questions is related to the book on “Refactoring Code Smells with Patterns”)
- What are the most common design “patterns” that are unique to developing high quality Rule-based systems.
- What are the best source of information on analysis and design best practices for rule-based systems?