Guia DMN
Guia completo para criar decisões usando DMN (Decision Model and Notation) é a linguagem FEEL (Friendly Enough Expression Language).
O que é DMN?
DMN é um padrão da OMG (Object Management Group) para modelar decisões de negócio de forma visual e executável. O Decision Engine utiliza o Camunda DMN Engine que implementa o padrão DMN 1.3.
Vantagens do DMN
- Padronizado: Padrão internacional reconhecido
- Visual: Pode ser modelado em ferramentas gráficas
- Executável: O mesmo modelo é usado para documentação e execução
- Auditável: Trace completo de todas as regras avaliadas
Estrutura do XML
Um arquivo DMN é composto por elementos XML que definem a estrutura da decisão.
Estrutura Básica
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/"
id="minha_decisao"
name="Minha Decisão"
namespace="http://minha-empresa.com/dmn">
<decision id="decisionId" name="Nome da Decisão">
<decisionTable id="tableId" hitPolicy="FIRST">
<!-- Inputs -->
<input id="input1" label="Label do Input">
<inputExpression typeRef="number">
<text>nomeVariavel</text>
</inputExpression>
</input>
<!-- Output -->
<output id="output1" name="resultado" typeRef="string"/>
<!-- Rules -->
<rule id="rule1">
<description>Descrição da regra</description>
<inputEntry><text>condição</text></inputEntry>
<outputEntry><text>"valor"</text></outputEntry>
</rule>
</decisionTable>
</decision>
</definitions>
Elementos Principais
| Elemento | Descrição |
|---|---|
definitions | Elemento raiz do DMN |
decision | Define uma decisão |
decisionTable | Tabela de decisão com regras |
input | Define uma variável de entrada |
output | Define a saída da decisão |
rule | Define uma regra com condições |
Decision Tables
A Decision Table é o coração do DMN. É uma tabela onde cada linha é uma regra e cada coluna é uma condição ou saída.
Estrutura Visual
Uma Decision Table é organizada como uma tabela:
Colunas:
- Inputs (esquerda): Variáveis de entrada que serão avaliadas
- Output (direita): Resultado retornado pela regra
Linhas:
- Header: Define os inputs e output
- Rules: Cada linha é uma regra com condições e resultado
Exemplo de Decision Table:
Inputs:
- Input 1: Score de crédito (variável
score) - Input 2: Renda mensal (variável
rendaMensal) - Input 3: Ratio de endividamento (variável
endividamento)
Output:
- resultado: Status da aprovação
Rules:
-
Regra Premium:
score >= 800ErendaMensal >= 10000Eendividamento < 0.3→"PREMIUM"
-
Regra Aprovado:
score >= 600ErendaMensal >= 5000Eendividamento < 0.5→"APROVADO"
-
Regra Fallback (catch-all):
- Qualquer valor (
-) E Qualquer valor (-) E Qualquer valor (-) →"NEGADO"
- Qualquer valor (
Inputs
Cada input define uma variável que será avaliada:
<input id="scoreInput" label="Credit Score">
<inputExpression typeRef="number">
<text>score</text>
</inputExpression>
</input>
<input id="incomeInput" label="Renda Mensal">
<inputExpression typeRef="number">
<text>rendaMensal</text>
</inputExpression>
</input>
Outputs
Define o resultado da decisão:
<!-- Output simples -->
<output id="resultOutput" name="resultado" typeRef="string"/>
<!-- Múltiplos outputs -->
<output id="statusOutput" name="status" typeRef="string"/>
<output id="taxaOutput" name="taxa" typeRef="number"/>
<output id="parcelasOutput" name="parcelas" typeRef="number"/>
Rules
Cada rule define uma combinação de condições e seu resultado:
<rule id="rule_premium">
<description>Cliente premium - score excelente</description>
<inputEntry><text>>= 800</text></inputEntry> <!-- score >= 800 -->
<inputEntry><text>>= 10000</text></inputEntry> <!-- renda >= 10000 -->
<outputEntry><text>"PREMIUM"</text></outputEntry>
</rule>
No XML, os caracteres < e > precisam ser escapados:
<→<>→>
Hit Policies
A Hit Policy define como as regras são avaliadas quando mais de uma pode ser acionada.
| Policy | Símbolo | Descrição | Resultado |
|---|---|---|---|
FIRST | F | Retorna a primeira regra acionada | Único |
UNIQUE | U | Apenas uma regra deve ser acionada | Único |
ANY | A | Qualquer regra pode ser acionada (mesmo resultado) | Único |
COLLECT | C | Coleta todas as regras acionadas | Lista |
RULE ORDER | R | Retorna na ordem das regras | Lista |
OUTPUT ORDER | O | Retorna ordenado pelo output | Lista |
FIRST (Recomendado)
A política mais comum. Retorna o resultado da primeira regra que satisfaz todas as condições.
<decisionTable id="table" hitPolicy="FIRST">
<!-- Regras são avaliadas na ordem, para na primeira que aciona -->
<rule id="r1">...</rule> <!-- Se acionar, retorna e para -->
<rule id="r2">...</rule> <!-- Só avalia se r1 não acionou -->
<rule id="r3">...</rule> <!-- Só avalia se r1 e r2 não acionaram -->
</decisionTable>
UNIQUE
Exige que apenas uma regra seja acionada. Útil quando as condições são mutuamente exclusivas.
<decisionTable id="table" hitPolicy="UNIQUE">
<rule id="r1">
<inputEntry><text>[0..599]</text></inputEntry> <!-- 0-599 -->
</rule>
<rule id="r2">
<inputEntry><text>[600..799]</text></inputEntry> <!-- 600-799 -->
</rule>
<rule id="r3">
<inputEntry><text>>= 800</text></inputEntry> <!-- 800+ -->
</rule>
</decisionTable>
COLLECT
Coleta todos os resultados das regras acionadas.
<decisionTable id="table" hitPolicy="COLLECT">
<!-- Pode retornar múltiplos resultados -->
</decisionTable>
Tipos de Dados
O DMN suporta os seguintes tipos:
| Tipo | Descrição | Exemplo |
|---|---|---|
string | Texto | "aprovado" |
number | Número (inteiro ou decimal) | 720, 0.05 |
boolean | Verdadeiro/Falso | true, false |
date | Data | date("2024-01-15") |
time | Hora | time("14:30:00") |
dateTime | Data e hora | dateTime("2024-01-15T14:30:00") |
Sintaxe FEEL
FEEL (Friendly Enough Expression Language) é a linguagem de expressão usada no DMN.
Comparações Numéricas
| Expressão | Descrição | Exemplo |
|---|---|---|
>= valor | Maior ou igual | >= 600 |
<= valor | Menor ou igual | <= 100000 |
> valor | Maior que | > 0 |
< valor | Menor que | < 0.5 |
= valor | Igual a | = 720 |
!= valor | Diferente de | != 0 |
<inputEntry><text>>= 600</text></inputEntry>
<inputEntry><text>< 0.5</text></inputEntry>
Ranges (Intervalos)
| Expressão | Descrição | Exemplo |
|---|---|---|
[a..b] | Intervalo fechado (inclui a e b) | [600..799] |
(a..b) | Intervalo aberto (exclui a e b) | (0..1) |
[a..b) | Fechado-aberto | [0..100) |
(a..b] | Aberto-fechado | (0..100] |
<!-- Score entre 600 e 799 (inclusive) -->
<inputEntry><text>[600..799]</text></inputEntry>
<!-- Percentual entre 0 e 1 (exclusivo nas pontas) -->
<inputEntry><text>(0..1)</text></inputEntry>
Strings
| Expressão | Descrição |
|---|---|
"valor" | String literal |
"BMW", "Mercedes" | Lista de valores possíveis |
<!-- Marca igual a "BMW" -->
<inputEntry><text>"BMW"</text></inputEntry>
<!-- Output string -->
<outputEntry><text>"APROVADO"</text></outputEntry>
Wildcard (Qualquer Valor)
O caractere - significa "qualquer valor" (sempre match):
<!-- Aceita qualquer valor -->
<inputEntry><text>-</text></inputEntry>
Negação
Use not() para negar uma condição:
<!-- Não é "BMW" -->
<inputEntry><text>not("BMW")</text></inputEntry>
<!-- Não está no range -->
<inputEntry><text>not([0..100])</text></inputEntry>
Null Check
<!-- Valor é null -->
<inputEntry><text>null</text></inputEntry>
<!-- Valor não é null -->
<inputEntry><text>not(null)</text></inputEntry>
List Contains
Para verificar se um valor está em uma lista:
<inputEntry>
<text>list contains(["BMW", "Mercedes", "Audi", "Porsche"], marca)</text>
</inputEntry>
Use list contains([lista], variavel) quando precisar verificar se um valor está em uma lista de opções. A variável deve ser referenciada pelo nome definido no input.
Expressões Compostas
Combine expressões com and e or:
<!-- score >= 600 AND renda >= 5000 -->
<inputEntry><text>score >= 600 and renda >= 5000</text></inputEntry>
Boas Práticas
1. Use IDs Descritivos
<!-- Bom -->
<rule id="rule_denied_low_score">
<rule id="rule_approved_premium">
<rule id="rule_manual_review">
<!-- Evite -->
<rule id="r1">
<rule id="rule1">
2. Adicione Descriptions
<rule id="rule_denied_score">
<description>Negado - Score abaixo do mínimo permitido (500)</description>
...
</rule>
3. Ordene Regras Estrategicamente
Com hitPolicy="FIRST", coloque regras mais específicas primeiro:
<!-- 1. Regras de negação primeiro (mais específicas) -->
<rule id="rule_denied_score">...</rule>
<rule id="rule_denied_income">...</rule>
<!-- 2. Regras de aprovação específicas -->
<rule id="rule_approved_premium">...</rule>
<rule id="rule_approved_excellent">...</rule>
<!-- 3. Regras genéricas por último -->
<rule id="rule_approved_regular">...</rule>
<!-- 4. Fallback (catch-all) -->
<rule id="rule_manual">
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"ANALISE_MANUAL"</text></outputEntry>
</rule>
4. Use Hit Policy FIRST
Na maioria dos casos, FIRST é a política mais intuitiva e fácil de debugar.
5. Evite Condições Sobrepostas com UNIQUE
Se usar UNIQUE, garanta que as condições são mutuamente exclusivas:
<!-- Correto: ranges não se sobrepõem -->
<rule><inputEntry><text>[0..599]</text></inputEntry>...</rule>
<rule><inputEntry><text>[600..799]</text></inputEntry>...</rule>
<rule><inputEntry><text>>= 800</text></inputEntry>...</rule>
<!-- Errado: regras podem acionar juntas -->
<rule><inputEntry><text>>= 500</text></inputEntry>...</rule>
<rule><inputEntry><text>>= 600</text></inputEntry>...</rule>
6. Sempre Tenha um Fallback
Inclua uma regra catch-all para evitar resultados inesperados:
<rule id="rule_fallback">
<description>Caso não coberto - análise manual</description>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<inputEntry><text>-</text></inputEntry>
<outputEntry><text>"ANALISE_MANUAL"</text></outputEntry>
</rule>
Ferramentas
Camunda Modeler
O Camunda Modeler é uma ferramenta gratuita para criar DMN visualmente.
Validação
O Decision Engine valida o DMN no momento da criação da versão. DMN inválido retorna erro 400.