====== 可逆计算:下一代软件构造理论 ====== ===== 引入动机 ===== 软件复用的理想一直是:写一次,处处用。但现实是,当你拿到一个已有的软件产品(比如银行核心系统、电商平台),要把它适配到不同的客户场景时,往往会陷入两难。 **如果直接修改源码**:每个客户一个分支,基础产品升级时,必须手动合并代码冲突。随着客户增多,维护成本呈指数增长。 **如果抽象出扩展接口**:需要预判所有可能的定制点,对架构能力要求极高。大部分扩展点在设计时根本无法预见。 组件理论的隐含前提是"相同才可复用",但任意两个业务系统 A 和 B 之间的公共部分,往往既小于 A 也小于 B。这意味着组件理论在系统级的粗粒度复用面前,理论上有局限性。 近年来,业界大量涌现出基于差量(Delta)思想的实践: * **Docker**:BaseImage + OverlayFS + DockerFile * **React**:Virtual DOM + Diff 算法 * **Kubernetes Kustomize**:Base + Overlay 资源定义 * **Git**:提交 = diff,合并 = 差量合并 这些实践各自解决了局部问题,但它们背后是否存在一个统一的软件构造规律? ===== 拆解问题 ===== 要回答这个问题,先要拆解"软件定制化"的本质。 假设有一个基础产品 A,客户需要的定制版本 B。传统思路是"修改 A 得到 B"。问题在于:修改后的 B 和 A 之间的差异,没有人显式记录下来。下次 A 升级到 A',原来的修改必须重新手工合并——因为那些修改隐含在 B 的代码里,没有独立存在。 如果换一个思路:**把差异显式提取出来**: **Delta = B - A** 那么 B 就可以表示为: **B = A + Delta** 这个 Delta 就是一个独立的结构,可以在 A 升级后重新应用:A' + Delta = B'。 拆解下来,问题有三个关键点: * **如何提取差量**:怎么定义"B 相对于 A 变了什么"? * **如何存储差量**:差量必须独立于 A 存在,不侵入 A 的源码 * **如何合并差量**:多个差量层叠加时,顺序和冲突如何处理? 如果这三个问题能解决,软件定制化就不再是修改源码,而是叠加差量。 ===== 给出答案 ===== 回到拆解出的三个问题,可逆计算在每个问题上都给出了明确的回答。 **如何提取差量?** 差量必须有明确的提取对象。散乱的代码难以作为提取对象——你很难说清楚"这行代码相对于那行代码变了什么"。 可逆计算的答案:**用 DSL(领域特定语言)作为提取对象**。DSL 是结构化的、严格定义的模型(如 Excel 数据模型、XML 配置、XDef 定义)。因为结构清晰,两个 DSL 之间的差异可以被精确描述。用公式表达就是: **Delta = App - Generator⟨DSL⟩** 即:最终应用减去生成器对 DSL 的映射结果,剩下的就是差量。 **如何存储差量?** 差量必须独立于原始代码存在,不能侵入源码,否则升级时会被覆盖。 可逆计算的答案:**差量存储在独立的 Delta 层中**。在文件系统中,差量文件放在独立的目录(如 _v1/、_v2/),与基础产品目录(如 _app/)完全隔离。手写的 Delta 代码从不混入自动生成的代码中,基础产品升级时只需重新生成,Delta 层自动叠加。 **如何合并差量?** 多个差量层叠加时,需要明确的规则处理优先级和冲突。 可逆计算的答案:**x-extends 按优先级合并**。框架按目录优先级自动合并多层 Delta,上层覆盖下层,同层按文件路径匹配。特别地,"可逆"意味着差量不仅可以增加内容,还可以通过标记来删除或替换已有结构。 ---- 三个问题回答完毕,完整公式即: **App = Delta x-extends Generator⟨DSL⟩** 翻译成白话:一个应用 = 差量定制 × 对领域模型的生成器。 分解来看: * **DSL(领域模型)**:结构化模型,作为差量的提取对象和操作单位 * **Generator(生成器)**:将 DSL 转化为可运行的代码/配置,可重复执行 * **Delta(差量层)**:独立的定制层,独立于生成器输出存储 * **x-extends(合并机制)**:按优先级自动叠加上层差量,支持增删改 这套公式统一解释了 Docker(Dockerfile + OverlayFS = Delta × BaseImage)、React(VDOM diff = Delta × Render)、Kustomize(Overlay = Delta × Base)等实践的内在逻辑。Nop 平台是这个理论在 Java 服务端最完整的落地实现。 ===== 与传统理论的对比 ===== ^ 传统面向对象 ^ 可逆计算 ^ | 继承是代码级复用 | 差量是结构级复用 | | 修改源码来实现定制 | 叠加差量层来实现定制 | | 组件 = 封装好的黑盒 | 模型 = 可差量化的白盒 | | 运行时多态 | 编译期结构变换 | ===== 进一步阅读 ===== * [[https://zhuanlan.zhihu.com/p/64004026|可逆计算:下一代软件构造理论]](知乎) * [[https://zhuanlan.zhihu.com/p/1942216215067100536|让演化可编程:XLang 与可逆计算的结构化范式]](知乎) * [[https://github.com/entropy-cloud/nop-entropy|Nop Platform 2.0 开源项目]]