Combining BRC Executions
Understanding complex BRC
In most circumstances, it is very easy to determine which BRC to use, and how to determine the output of a BRC:
- For a simple, static domain BRC, you can use a matrix.
- For a pricing aggregation, you can use a formula.
However, in some circumstances, things are not so straightforward. Calculations can get complex, and when things get complex, you will tend to use macros or java code. The following examples will make things more clear.
EXAMPLE 1: USING A WEB SERVICE TO DETERMINE THE EXISTENCE OF AN OPTION
Suppose that the existence of a car option, let’s say “alloy wheels”, is determined by 2 criteria: the car finish (you’ve chosen a sports kit) and the physical availability of the alloy wheels.
In theory, this BRC could be very simple to express:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aFinish | CPE.rootCP.FO/foKits.FP/fpFinish.value | Yes | Yes |
| aStock | ? | Yes | No |
| aExist | CPE.currentFP.state.exist | Yes | No |
| AFINISH | ASTOCK | AEXIST |
|---|---|---|
| =SPORT | >0 | Yes |
| AFINISH | ASTOCK | AEXIST |
|---|---|---|
| =SPORT | =0 | No |
| <>SPORT | >0 | No |
| <>SPORT | =0 | No |
This BRC seems simple enough, however there’s a hatch: it is impossible to determine the CPE because the stock is a calculated piece of data, for instance by web service. In this case, we will be tempted to convert the matrix BRC into a macro-based BRC, because it’s the natural way to calculate everything inside one BRC:
BRC DictionaryExSportsKit()
/* Define local variable to calculate the stock level */
LOCAL vStockLevel -1
/* Initialize result for existence rule */
LOCAL result 0
/* Calculate result based on car finish and stock level */
IF aFinish = “SPORT”
/* Calculate stock level */
LET vStockLevel mWebServiceGetStockLevel()
IF vStockLevel > 0
LET result 1
END_IF
END_IF
/* Display result */
LET tab[0,0] “aExist”
LET tab[1,0] result
LET tab[“NR”] 1
LET tab[“NC”] 1
DISPLAY “tab”
END_DEFINE
EXAMPLE 2: USING A MACRO TO DO COMPLEX CALCULATIONS
The calculation of a surface is length times width. This seems simple enough, certainly if the length and width are 2 pieces of data which are immediately accessible by CPE. In this case, a simple formula can be enough:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| Length | ? | Yes | Yes |
| aWidth | ? | Yes | Yes |
| aSurface | CPE.currentFP.value | Yes | No |
aSurface := aLength * aWidth
However, in the event that the length and the width are 2 complex pieces of data that need to be calculated themselves, 2 possibilities offer themselves: adding calculated form properties or using a macro.
The first option, adding calculated form properties, will actually use a workaround to get the intermediate calculated values for both the length and the width. Basically, the formula will remain the same; however the model will contain 2 extra form properties each having its own calculation BRC.
The second option is another workaround, basically putting inside one macro all the criteria allowing to calculate both the length as well as the width:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aLength1 | CPE.currentForm.FP/fpLength1.value | Yes | Yes |
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aLength2 | CPE.currentForm.FP/fpLength2.value | Yes | Yes |
| aWidth1 | CPE.currentForm.FP/fpWidth1.value | Yes | Yes |
| aWidth2 | CPE.currentForm.FP/fpWidth2.value | Yes | Yes |
| aWidth3 | CPE.currentForm.FP/fpWidth3.value | Yes | Yes |
| aSurface | CPE.currentFP.value | Yes | No |
BRC Dictionaryurface()
/* Initialize intermediate calculation results */
LOCAL vLength -1
LOCAL vWidth -1
/* Calculate vLength */
LET vLength mCalculateLength(aLength1, aLength2)
/* Calculate vWidth */
LET vWidth mCalculateWidth(aWidth1, aWidth2, aWidth3)
/* Calculate and display result */
LET tab[0,0] “aSurface”
LET tab[1,0] vLength * vWidth
LET tab[“NR”] 1
LET tab[“NC” 1
DISPLAY “tab”
END_DEFINE
The examples mentioned above show clearly that complex calculations lead to a more complex model.
This can have an impact on the model in terms of:
- Maintainability: using macros instead of matrixes make the model less easy to read and harder to change for business users
- Performance: each form property that represents an intermediate calculation makes the model heavier and can have an impact on performances
Doing intermediate calculations
The section here above should make it clear that intermediate calculations can sometimes be necessary and that these intermediate calculations often lead to more complex model. An easier solution for these intermediate calculations has been put in place using combined BRC.
Definition: A combined BRC is a BRC for which at least one alias is calculated by another BRC.
Information:
In a 2-dimensional combined BRC, 2 BRC intervene: a parent BRC and a child BRC.
The parent BRC corresponds to a complex BRC for which one of the criteria cannot be found in the model, and which needs to be calculated by another BRC (the child BRC).
The child BRC corresponds to a BRC which will calculate an intermediate global variable, which can be used as an input for the parent BRC.
The general principle can be demonstrated as follows:
In this example, a parent BRC needs to calculate a domain or a value for form property fp14. In order to do that, it needs 3 input aliases (modelInput1, 2 and 3) pointing respectively to fp11, fp12 and fp13.
However, a fourth alias (externalInputX) is necessary to trigger the BRC. This fourth alias is based on fp21, fp22 and fp23. Instead of putting all input aliases together in the same business rule (written as a macro), or instead of getting the intermediate calculation for “externalInputX” done in a calculated form property, the business rule has been split in two, allowing the first one to determine the main rule and the second one (the child one) to focus on one special element.
The 2 above-mentioned examples can clearly benefit from the combined BRC concept
EXAMPLE 1: USING A WEB SERVICE TO DETERMINE THE EXISTENCE OF AN OPTION.
Based on the above mentioned reasoning, our first example will be split up in two BRC.
The main parent BRC will calculate the existence based on the car finish and the stock level. However, the stock level will “point” to the output of another BRC:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aFinish | CPE.rootCP.FO/foKits.FP/fpFinish.value | Yes | Yes |
| aStock | CPE.rootCP.FO/foKits.BRC/brcStock.aOutput? | Yes | No |
| aExist | CPE.currentFP.state.exist | Yes | No |
| AFINISH | ASTOCK | AEXIST |
|---|---|---|
| =SPORT | >0 | Yes |
| =SPORT | =0 | No |
| <>SPORT | >0 | No |
| <>SPORT | =0 | No |
The child BRC will calculate the stock level based on a specific business rule, and will issue it using an output alias without CPE (it’s simply a means to issue an output that can be reused (“called”) by the parent BRC):
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aInput1 | Whatever CPE necessary | Yes | Yes |
| aInput2 | Whatever CPE necessary | Yes | No |
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aOutput | This CPE is empty! | Yes | No |
The resulting macro is now much simpler and only treats one business case: determining the stock level.
BRC DictionaryExSportsKit()
/* Define local variable to calculate the stock level */
LOCAL vStockLevel -1
/* Calculate stock level */
LET vStockLevel mWebServiceGetStockLevel(aInput1, aInput2)
/* Display result */
LET tab[0,0] “aOutput”
LET tab[1,0] vStockLevel
LET tab[“NR”] 1
LET tab[“NC”] 1
DISPLAY “tab”
END_DEFINE
EXAMPLE 2: USING A MACRO TO DO COMPLEX CALCULATIONS
The BRC calculating the surface will now be split up into 3 BRC: a formula doing the main calculation, a matrix calculating the length and a matrix calculating the width. The main BRC will look as follows:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aLength | CPE.currentForm.BRC/brcLength.aOutput | Yes | Yes |
| aWidth | CPE.currentForm.BRC/brcWidth.aOutput | Yes | Yes |
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aSurface | CPE.currentFP.value | Yes | No |
aSurface := aLength * aWidth
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aModel | CPE.rootCP.FO/foModel.FP/fpType.value | Yes | Yes |
| aOutput | This CPE is empty! | Yes | No |
| AMODEL | AOUTPUT |
|---|---|
| OSIRIS | 4 |
| ELDORADO | 5 |
| AMBIENTE | 6 |
The second child BRC will issue the width. It will look as follows:
| NAME | CPE | MUSTEXIST | MUSTBEANSWERED |
|---|---|---|---|
| aModel | CPE.rootCP.FO/foModel.FP/fpType.value.BPS/bpsTechnical.BP/bpWidth.value | Yes | Yes |
| aOutput | This CPE is empty! | Yes | No |
aOutput := aModel
TIP:
Combining BRC allows you to facilitate modeling by expressing each part of the global business rule using the most adapted form (matrix, formula, macro, product filter).
Combining BRC greatly simplifies the maintenance of a BRC. Indeed, when a complex criterion is added, the original BRC can just be extended with 1 parameter that is itself calculated by another business rule.
