规则写成带版本的数据

会变的制度条款存成带版本的行,改参数不改代码,每个时点的取值都查得到

SZV 把金额线、签核位序列、开关这类会变的制度条款存成带版本的数据行,用已有判据改参数时不必改代码。接入 AI 时,金额、是否需要审批这类判定用的值取自这些行,不取自模型。判据结构常变、规则极少且多年不动,或要用任意循环、任意跨单据汇总的业务,不适合这样存。

程序不含取值 但含取值的语义

常见的说法是「程序里没有条款」。更准确的说法是:程序不含取值,含解释取值的语义。

放在数据里留在程序里
金额线、时限、开关的值值怎样读:同一个键取哪一行,缺键怎么办
一个值的类型与合法范围每种类型怎样校验;类型本身是字典表里的一行,新增类型要加一行,再加一支校验函数
签核位序列与金额线引用每种判据的含义:「何时」一栏只写判据名,含义在解释器里

用已有判据重排位序列、换金额线,改的是数据,不改代码:注册表与金额档表随版本发布追加新行,旧行由触发器拒改拒删。新增一种判据,要给解释器加代码,见审批流转。

数据不都走同一条改法,哪类走哪条路见修改规则参数的唯一入口:规则参数的值与分支登记经变更单;金额档位与审批单型注册表随版本发布追加。

核对一次改动时,先问它用到新判据没有。没有,就只是改几行数据。

改一次值就追加一行

一条规则参数占一行,主键是键加生效时间。同一个键可以有多行,各带自己的生效时间。取值时,系统取已生效、未到期、生效时间最大的一行。生效时间写在未来,就是预约生效。

改值追加一行 按查询时点取值

图里 10-28 查询取到 7,11-01 查询取到 14,第一行没有动。键不存在时,结果是拒绝,没有缺省值顶替。

每一行还带版本整数(每次变更自增)、变更人、变更时间、变更理由和来源。键与生效时间不可改,改值只能追加。每次追加,前一行与新行的整行内容都写进另一张只追加的历史表。

生效时间取「期望生效时间」与「批准时刻」中较晚的一个,不倒填,见修改规则参数的唯一入口。这样回放取到的,是当时实际用过的值。

取值只按生效时间这一条轴,规则不表达追溯更正:事后发现过去的值设错了,只能追加一行,旧行仍留在历史里。要同时回答「当时生效的是什么」和「事后才知道应该是什么」,需要第二条时间轴,即双时间:一条记事实何时成立,一条记系统何时得知。

缺键就拒绝 租户行压过全局行

开关与参数的取值有固定顺序:全局行与租户行并存时,租户行压过全局行;同一级里取生效时间最晚的一行;每行有生效区间。

键不存在时,系统直接失败,不回落到环境变量,也不回落到代码里的缺省值。漏配的后果因此是「某件事做不了」,会有人来报告。若回落到缺省值,系统会悄悄用上一个没有人批准过的数。

规则表里查不到的东西,系统一律当作没有,不会替它编一个值。

类型 范围 次序由数据库检查

一行规则的类型与合法范围写在行里,写入时由数据库校验,越界的值进不了表。业务账号直连数据库,也要过这道检查。

次序约束也是数据。例如「提醒起点要早于升级起点」,这类跨两个键的关系存在一张字典表里,改值时一并校验。单行的 CHECK 约束只能比一个值,比不了两个键之间的先后。

防改写靠触发器:键与生效时间由触发器冻结,历史表拒绝改和删。触发器有一个前提。PostgreSQL 文档写明:默认启用的触发器只在会话复制角色为 origin 或 local 时触发;表属主可以停用触发器。SZV 把这些触发器声明为 ENABLE ALWAYS,让它在任何复制角色下都触发。这样挡住的是业务账号与误操作,挡不住拥有表属主或超级用户权限的人。

分支可调的属性是另一套

分支沿用总部的规则,只在少数属性上自己填值。这一套与上面的参数表是两种机制。

对象存什么
属性定义键、类型、范围、缺省值
取值覆盖行一个分支对一个属性填的值,只写与总部不同的那一项
分支主数据分支本身的一行;主数据指描述分支这类对象本身的基础资料
总部规则审批链、权限策略、规则参数、金额线挂在租户一级,分支沿用

取值规则很短:有覆盖行,用覆盖行;没有,用定义里的缺省值。新增一项可覆盖的属性,是加一行定义,分支的编辑页按定义表生成,多出一项,所有分支先显示缺省值。字典型属性的取值范围,是选项字典里已启用的那些选项。

新开分支是登记一行主数据。它的归属范围由所属类别推出,不由提交人自填;名称与编码查重;只新增,不修改已有分支。它走与其他规则改值同一条审批,批准后由写入入口追加,下一次读取即含新分支,见修改规则参数的唯一入口。完整做法见新开一家分支。

这一套有以下限度:

  • 加定义多出来的只是一个可填的值。没有代码读取它,它就不改变行为。新的计算方式仍要加代码。
  • 这是 EAV(实体、属性、值)形态:加属性不改表结构,代价是值的类型偏弱、难做联表汇总、难加外键。定义表里的类型与范围,收的是弱类型这一头。
  • 取值表里一个分支一个属性只有一行,没有生效时间。

总部改了某一项,所有沿用它的分支同步生效。这是便利,也让一次改动的影响面扩大到全部沿用者。

限制与不适用

  • 解释器仍在程序里。新增判据种类要发版,规则本身也要审查、要测试。
  • 解释器只提供已有的判据,包括累计线与窗口。要用任意循环、任意跨单据汇总的逻辑,须新增判据。
  • 判据结构常变,或规则极少且多年不动的业务,不适合这样存。

与常见做法对照

做法规则放在哪擅长取舍
SZV 规则表数据库里的行,值带版本与生效时间,判据含义在解释器阈值、位序列、开关这类取值型规则,按时点回放只提供已有判据,含累计线与窗口;任意循环、任意跨单汇总要新增判据,随发版
DMN 决策表决策建模标准:一行一条规则,多行同时命中怎么办由「命中策略」定,如 UNIQUE、FIRST、COLLECT(Camunda 文档)条件列多、要业务人员读懂的决策条件与结果的列要先建模好
OPA用 Rego 语言写策略,策略与数据打成 bundle 下发,bundle 可带 revision 标识版本(OPA 文档)判定逻辑复杂、要跨系统统一策略策略是代码,审查与测试走代码流程

SZV 的签核规则是「按序首条命中,最后一条必须是无条件默认」,相当于 DMN 的 FIRST 命中策略,所以每张单总能找到一条规则可走。SZV 选表而不选策略语言,是因为要改的大多是取值:谁来改、改成多少,都要财务负责人自己看得懂、查得到。判定逻辑复杂到取值表达不了时,应改用策略语言。

其他做法

做法它解决什么为什么不用
条款写成程序里的常量取值快,没有解释器改一条线要改代码、发版、重测;事后难查谁在何时改过
原地更新规则行表最小,只有当前值旧值没了,一张旧单当时按什么判的无从回放,见重放一张旧单的判定
缺键时回落到代码缺省漏配也能跑悄悄用上没人批准过的值,问题到出事才暴露

验收时可以问的问题

  • 请演示:提议一个早于批准时刻的生效时间,实际生效时间取批准时刻。
  • 请演示:查询一个不存在的键,结果是拒绝,没有缺省值顶替。
  • 请现场查一条规则的历史表记录,确认前一行与新行的整行内容都在。
  • 请现场打开一个分支的属性页,区分哪些属性是覆盖值,哪些显示「缺省值(沿用)」。

相关页

这页有帮助吗谢谢,我们会据此改进这一页。

需要帮助?联系我们

想先知道我们怎么想?关于 SZV

联系我们

企业人员规模(人)

试用工作台