Skip to main content

BLOGE 0.9.9-RC1 在线版 · 编制 2026-11-02 · English

附录 J —— BLOGE 编码重构手册

代码可以很短,却把重要决定藏起来:表达式里查了一次远端,fallback 把超时伪装成低分,或者一句「批准」同时发款和通知。本手册从这些具体症状出发,说明应该选择哪种 BLOGE 结构,以及怎样验证改写没有改变业务承诺。

方法与可运行工作坊核对 BLOGE 0.9.9-RC1 候选源码。它们不是引擎强制执行的通用规范,也不代表候选制品已经公开发布。首次阅读按正文前进;遇到设计判断时按 BP 编号查阅;第 34 章把这些选择串成一次完整重构。

先选择表达,再选择维护范围​

值计算与独立执行责任

主要责任首选表达需要保留的边界
读取或重命名已有字段input binding数据来源显式
通用、轻量的值计算已注册 built-in function类型、null、数值与 locale 语义
多字段命名投影transform不把外部动作藏进投影
有界计算需要业务名称helper;需要 DSL 复用时注册 typed function参数显式、可独立测试
多个事实共同决定结果decision_table 或领域方法重叠、遗漏、优先级
选择下一条执行路径branch只消费决定,不重复计算政策
需要独立调用和控制的能力Operator输入输出、失败、成本与 effect
复用多步业务片段subgraph明确输入输出与唯一所有者

纯计算不一定便宜。一个耗时较长、需要独立隔离的算法也可以使用 Operator;一个只在内部调用的 helper 不必因为有名字就发布为 DSL function。

表达形式与维护范围

维护范围合适内容不足以扩大范围的理由
当前应用本企业政策、业务适配「其他团队也许用得上」
团队或领域库多个消费者共享同一契约复制次数多,但政策所有者不同
可选模块协议、SDK、专属接线为安装方便把供应商依赖放入 core
BLOGE 核心稳定、跨领域的基础能力仅仅少写一行表达式

BP-01​

通用值计算先查既有函数​

症状: 为 trim、集合去重或字段拼接增加专用 Operator。

改法与原理: 先查实际 runtime 的 registry/catalog,再核对语义。单个字段用 binding;相关投影需要命名时用 transform。已有 trim、distinct 能表达意图时,没有必要增加一个可重试节点。投影仍需求值,不能称为零成本。

验证: 检查 null、空集合、顺序和错误类型。concat 把 null 当空串,不等于满足姓名必填要求;通用 round 不等于货币政策中的舍入。

例外: now()、today()、uuid() 也是内置函数,却与执行环境有关;不能假定函数都纯或跨执行不变。时间和 ID 从执行服务取得,也不能据此假定重试后值不变。

BP-02​

为有界计算命名,保留业务参数​

症状: 多层嵌套表达式需要解释执行顺序;同一计算的修复要改多个位置。

改法与原理: 先提取普通领域方法。只有 graph 作者需要调用时,再通过 @BlogeFunction、@BlogeFunctionLibrary 注册 typed function。用 JavaDoc 说明输入、结果和错误,用注解声明 effect 与确定性;注解不是运行时行为证明。

工作坊的 loanText.normalizePolicyCode 是项目新增函数,不是 BLOGE 内置 API。它拒绝空代码,以 Locale.ROOT 规范大小写;这份合同不同于依赖默认 locale 的通用转换。

验证: 工作坊包含完整类、注册和 DSL 调用;测试土耳其语默认 locale、null、空白、catalog 名称和投影结果。

例外: 一次 trim 已足够清楚时不抽取函数;只供 Operator 内部使用的方法不必发布到 DSL。registry 允许同名替换,因此新库应有明确前缀并检查冲突。

BP-03​

独立执行责任需要 Operator 边界​

症状: customer.currentCredit(id) 在绑定中读远端;一次函数调用既查询又写库;纯算法耗时很长,却与绑定求值混在一起。

改法与原理: 当调用需要独立 timeout、retry、替换、观测或容量策略时,优先使用 Operator。例如显式 CreditScore node,后续政策只读 credit.output.score。一个 Operator 承担一项可说明的能力,不把审批、发款、通知捆成一次失败边界。

验证: 分开观察函数调用、Operator 调用和真正的外部 effect。使用 EffectPort 时经 invoke 调用,并验证实际 REAL/DOUBLE/DENY 接线;单独建一个 node 不会自动截获任意内部 HTTP/JDBC 调用。

例外: 实例函数库支持 repository/client 和 READ_EXTERNAL,所以 I/O 用 Operator 是默认设计建议,不是语法限制。保留外部读取函数时,应说明重复求值、一致性和控制需求。反过来,没有副作用的大计算也可能需要 Operator。

BP-04​

公共函数先证明语义缺口​

症状: 一个企业规则被建议加入 core;为少写一层组合而新增公共函数。

改法与原理: 项目注册、团队函数模块、默认 built-in 是不同决定。公共提案应包含不同业务语境中的同一语义、现有组合的具体不足、完整类型/null/错误/顺序/数值合同、成本边界、维护者和兼容方案。特定 SDK 或客户凭证通常应进入可选模块。

实例: distinct 已存在;「按业务键保留首项」可以成为项目探索,但 distinctBy 在此只是候选名称。提案必须先说明 null 键、首末项、相等性和顺序,不能先把未实现语法写进生产 DSL。

验证: 至少用真实消费者的不同输入检验同一合同,并回归已有函数调用。修复违反既有合同的实现与改变合同是两回事;修改 null、舍入或返回形状需要明确迁移。

例外: 某银行准入评分有政策所有者与版本,适合领域代码或决策表。它不因被调用很多次就变成通用 built-in。

BP-05​

扩展 Operator 先区分配置、适配和新动作​

变化优先改法订单映射
地址、凭证、接线变化配置或实例装配同一支付服务的不同环境
供应商协议变化窄 port/adapter、可选依赖保留授权合同,替换提供方
业务保证或结果变化新能力或显式版本支付授权与扣款分别建模
多项能力按顺序完成graph/subgraph扣款、登记、通知
只改变字段形状binding/transform映射提供方返回

症状: UniversalBusinessOperator(mode, payload) 同时承担查询、审批和扣款。

改法与原理: 让能力名称和合同保持一致。公共 Operator 提案先给出 schema、effect、错误、幂等、维护者及真实依赖合同;供应商连接器可单独发布,不必进入 core。

验证与例外: 供应商 adapter 可复用同一能力,但不能把授权和实际扣款仅作为一个模式参数。默认 UNKNOWN/MIXED 不表示已具备安全重试保证。

BP-06​

多事实决策显式列规则,路由只消费结果​

症状: 超过 3 个独立判断维度共同决定一个结果;改一条政策需要追踪多层 if。

改法与原理: 先列事实、输出和规则优先级,再评估决策表。branch 消费政策结果,不在分支里重新算政策。「超过 3 个」是审查信号,不是引擎阈值:四个枚举值的路由仍可直接用 branch。

贷款 starter 的拒绝条件是黑名单命中、信用低于 600、欺诈分至少 80 或收入 weak;否则信用至少 740、欺诈低于 20 且收入 strong 时批准,其余人工复核。第 34 章把这个决定迁到 decision_table,保留七个结果字段和三路行为。

验证: 比较固定 CSV 标准答案、重构前后输出、metadata、SKIPPED 和模拟动作计数。短领域方法本来清楚且政策稳定时,保留它也是合格的设计结果。

例外: 复杂算法和递归不适合塞进规则行;无必要的简单 guard 不必各建一张表。

BP-07​

先解释重叠,再选择 hit policy​

合同策略必须检查
允许重叠,前者优先first顺序变化是否改变业务结果
规则本应互斥unique实际执行的重叠输入报错
多条命中但结果相同any不同输出时冲突
每条命中贡献一项collect空、多项、重复及默认项

实例: 信用 760、欺诈 10、收入 strong、黑名单 true,同时满足拒绝与批准条件。first 保留拒绝优先;直接换成 unique 会把有效拒绝变成冲突。unique 也不静态证明无限输入域没有重叠。

验证与例外: 改写为互斥规则后可以选择 unique,但须验证排除条件和遗漏。collect + otherwise 在当前实现中始终追加默认项;「集合为空才补正常说明」需要后续逻辑,不能用这条 otherwise 模拟。

BP-08​

业务数据走输入输出,依赖表达真实前提​

症状: Operator 从共享 map/context 偷读上游结果;独立的信用与收入检查被机械串行;合流无条件读取未选分支输出。

改法与原理: 显式绑定业务输入,context 用于请求元数据。删除无业务理由的依赖,让所需事实扇入决策;只有「必须先完成」而没有字段引用时,再声明控制依赖。并发还受线程安全、CPU 和提供方容量限制。

验证: 比较数据来源与执行轨迹;覆盖可空、缺失和 SKIPPED 输出。审批必须先于扣款,即使没有直接字段引用,也仍需控制前提。

BP-09​

一层负责重试,业务键跨尝试稳定​

症状: graph、Operator 循环、SDK 各允许总计 3 次尝试;每次用新 uuid 做幂等键。

改法与原理: 指定主要重试层并协调总预算。相同逻辑请求的业务键跨重试和恢复稳定;新的合法请求获得新身份。executionId 通常标识运行,不自动等于业务请求身份。

验证: 同时记录底层尝试和已发生 effect;两层各允许总计 3 次尝试,可能放大到 9 次。Java builder 的 .retry(1, backoff) 表示初次调用后再重试 1 次,总计 2 次调用。工作坊证明 EffectPort.idempotencyKey 声明本身不会去重;去重由提供方或应用实现。

0.9.9 边界: durable 恢复预算与单次调用 retry 不同。恢复失败预算按连续无进展失败计算;仅重新接管不等于提交了业务进展。

BP-10​

超时、降级和补偿保留真实业务状态​

症状: 信用超时返回 score=0;支付超时直接判为未扣款;通知失败后宣称整个流程已回滚。

改法与原理: 区分成功、拒绝、降级和未知。写入超时可能已发生 effect,需要按业务键对账。fallback 要让下游识别降级;补偿用原动作 receipt,且该动作必须可被业务上反向处置。

验证: 分别模拟未执行、成功后响应丢失、重试耗尽、降级被消费、补偿失败和再次处置。schema 相同不能证明业务等价。

例外: 政策允许「无可信结果就拒绝」时可拒绝,但不能伪造一次成功信用查询。补偿不等于数据库式跨系统回滚。

BP-11​

时间、等待与恢复身份显式化​

症状: sleep 等待人工批准;多个节点各自读现在并推导不同截止时间;在同一 runtime 恢复就称为冷恢复。

改法与原理: 长等待使用声明的挂起模型与 deadline;Operator 使用 ctx.timeSource(),业务截止时间固定为输入事实。用新 runtime 读取持久事实验证冷恢复。

验证: 测试截止前、恰好截止、截止后和错误相关键。0.9.9 的旧 worker 失权后不得继续本地提交,但这仍不能证明远端 effect 未发生。checkpoint、租约与外部幂等分别验证。

例外: 有界短轮询可以保留,需明确次数、间隔、总 deadline 和资源影响。

BP-12​

复用多步流程,明确唯一生命周期所有者​

症状: 多图复制一段信用评估;子图读取父图任意 context;Session 和状态机各自维护同一权威业务状态。

改法与原理: 稳定业务片段才抽成 subgraph,显式传入事实并返回结果,不让调用方依赖内部 node ID。按主导身份选择外层生命周期 owner,内层通过公开 signal 与终局结果交互。

验证与例外: 换内部节点不影响调用方,恢复后 signal 仍到正确 owner。形状相似但政策归属不同的两段流程不必共享;类或图数量少不等于责任清楚。

BP-13​

批量、循环与 Agent 都要能停止​

症状: 对未知集合直接并发;直到成功的循环;Agent 用完轮次却返回正常完成结果。

改法与原理: 分别说明输入规模、容量、业务退出条件与上限;Agent 还需明确工具范围与预算。使用各模型实际支持的参数,不发明一个跨模型通用 DSL 限流字段。

验证: 空、边界、超限、部分失败、永不满足退出条件。0.9.9 的有界异步恢复需显式启用,共享预算为进程内范围;容量名额覆盖实际 worker 生命周期,方法返回或取消请求不等于已释放资源。

BP-14​

标准答案独立,也验证不该发生的动作​

症状: 只断言 SUCCESS;当前实现生成 expected;mock 整个 Operator 后声称内部政策得到验证。

改法与原理: 领域方法验证计算;graph 验证依赖与路径;port contract 验证提供方行为;Scenario 使用业务负责人认可的 Oracle。贷款拒绝须分别观察拒绝结果、approve 的 SKIPPED 和模拟批准动作计数为 0。

验证: 工作坊把批准规则移到黑名单规则之前,原始黑名单 Case 必须揭示改变。等价重构证明保留旧行为,不能证明旧政策合理;sensitivity 和 bounded property 的结论仍受样本与控制范围约束。

能力扩展提案与重构完成卡​

材料可审阅的交付
问题与既有能力当前代码、真实用例、查过的 catalog 与组合不足
选择表达、执行责任、维护范围及被否决方案
合同类型、null、错误、effect、确定性、成本与版本
兼容既有消费者、迁移方案、维护者
证据固定标准答案、边界、反例、路径、effect 与测试范围

提交前回答:这次移动的是数据形状、政策还是执行责任?新增结构带来了什么可观察收益?哪些旧输出和外部动作必须保持?失败注入在哪个接缝能揭示错误?只减少行数或 node 数量不构成完成证据。

完整代码由第 34 章资产目录维护。命令、12 个标准案例、反例和验证限制见工作坊。

Coding Agent: Open the versioned task guide.