red6/dmn-check
GitHub: red6/dmn-check
一个用于对 DMN 决策模型文件执行静态分析的工具,可自动检测决策表中的逻辑错误和结构缺陷。
Stars: 42 | Forks: 14

[](https://red6.github.io/dmn-check/javadoc/)
[](https://sonarcloud.io/dashboard?id=red6_dmn-check)
[](http://search.maven.org/#search|gav|1|g:"de.redsix"%20AND%20a:"dmn-check")
# dmn-check
这是一个用于验证 [Decision Model Notation (DMN)](https://en.wikipedia.org/wiki/Decision_Model_and_Notation) 文件的工具。它
执行各种静态分析以检测决策模型中的不一致和错误。
您可以通过六种方式使用 `dmn-check`。
* 作为 [Maven](https://maven.apache.org/) 或 [Gradle](https://gradle.org/) 插件,可以集成到您的构建
过程和持续集成中,以防止错误混入您的工件中。
* 通过 dmn-check 插件集成到 [Camunda Modeler](https://camunda.com/products/modeler/) 中。
* 通过使用 [dmn-check-core](https://search.maven.org/artifact/de.redsix/dmn-check-core) 或
[dmn-check-validators](https://search.maven.org/search?q=a:dmn-check-validators) 工件集成到您的自定义工具中。
* 作为独立的 CLI 工具。
* 作为 [Docker 镜像](https://github.com/red6/dmn-check/pkgs/container/dmn-check)(例如在您的 CI 流水线中)。
* 集成在 [dmnmgr](https://github.com/davidibl/dmnmgr-client) 中。
目前,`dmn-check` 会检查以下内容(包括但不限于):
* 重复规则
* 冲突规则
* 遮蔽规则
* 表达式类型
* 枚举的正确使用
* 正确连接的需求图
在[验证](#validations)部分,您可以找到包含其功能详细描述的完整列表。
`dmn-check` 验证的大多数属性和不变量在
[DMN 规范](https://www.omg.org/spec/DMN) 中进行了非正式的描述。如果您对某项验证有疑问,
不妨浏览一下该规范。
## Maven 插件
### 前置条件
此插件需要 Java 21 或更高版本以及 Apache Maven 3 或更高版本。一些分析是针对 Camunda DMN 实现量身定制的,
可能不适用于不同的 DMN 实现。
### 用法
`dmn-check` 既可以在您项目的 `pom.xml` 中作为普通的 Maven 插件使用,也可以作为独立程序使用。
#### 在 POM 中配置
以下示例展示了插件的基本配置:
```
de.redsix
dmn-check-maven-plugin
...
verify
check-dmn
```
使用此配置,插件将在当前项目的所有文件夹中搜索扩展名为 `.dmn` 的文件,并应用所有
可用的验证器。也可以提供一组搜索路径,以及忽略某些文件并指定应执行的
验证器。以下示例展示了如何利用这些选项:将搜索路径限制为
文件夹 `src/` 和 `model/`,并忽略文件 `test.dmn`。该配置还进一步指定了仅执行
[`ShadowedRuleValidator`](#shadowed-rules)。要指定验证器,您必须使用完全限定名。
```
src/
model/
test.dmn
de.redsix.dmncheck.validators.ShadowedRuleValidator
```
此外,可以设置 `failOnWarning` 参数(默认为 false),以便在存在
严重级别为警告的验证错误时,使 Maven 执行失败。
```
true
```
#### 独立使用
要在没有 Maven 项目或在 Maven 项目之外使用 `dmn-check`,您可以通过以下方式调用它
```
mvn de.redsix:dmn-check-maven-plugin:check-dmn
```
## Gradle 插件
### 前置条件
此插件需要 Java 11 或更高版本以及 Gradle 6.5 或更高版本。一些分析是针对 Camunda DMN 实现量身定制的,
可能不适用于不同的 DMN 实现。
## 集成在 dmnmgr 中
Dmnmgr 是一个_整合了 Camunda DMN 实现的工具包,提供工具以支持跨职能团队开发基于 DMN 的应用程序。
它内置了 `dmn-check` 集成,并在 DMN 模型的图形表示中可视化警告和错误。你需要安装 [dmnmgr-client](https://github.com/davidibl/dmnmgr-client) 和 [dmnmgr-server](https://github.com/davidibl/dmnmgr-server) 才能使用它。
## 作为 Docker 容器
包含 `dmn-check` 的 Docker 镜像可从 GitHub Container Registry 获取,您可以通过执行以下命令拉取最新版本
```
docker pull ghcr.io/red6/dmn-check:latest
```
如果您想使用 `docker run` 执行 `dmn-check`,您必须将包含 DMN 文件的目录挂载到
容器中并适当地设置搜索路径,例如
```
docker run -v ~/dmn-files:/dmn-files ghcr.io/red6/dmn-check:latest --searchPath=/dmn-files
```
如果您想在 Gitlab 流水线中使用 Docker 镜像,您必须覆盖入口点并直接调用 `dmn-check`。
在以下 Gitlab 流水线示例中,我们还指定了项目类路径,以使枚举验证成为可能。
```
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
default:
artifacts:
paths:
- ./cp.txt
- .m2/repository
stages:
- analysis
image:
name: ghcr.io/red6/dmn-check:latest
entrypoint: [ "" ]
create-classpath-for-dmn-check:
image: adoptopenjdk/maven-openjdk11
stage: analysis
script: mvn dependency:build-classpath --settings .m2/settings.xml --batch-mode -Dmdep.outputFile=cp.txt
dmn-check:
stage: analysis
needs:
- create-classpath-for-dmn-check
script: |
/opt/java/openjdk/bin/java -cp /app/resources:/app/classes:/app/libs/* de.redsix.dmncheck.cli.Main --projectClasspath=$(< cp.txt)
```
## 验证
以下小节详细介绍了可用的验证。本节中使用的 DMN 决策表源自
[camunda.org](https://camunda.org/) 上的一个示例。
### 重复规则
考虑以下命中策略为 `UNIQUE` 的 DMN 决策表:
| | Season ᴵᴺᴾᵁᵀ | How many guests ᴵᴺᴾᵁᵀ | Dish ᴼᵁᵀᴾᵁᵀ |
| --- | ------------- | --------------------- | ----------- |
| 1 | "Fall" | <= 8 | "Spareribs" |
| 2 | "Winter" | <= 8 | "Roastbeef" |
| 3 | "Spring" | [5..8] | "Steak" |
| 4 | "Winter" | <= 8 | "Roastbeef" |
很明显,规则二与规则四重复。这不符合 `UNIQUE` 命中策略的
要求,因此是一个错误。
**定义**:当且仅当两条规则的所有输入和输出完全相同时,一条规则是另一条规则的重复。
`dmn-check` 将为除命中策略为 `COLLECT` 之外的所有决策表报告重复规则。
### 冲突规则
冲突规则在某种程度上类似于重复规则。考虑以下命中策略为 `UNIQUE` 的示例:
| | Season ᴵᴺᴾᵁᵀ | How many guests ᴵᴺᴾᵁᵀ | Dish ᴼᵁᵀᴾᵁᵀ |
| --- | ------------- | --------------------- | ----------- |
| 1 | "Fall" | <= 8 | "Spareribs" |
| 2 | "Winter" | <= 8 | "Roastbeef" |
| 3 | "Spring" | [5..8] | "Steak" |
| 4 | "Winter" | <= 8 | "Stew" |
我们再次查看规则二和规则四。这一次,它们的所有输入都相同,但输出不同。这可以说比
重复规则更糟糕,因为它可能会根据决策表的评估顺序产生不同的结果。假设运行时
没有检测到这些不一致。
**定义**:当且仅当规则 `r` 和规则 `s` 的所有输入相同,且它们在至少一个输出上不同时,
规则 `r` 与规则 `s` 冲突。
`dmn-check` 将为除命中策略为 `COLLECT` 和 `RULE_ORDER` 之外的所有决策表报告重复规则。
### 遮蔽规则
某些规则会阻止其他规则被考虑。请看以下命中策略为 `FIRST` 的示例:
| | Season ᴵᴺᴾᵁᵀ | How many guests ᴵᴺᴾᵁᵀ | Dish ᴼᵁᵀᴾᵁᵀ |
| --- | ------------- | --------------------- | ------------|
| 1 | "Fall" | <= 8 | "Spareribs" |
| 2 | "Winter" | <= 8 | "Roastbeef" |
| 3 | – | – | "Stew" |
| 4 | "Spring" | [5..8] | "Steak" |
此示例不包含重复规则,也不包含冲突规则。然而,规则三的所有输入都为空(在本例中以破折号表示)。
由于空输入匹配任何内容,并且由于我们假设命中策略为 `FIRST`,规则四将永远不会匹配,因为规则三匹配
所有可能的输入。因此,在春季会向 5 到 8 位客人提供炖菜。假设每条规则都有其目的,被遮蔽的规则
总是一个错误,因为它们永远不会被匹配到。
**定义**:当且仅当规则 `r` 的输入至少匹配规则 `s` 的输入匹配的所有值时,
规则 `r` 遮蔽了规则 `s`。
`dmn-check` 将为除命中策略为 `COLLECT` 和 `RULE_ORDER` 之外的所有决策表报告重复规则。
### 表达式类型
DMN 提供了一种名为 [Friendly Enough Expression Language](https://docs.camunda.io/docs/components/modeler/feel/what-is-feel/) (FEEL) 的丰富表达式语言,可用于描述输入项的条件。然而,与大多数
表达式语言一样,并非所有语法上可能的表达式都是有效的(具有语义)。`dmn-check` 集成了一个用于
FEEL 表达式语言的类型检查器,以确保决策表仅包含类型良好的表达式。
一个类型不正确的表达式示例是 `[1..true]`,它将描述 `1` 和 `true` 之间的范围,这(至少在 FEEL 中)不是一个
有效的表达式。相反,`[1..9]` 是类型良好的,描述了从 1 到 9 的数字。
| FEEL-Expression | Type |
| ---------------- | ----- |
| true | boolean |
| [1..3] | integer |
| [1.."string"] | ✘ |
| 1, 2, true | ✘ |
| > 5 | integer |
| > true | ✘ |
当然,类型声明也会被验证。
### 枚举的正确使用
决策通常涉及一组固定的值(例如,支持的货币列表),因此这些值会被用在 DMN
决策表中。这些值通常以 Java 枚举的形式实现。`dmn-check` 还允许在输入/输出列的类型声明中
指定枚举的完全限定类名,并根据枚举实现检查 DMN 决策表中的值。
默认情况下,`dmn-check` 使用项目依赖来解析枚举。由于在 Maven
独立模式下无法做到这一点,您可以指定用于解析枚举的类路径
```
mvn de.redsix:dmn-check-maven-plugin:check-dmn -Dclasspath=foo.jar,bar.jar
```
### 正确连接的需求图
DMN 标准还提供了一种将决策表相互连接以及建模输入和知识源的方法。由此产生的
图被称为[决策需求图 (DRG)](https://docs.camunda.org/manual/latest/reference/dmn/drg/)。
`dmn-check` 验证决策需求图
- 是[连通的](https://en.wikipedia.org/wiki/Connectivity_(graph_theory))
- 是[有向无环的](https://en.wikipedia.org/wiki/Directed_acyclic_graph)
- 确保输入和输出的兼容性
- 只有一个叶节点(即,恰好有一个节点决定输出)
- 没有(自)环
在以下示例中,决策表 `Dish` 将 `Season` 和 `How many guests` 作为输入,但连接到该决策表的输入不是 `Season`,
而是输入 `Lunar phase`。
```
graph TD;
x(Lunar phase)-->Dish;
y(How many guests)-->Dish;
Dish-->Beverages;
z(Guests with children)-->Beverages;
```
### 聚合的正确使用
DMN 标准允许对命中策略 collect 的值进行聚合。例如,您可以计算决策表中所有
匹配行的总和。您可以使用此功能来计算信用评分。
我们确保这些聚合仅应用于具有数字类型的列。此外,我们验证
聚合仅在命中策略为 collect 时使用。
### 缺少 Id 和名称
通常您不需要过多关心 DMN 元素的 id 和名称。然而,在升级和重构期间,
可能会发生丢失 id 或名称的情况。这些错误通常会在很长一段时间内被忽视。根据场景的不同,
缺少 id 或名称可能会破坏您的决策模型或使错误分析变得棘手。
`dmn-check` 验证以下 DMN 元素始终具有 id 和名称:
- Decision
- Definition
- InputData
- ItemDefinition
- KnowledgeSource
### 来自 `ItemDefinition` 的允许值
`ItemDefinition` 是 DMN 表达枚举的方式。在 `ItemDefinition` 的定义中,您可以声明哪些
值是被允许的。目前,我们仅验证 `ItemDefintion` 中的表达式是否类型良好。
## 相关工作
当我们开始开发 `dmn-check` 时,我们并没有找到适合我们需求且能在我们的 Camunda 风格
环境中运行的 DMN 文件分析工具。从那时起,DMN 变得越来越流行,其他工具也开始提供一些分析功能。如果您想知道
`dmn-check` 与其他工具相比如何,您可以在 [GCD](#GCD) 中阅读到对比。
### 一个用于分析 DMN 决策表的工具
Ülari Laurson 和 Fabrizio Maria Maggi 使用分析功能扩展了 Camunda 的 `dmn-js` 编辑工具包,并将其发布在
[github.com/ulaurson/dmn-js](https://github.com/ulaurson/dmn-js)。该工具能够检测语法和类型错误,并识别
重叠和缺失的规则。它还能够通过合并规则来简化决策表。在演示论文 [LM16](#LM16) 中,他们描述了
该工具。该工具执行的分析的更多详细信息发表在 [CDL+16](#CDL+16) 中。
## 参考文献
CDL+16 Calvanese, D., Dumas, M., Laurson, Ü., Maggi, F.M., Montali, M., Teinemaa, I.: Semantics and analysis of DMN
decision tables. In Proceedings of the 14th International Conference on Business Process Management (BPM) 2016
LM16 Laurson, Ü. and Maggi, F.M., 2016, September. A Tool for the Analysis of DMN Decision Tables. In BPM (Demos) (pp.
56-60).
BW-a Batoulis, K. and Weske, M., A Tool for Checking Soundness of Decision-Aware Business Processes.
BW-b Batoulis, K. and Weske, M., Disambiguation of DMN Decision Tables.
FMTV18 Figl, K., Mendling, J., Tokdemir, G. and Vanthienen, J., 2018. What we know and what we do not know about DMN.
Enterprise Modelling and Information Systems Architectures, 13, pp.2-1.
Silver16 Silver, B., 2016. Decision Table Analysis in DMN.
HDSV17 Hasic, F., De Smedt, J. and Vanthienen, J., 2017. Towards assessing the theoretical complexity of the decision
model and notation (dmn). Enterprise, Business-Process and Information Systems Modeling. Springer International Publishing.
GCD Grohé, C., Corea, C. and Delfmann P, 2021. [DMN 1.0 Verification Capabilities: An Analysis of Current Tool Support](https://www.researchgate.net/publication/353906682_DMN_10_Verification_Capabilities_An_Analysis_of_Current_Tool_Support). Business Process Management Forum, BPM Forum 2021, Rome, Italy.
Valencia-Parra, A., Parody, L., Varela-Vaca, A., Caballero, I., and Gómez-López M., 2020. DMN4DQ: When data quality meets DMN. Journal 'Decision Support Systems'.
标签:Bug检测, Camunda, DMN, Docker, Gradle插件, JS文件枚举, Maven插件, 业务规则管理, 云计算, 决策模型与表示法, 后台面板检测, 域名枚举, 安全防御评估, 开源框架, 持续集成, 模型验证, 规则引擎, 请求拦截, 错误基检测, 静态代码分析