What is DECISION MODEL AND NOTATION™ (DMN™)?
DMN stands for Decision Model and Notation. It is a standard administered by an OMG institution (opens in a new tab) and has been widely adopted across various industries. Businesses leverage DMN to design decision models that are used for automation of the decision-making processes. DMN serves as a common language to align business and IT on repeatable business rules and decision management. The notation enhances business efficiency, reduces the risk of human error, and ensures that decision models are interchangeable across the organization. SPECIFICATION OF BUSINESS DECISIONS AND BUSINESS RULES (opens in a new tab)
Core elements of DMN include:
- Decision tables – Simple and intuitive representation of decisions consisting of input, condition, and output.
- Friendly Enough Expression Language (FEEL) – Used to express conditions in the decision tables so they can be executed.
- Decision Requirements Diagrams (DRD) – Created when a decision can not be described in just one simple table. For example, when there are dependencies between intermediate decisions output from which serve as an input for the final decision to be made.
In Flower DMN is basically used to make decisions for BPMN gateways and update Jira issue fields on the fly. Read how Flower uses DMN
Get Started
The DMN editor is integrated in the Flower BPMN modeler, so you can always switch between BPMN and DMN. Once a DMN model has been created you can evaluate the model in conjunction with the current BPMN and example Jira issues. Read more about evaluating DMN
NOTE: In contrast to the BPMN model, the DMN model is not yet versioned. The draft is at the same time also the published version.
Introducing FEEL
DMN defines the friendly enough expression language (FEEL) for the purpose of giving standard executable semantics to many kinds of expressions in decision model. It is also part of the DMN standard (opens in a new tab) defined by the OMG. FEEL defines a syntax for expressing conditions that input data should be evaluated against. For example, you can describe in FEEL that a certain input data should be
- a concrete string (like the season, that should be “summer”)
- true or false (like the fact that our guests are vegetarians)
- a number that is below, above or the exact same like another given number
- a number that is between a minimum and a maximum given number
- a date that is before, later or the same like another given date
- …and much more
Sample FEEL Expressions
Some valid FEEL expressions (logically categorized):
Arithmetic
- a + b - c
- ((a + b)/c - (d + e*2))**f
- 1-(1+rate/12)**-term
- (a + b)**-c
- date("2012-12-25") + date("2012-12-24")
- time("T13:10:06") - time("T13:10:05")
- date and time("2012-12-24T23:59:00") + duration("P1Y")
Comparision
- "thisStringValue"
- not("thisStringValue")
- 5 in (<= 5)
- 5 in ((5..10])
- 5 in ([5..10])
- 5 in (4,5,6)
- 5 in (<5,>5)
- (a + 5) >= (7 + g)
- (a+b) between (c + d) and (e - f)
- date("2012-12-25") > date("2012-12-24")
- date and time("2012-12-24T23:59:00") < date and time("2012-12-25T00:00:00")
Conjunction
- a or b
- a and b
- ((a or b) and (b or c)) or (a and d)
- ((a > b) and (a > c)) and (b > c)
- ((a + b) > (c - d)) and (a > b)
- a or b or a > b
- (x(i, j) = y) and (a > b)
- (a + b) > (c - d) and (a > b)
For
- for a in [1,2,3] return a * a
- for age in [18..40], name in ["george", "mike", "bob"] return status
Function Definition
- function(age) age < 21
- function(rate, term, amount) (amount*rate/12)/(1-(1+rate/12)**-term)
If
- if applicant.maritalStatus in ("M", "S") then "valid" else "not valid"
- if Pre-Bureau Risk Category = "DECLINE" or Installment Affordable = false or Age < 18 or Monthly Income < 100 then "INELIGIBLE" else "ELIGIBLE"
- if "Pre-Bureau Risk Category" = "DECLINE" or "Installment Affordable" = false or Age < 18 or "Monthly Income" < 100 then "INELIGIBLE" else "ELIGIBLE"
Quantified
- some ch in credit history satisfies ch.event = "bankruptcy"
Date Time Semantics
- time("13:10:05@Etc/UTC").hour
- time("13:10:05@Etc/UTC").minute
- time("13:01:05+05:30").second
- date and time("2012-12-24T23:59:00").year
- date("2017-06-10").month
- date("2017-06-10").day
- duration("P13M").years
- duration("P1Y11M").months
- duration("P5DT12H10M").days
- duration("P5DT12H10M").hours
- duration("P5DT12H10M").minutes
- duration("P5DT12H10M25S").seconds
Date Time Conversion and Equality
- date("2012-12-25") – date("2012-12-24") = duration("P1D")
- date and time("2012-12-24T23:59:00") + duration("PT1M") = date and time("2012-12-25T00:00:00")
- time("23:59:00z") + duration("PT2M") = time("00:01:00@Etc/UTC")
- date and time("2012-12-24T23:59:00") - date and time("2012-12-22T03:45:00") = duration("P2DT20H14M")
- duration("P2Y2M") = duration("P26M")
Please note: This is not a complete list of FEEL Expressions. Please refer DMN Specification Document (opens in a new tab) for detailed documentation on FEEL grammar.
Evaluate DMN in Flower
The result of evaluating a decision table is
undefined
if no rule matched- an array of objects if the hit policy of the decision table is COLLECT or RULE ORDER (one array item for each matching rule)
- an object if the hit policy of the decision table is FIRST or UNIQUE and a rule matched
The object for a matching rule contains the evaluated output value(s) of the rule. The structure is defined by the output names. Qualified names with a dot (.) inside lead to nested objects. See the following example:
An object for a matching rule of the above table would look like this:
{
plainOutputProperty: '...',
output: {
property: '...',
nested: {
property: '...',
},
}
}
Supported content in decision tables
Input expressions are commonly (qualified) names, like so:
- customerAge
- customer.age
Input expressions are however not restricted to qualified names. You can use any expression according to S-FEEL, and additionally even function invocations, too, like so:
- employee.salary * 12
- convertToUSD(employee.salary)
Built-in functions
Flower supports the following built-in functions from DMN:
- string functions:
starts with, ends with, contains, upper case, lower case
- boolean functions:
not
- list functions:
list contains, count, min, max, sum, mean, and, or, append, concatenate, insert before, remove, reverse, index of, union, distinct values, flatten
Input entries
As input entries, simple unary tests according to the DMN specification are supported, with some additions:
- an endpoint can also be arithmetic expression
- a simple value can also be function invocation
- a simple literal can also be a null literal
- a date time literal can also be "date and time"
- brackets in arithmetic expressions are supported
- additional name symbols are not supported
Examples (the list is not complete though):
Input entry | matches if the input expression evaluates to... |
---|---|
42 | the numeric value 42 |
< 42 | a value less than 42 |
[41 .. 50] | a value between 41 and 50 (inclusive) |
10, 20 | either 10 or 20 |
<10, >20 | a value either less than 10 or greater than 20 |
"A" | the string "A" |
"A", "B" | the string "A" or "B" |
true | the boolean value true |
- | any value, even undefined |
any value, even undefined (sams as -) | |
null | the value null or undefined |
not(null) | any value other than null or undefined |
property | the same value as the property (must be given in the context) |
object.property | the same value as the property of the object |
f(a) | the same value as the function evaluated with the property (function and property must be given in the context) |
limit - 10 | the same value as the limit minus 10 |
limit * 2 | the same value as the limit times 2 |
[limit.upper, limit.lower] | a value between the value of two given properties of object limit |
date("2017-05-01") | the date value Mai 1st, 2017 (date is a built-in function) |
date(property) | the date which is defined by the value of the given property, the time if cropped to 00:00:00 |
date and time(property) | the date and time which is defined by the value of the given property (date and time is a built-in function) |
duration(d) | the duration specified by d, an ISO 8601 duration string like P3D for three days (duration is built-in either) |
duration(d) * 2 | twice the duration |
duration(begin, end) | the duration between the specified begin and end date |
date(begin) + duration(d) | the date that results by adding the given duration to the given date |
< date(begin) + duration(d) | any date before the date that results by adding the given duration to the given date |
Most combinations of the syntax elements above are valid, too. For example the following is a valid input entry (although it probably does not make any sense):
not(f(a + 1), [ date(b) + duration(c.d) .. g(d) ])
Input variables as parameters to functions in input entries
Sometimes, one whishes to use the value of an input expression as a parameter to a function in an input entry, for example to test that a given input string contains a certain substring, where each substring to test for constitutes a different rule. This could be used for example to derive the project name from the prefix of an issue ID, like so:
The starts with(string, substring)
function allows to test if a string starts with a given prefix,
but with S-FEEL it is not possible to use the value of an input expression as input variable to the function.
Basically, if the input expression is issueId
, and the input entry is starts with(issueId, "CAM")
, then the input entry
will be evaluated to true
if the value of issueId
is for example CAM-42
, but a rule with this input entry
will still not match since true
does not equal the value of the input expression, which is CAM-42
.
Flower DMN follows a pragmatic approach to allow for input variable in input entries.
The convention is: if an input expression is a qualified name (in DMN sense), and
an input entry contains a function which takes the same qualified name as one of its parameters,
and the function evaluates to true
, then the rule will match with respect to this
input entry (it may still not match because of non-matching other input entries).
The decision table shown above can therefore be used to derive the project name from the issue prefix.
Output entries
A simple expression according to the DMN specification is supported as output entry, with the same additions as mentioned for input entries. Since output entries are expressions, not comparisons, values like the following are not allowed:
- < 1
- [1 .. 2]
- not("A")
- empty values (this includes the dash -)
Undefined values
Flower DMN allows function and properties that are referenced by input expressions, input entries, and output entries, to be undefined or missing from the input context. Undefined values are handled as follows:
Evaluation of input expressions, input entries, and output entries
Input expressions, input entries, and output entries evaluate to undefined if they contain a function or a property which is not found in the input context or is contained there with undefined value. Undefinedness cannot be compared or checked for equality: for undefined values 'a' and 'b', the expression
a = b
evaluated to undefined, not to true.
There is one exception though: there is a built-in function 'defined' which returns true if the given argument is neither null nor undefined, and false if the given argument is null or undefined.
Matching of rules
If an input expression evaluates to undefined, any rule whose corresponding input entry is not empty (neither the empty string literal nor the dash -) does not match, regardless of to which value (or undefined) the input entry evaluates.
If an input entry evaluates to undefined, the containing rule does not match, regardless of to which value the corresponding input expression evaluates.
Decision result
If an output entry of a matching rule evaluates to undefined, the variable defined by the output name is set to undefined, if the hit policy is UNIQUE or FIRST. If the hit policy is COLLECT or RULE ORDER, the undefined output entry value is not added to the result list.
Custom functions
If you cannot rule out undefined values, your custom functions should check their arguments for undefined values, and return undefined in turn if one or more of the arguments are themselves undefined.
Passing dates as input
For input expressions, input values, or output values of the following type:
date(property)
date and time(property)
the value of 'property' can be created in the following way:
// for dates only: date string in the format YYYY-MM-DD
const context = {
property: '2018-03-01';
}
// for date and time: ISO8601 date/time string
const context = {
property: '2018-03-01T14:30:00+01:00';
}
// Javascript date - a) from numerical year, month, ... values
const context = {
property: new Date(2018, 2, 1, 0, 0, 0); // note that this will be implicitly in the local time zone!
}
// Javascript date - b) from string with explicit time zone
const context = {
property: new Date('2018-03-01T00:00:00+01:00');
}
// moment-js value
const context = {
property: moment.parseZone('2018-03-01T00:00:00+01:00')
}
Syntactically, any Date or moment-js value is fine, regardless of how you created it.
warning: Heads up! The built-in date function crops the time portion of a Javscript Date or moment-js date after converting the date to a UTC timezone. Therefore, date('2018-03-01T00:00:00.000+01:00') actually resolves to Feburary 28th, 2018, but not March 1st, 2018, since in UTC time zone the date/time is '2018-02-28T23:00:00.000+00:00'.
How Flower interpretes the DMN result
Flower uses the DMN result to make decisions in your BPMN model and to updates certain Jira issues, that are related with your Process Instance.
To support the development process, the Flower DMN modeller offers the possibility to test Decision Tables in conjunction with the BPMN model and Jira. For this purpose, BPMN activities including the process instance can be mapped with existing Jira issue keys.
If the "Apply DMN result" checkbox is checked, the result is applied directly. This means the decision is saved on the process instance tick and data fields are saved on the Jira tick test directly.
A general JSON format, as a result of the DMN evaluation, that Flower can interpret is of the following form:
{
decisions:{
gatewayId:[transitionId],
gatewayId:transitionId
},
issueUpdates:{
nodeId:{fieldId:value},
nodeId:{description:'Lorem ipsum'}
}
}
The following example makes a decision in the Flower process based on the summary field of the process instance:
This produces the following JSON. The corresponding node and gateway ids must of course be taken from the BPMN diagram.
{
"issueUpdates": {
"pi": {
"description": "decision made here"
}
},
"decisions": {
"ExclusiveGateway_1cbd88k": "SequenceFlow_0vysjno"
}
}
Examples to address Jira fields
Expression | |
---|---|
pi.summary | The process instance's summary |
pi.key | The process instance's key |
pi.project.key | The process instance's project key |
pi.customfield_10016 | The process instance's story point field (number field) |
pi.customfield_10123.value | The process instance's custom select field (dropdown field) |
pi.reporter.displayName | The process instance's reporter e.g. 'Tom Smith' |
pi.status.statusCategory.name | The process instance's status category e.g. 'In Progress' |
date and time(pi.created) < date and time(pi.lastViewed) | The process instance has been viewed after creation |
pi.priority.name | The process instance's priority name e.g. 'Medium' |
contains(pi.description,'screen') | The process instance's description field contanig 'screen' |
count(pi.comment.comments) > 1 | The process instance has at least one comment (array field |
Debugging
Sometimes it is difficult to formulate the correct dmn expression and to address a Jira field correctly. For that reason, further debugging details are logged on the developer console.
Try Flower Process Automation for free
Unlock the full power of Jira by aligning and streamlining your BPMN processes and workflows directly with your team: Every business process turns into an automated Jira workflow by creating a Jira issue for each business process activity.