Bruce Silver's blog post - DMN: Beyond Decision Tables
Bruce Silver
Blog

DMN: Beyond Decision Tables

By Bruce Silver

Read Time: 4 Minutes

If you are using DMN, of course you are using decision tables. Every decision management platform, DMN or not, has some form of decision table.

Business users like them because the meaning of the decision logic is obvious from the table structure without any previous knowledge about how it works. That’s because diagrams and tables are much more intuitive to non-programmers – i.e., subject matter experts – than script or program code. There is still a bit of script in the table cells – in our case, FEEL – but the expressions are usually simple.

The creators of DMN a decade ago took this basic fact and carried it a step further: In order to make the full power of DMN accessible to subject matter experts, the language will include additional table structures with simple FEEL inside the table cells, instead of requiring complex FEEL expressions with functions nested inside other functions. They called those table structures boxed expressions. Today there are nine of them, including literal expression, which just means a FEEL expression in text form, and decision table.

From the outset, boxed expressions were put in DMN with the expressed intent to make the full power of the language more accessible to non-programmers. Today that may seem strange, since very few DMN tools outside of Trisotech support them, other than decision tables. Why is that? Two reasons:

1

Most DMN tools are not designed to expose executable logic directly to subject matter experts. Those tool vendors assume subject matter experts merely want to create business requirements in the form of DRDs, and leave the implementation to programmers. That’s antiquated thinking.

2

Implementing boxed expressions is challenging for the tool vendor. The basic structure of most boxed expressions is a two-column table in which the first column is a variable name and the second column is its value expression. But that value expression does not have to be a literal expression; it could be any boxed expression at all, for example, a decision table. That means the second column must be able to expand to a nested table, and there is no limit to the degree of nesting. From a graphics perspective, that’s not easy!

The fact is, except for decision table and one other boxed expression type, boxed expressions are simply graphical conveniences. The same logic could be written as a FEEL literal expression, a more complex one. But non-programmers have an easier time creating complex logic using simple FEEL inside the boxed expression cells than in constructing complex FEEL expressions.

Let’s look at some examples.

Invocation

An Invocation boxed expression represents a call by a decision to a logic function, typically a user-defined function such as a BKM or decision service, but in principle also a FEEL built-in function. Decision logic that is reused is typically packaged as a function with defined parameters. The Invocation maps values to each parameter and receives in return the function result.

For example, a commonly reused function in mortgage lending is the Loan Amortization Formula, in which the monthly payment is based on three parameters: p, the loan amount; r the interest rate as a decimal value; and n, the number of months in the term of the loan. It’s just an arithmetic expression, but it’s hard to remember so best encapsulated as a BKM.

A decision can get the monthly payment for any mortgage loan by supplying values of p, r, and n through an invocation. With formulas like these, it’s a good idea to explain the parameters in the Description field of the BKM Details.

The Invocation boxed expression is a two-column table in which the first column lists the parameters p, r, and n, and the second column lists expressions of decision variables for each parameter.

Here the decision Loan Payment is defined as an invocation of the BKM Loan Amortization Formula. The BKM parameters and their datatypes are listed in the first column. The second column provides their value as simple FEEL expressions of decision variables. Because the decision variable Loan rate pct is expressed as a percent, it must be divided by 100 when passed to parameter r.

We could just as easily written this invocation as a slightly more complicated FEEL expression:

Loan Amortization Formula(Loan amount, Loan rate pct/100, 360)

With this so-called literal invocation, the names of the parameters do not appear, but the order of the supplied value expressions must match the order of the parameters in the BKM definition. With FEEL built-in functions, it is much more common to use literal invocation, but they can be called using the Invocation boxed expression just as well.

Context

Similar in appearance to Invocation, the Context boxed expression is a two-column table in which each row, called a context entry, contains a name in the first column and a value expression in the second. Again, the second column could be any boxed expression type, including another context, so graphically these tables can be quite complex. The Context boxed expression really should be viewed as two separate boxed expression types, depending on whether or not the final row of the table, called the final result box, is left empty.

Context with Non-Empty Final Result Box

A Context with an expression in the final result box is the one boxed expression type besides decision table that has no literal expression equivalent. It is probably the most useful of the lesser-known boxed expressions, because it allows you to break down the complex logic of a decision into smaller pieces using local variables, i.e. names used only within the scope of the decision. Each context entry names a local variable, and the expressions of any subsequent context entry may refer to those names, as may the final result box expression.

Here is an example from the DMN training:

Total Price = Price after discount + Tax + Shipping cost

The logic is moderately complex but we really just care about the Total Price, not the details, so we can encapsulate those in local variables, the context entries, values not returned in the decision. Note the expression column for Shipping cost is a decision table, not a simple FEEL expression. The final result references the context entries, a much simpler expression.

Context with Empty Final Result Box

When the final result box is left empty, the Context boxed expression creates a structured value, in which each context entry represents a component of that data structure. Building on the previous example, suppose instead of just the Total Price, a number, we want to create an Invoice, a data structure of type tInvoice containing the components shown below:

The Context boxed expression for this is nearly identical to the previous one, except now Total price is a context entry and the final result box is empty.

Just to reinforce the point, the Context boxed expression is a simpler way to define logic that could alternatively be done using a literal expression. A FEEL context literal uses a JSON-like syntax to create data structures, which are comma-separated expressions enclosed in curly braces. For the example above, it would look like this:

{Price before discount: Quantity*Unit Price, Price after discount: if Quantity>6 then 0.9*Price before discount else Price before discount, Tax: if is Taxable=true then 0.09*Price after discount else 0, Shipping cost: if Shipping Type=”Standard” and Price after discount<100, then 9.95 else if Shipping Type=”Standard” and Price after discount>=100 then 0 else 17.95, Total price: Price after discount + Tax + Shipping cost}

Function Definition

A Function Definition boxed expression is only used in a context entry. It represents a user-defined function, just like a BKM, except it is used only within the context, i.e., it can be called only by a subsequent context entry or final result box, not from outside.

Referring back to the Loan Amortization Formula, we could make that a Function Definition inside a context if we weren’t concerned about reuse. It simplifies the final result without using a BKM. This boxed expression had the function name in the first column and the function definition — including comma-separated parameters enclosed in parentheses — in the second column.

Relation and List

A Relation boxed expression defines a FEEL table, a list of identical structures. The column names represent the components of the structure. Relations are often populated with literal values but the table cells may be any FEEL expression. On the Trisotech platform a Relation can be populated by uploading from Excel, a real convenience.

One common use for a Relation containing literal values is a static lookup table modeled as a zero-input decision, i.e., having no incoming information requirements. For example, in the table below, you can query this table using a filter expression:

Loan Table[pointsPct < 1.0].lenderName

returns a list of mortgage lenders who charge less than 1% points on the loan.

The List boxed expression is rarely used. It is simply a list of FEEL expressions arranged in a single column, such as shown below:

If the list contains literal values, it may be uploaded from Excel. One reason it is rarely used is the equivalent literal expression, a comma-separated list enclosed in square brackets, is usually easier to create:

[in1, in2, in3, upper case(in1) + “ “ +lower case(in2) + “ “ + in3]

Conditional

The Conditional boxed expression is a graphical representation of the FEEL if..then..else operator. It simply separates the if, then, and else clauses into separate rows of the table.

The expressions in the right-hand column are not restricted to literal expressions. They could, in fact, be another Conditional expression, implementing an “else if” clause. In that case, the boxed expression may be easier to read than the equivalent literal expression.

Iterator

For..in..return

The Iterator boxed expression is a graphical representation of the FEEL for..in..return or some/every..in..satisfies operators. The syntax of for..in..return is

for [name of dummy variable] in [some list] return [expression of dummy variable and other inputs]

Here the dummy variable stands for a single item in the list, and the operator returns a list of values where the return expression acts on that item. For example, returning to our list of mortgage products, suppose we want to generate a list of formatted monthly payment strings for each product, based on a specific requested loan amount.

Implementing Formatted Monthly Payments as a literal expression may be difficult for some users to follow:

for x in Loan Table 30 return string(“$%,.2f”, payment(Requested amount*(1+x.pointsPct/100) + x.fees, x.rate/100, x.term))

Using the Iterator boxed expression for Formatted Monthly Payments, we can write

Here the return expression uses the Invocation operator twice, first to call the FEEL built-in function string(), which allows a formatting mask, and to call the BKM payment(), which is the Loan Amortization Formula. With complex return expressions, the Iterator boxed expression often provides more readable logic.

This is just one form of iteration, called iteration over item value. When the in expression is a list of integers, the dummy variable represents a position in the list, and iteration is over item position. The boxed expression works in exactly the same way.

Some/every..in..satisfies

You can also use this boxed expression to test membership in a list.

some [dummy variable] in [list] satisfies [boolean expression]

returns true if any member of a list satisfies some requirement, and

every [dummy variable] in [list] satisfies [boolean expression]

returns true only if every member of the list satisfies the requirement. The Iterator boxed expression works in exactly the same way when some or every is entered in the left column of the first row.

Filter

An expression in square brackets immediately following a list expression models a filter of the list. When the bracketed expression is a Boolean, the filter selects list items for which the expression is true. When the bracketed expression is an integer, the filter selects the list item at that integer position.

The Filter boxed expression puts the list in the first row and the filter expression, enclosed in square brackets, in the second row. For example, instead of the

literal expression [1, 3, 7, 11][item> 5]

you can use the Filter boxed expression

Here the list to be filtered is a list of literal values, and the filter expression is a Boolean, returning the list [7, 11].

I personally do not use this boxed expression much, as I am usually using filters with tables, following the filter expression with .[columnName], or extracting an item from a singleton list by appending the filter [1], and you cannot do either of those with this boxed expression.

The Bottom Line

If your use of DMN stops at DRDs and decision tables, you owe it to yourself to go further. The creators of DMN created these boxed expressions for you, since breaking complex logic apart using standardized table formats makes them easier to create and easier to understand than long, complex FEEL expressions. It’s really not so hard. If you want to learn more about how to do it, check out the book DMN Method and Style 3d edition or our DMN Method and Style training. You’ll be glad you did!

Follow Bruce Silver on Method & Style.

Blog Articles

Bruce Silver

View all

All Blog Articles

Read our experts’ blog

View all

Learn how it works

Request Demo

Confirm your budget

Request Pricing

Discuss your project

Request Meeting
Graph