Rust 让对象修改变难之后,我们反而把它设计对了

💡 原文中文,约4000字,阅读约需10分钟。
📝

内容提要

Rust的所有权规则促使设计者明确对象修改边界,催生了共享的mutation ledger(修改账本),记录待提交新值、原始版本及删除标记,支持乐观锁、checker/fix和失败重试,而非事件溯源或快照比较。该设计源自Rust,现已被TeaQL的七种运行时统一采用,确保跨语言行为一致。

🔎

延伸解读

Rust 暴露了隐式契约

文章指出,Rust 的所有权规则迫使开发者明确修改的边界,而其他语言如 Java、Python 等通过垃圾回收、动态代理等机制隐藏了这些细节。这种隐藏并非设计清晰,而是让未定义的契约得以运行。Rust 的摩擦实际上揭示了架构中隐含的所有者、生命周期和副作用,促使设计者显式定义修改单元,从而让跨语言实现更容易保持一致。

账本设计的关键取舍

mutation ledger 只记录最终新值和原始版本,不复制旧值,避免同步问题。它不同于事件溯源,不持久化历史,也不支持重放;也不同于快照比较,它记录的是明确的修改意图,而非差异。这种设计使得删除、乐观锁、失败重试等场景语义清晰,但代价是丢弃原始实体状态后无法重建旧值,因此它并非持久化历史系统。

失败路径的明确状态转换

文章强调,失败后的状态比成功路径更难设计。账本规则规定:checker 拒绝时 provider 调用次数为零,账本保留;写入失败时不清账本、不递增版本;成功后才清理并接受权威值。这种设计让失败行为和重试边界可理解,也为调试保留了结构化信息,如业务意图、checker 补充、实际提交命令和最终结果。

Q&A

Rust 的所有权规则如何影响对象修改的设计?

Rust 的所有权和借用规则不允许轻易隐藏共享可变状态,迫使设计者明确修改的边界、所有权和生命周期,从而暴露了其他语言中隐含的设计问题。

什么是 mutation ledger(修改账本)?它如何工作?

mutation ledger 是一个由整个对象图共享的修改状态记录,存储待提交的新值、原始版本、新建和删除标记。它记录最终准备提交的状态,支持乐观锁和失败重试。

为什么 mutation ledger 只记录新值而不复制旧值?

因为实体本身保留了原始状态,账本只需记录新值和原始版本,避免复制实体状态和同步问题。审计时可将原始状态与新值组合。

checker 和 fix 在 TeaQL 中如何处理?

checker 拒绝不合法的业务状态,fix 自动补充字段。它们必须写入同一个 mutation ledger,确保最终数据库命令、审计和诊断一致。

保存失败后,内存中的修改状态如何处理?

保存失败时,账本保留待提交状态,不清理也不递增版本;成功后才清理并接受数据库返回的权威值。这保证了失败重试的可理解性。

mutation ledger 与事件溯源(Event Sourcing)有何区别?

mutation ledger 是暂存的待提交状态,可折叠多次赋值,保存后清理;事件溯源持久化有序事件作为事实来源。两者解决的问题不同。

TeaQL 的七种运行时如何保证行为一致?

七种运行时(Rust、Java、Python、Go、.NET、Swift、TypeScript)采用同一套 mutation-ledger 语义,并通过 conformance 测试进行可执行验证,确保跨语言行为一致。

🏷️

标签

➡️

继续阅读