确定性的核心,非确定性的外壳
Deterministic Core, Non-Deterministic Shell

十四年前,Gary Bernhardt 提出了 Functional Core, Imperative Shell 架构,将业务逻辑与外部交互分离。文章指出,纯函数并非实现可测试性的唯一路径,关键在于“确定性”。即使在使用 C 等语言或状态机时,只要核心逻辑保持确定性,就能获得相同的测试优势。作者建议将随机数生成、网络通信等不可控因素移至“非确定性外壳”,并对遗留代码进行“确定性碎片整理”。通过识别并聚合隐藏的确定性状态机,我们能在复杂的代码库中逐步重建系统的可靠性与可维护性。
不要让人性化的完美成为良好的敌人!
HN 评论区
17- kccqzy
我同意文章的主旨,但有一点想争论一下:文章说“调用未种子的 RNG(随机数生成器)”不算确定性行为,但随机算法往往比非随机算法实现更简单、渐近性能更好,同时对其性质拥有统计保证(“几乎必然”)。我最喜欢的两个例子是:(1) 随机化快速排序,每次迭代随机选择枢轴,比确定性的枢轴选择方法更简单、更高效;(2) 随机化 Treap 能给你一个平衡二叉搜索树,其实现远比红黑树简单。此外,在哈希函数内部使用随机性还能带来更实用的安全优势,即防止 HashDoS 攻击。
所以我想恳请作者删掉这个限制。即使随机算法产生不同的输出(比如 Treap 对同一序列插入操作生成形状不同的树),这些输出也具有可以通过统计方法验证的性质。
- Retr0id
我一直在思考一个我称之为“核心是渣,外壳是匠心”的概念,以此作为一种控制 vibecoding 的方法。“核心是渣”听起来像是你想避免的东西,但只要它是纯函数的(或者至少是确定性的),它就应该具备稳健的可测试性。“匠心外壳”则让事物保持人类可理解和可修改的状态,前提是你需要花些心思去设计 API 边界。
- consuming2
这种拆分在 Temporal.io 中很常见:工作流(workflows)是确定性的,而活动(activities)是幂等的。