pstack 拆解 02 · 重画与终态
模型很擅长在原结构上"贴一块",因为那是让它最快通过编译的路径。但积少成多,系统里就住进两套逻辑,谁也说不清哪一套是准的。
这一篇讲两条:新需求要按"它本来就在"来重画,而不是打补丁;迁移要朝终态收敛,不要为过渡期留下会活成永久债的兼容层。
redesign-from-first-principles
从第一性重画的背后是一个诊断:系统往往不是被一次错误的设计毁掉的,而是被一百个各自合理的小补丁。 每贴一块补丁,系统里就多住进一套局部逻辑:新的需求一套,原来的设计一套。补丁本身都没错,错的是它们让系统失去了"一个心智模型"这件事。所以整合新需求时,要维护的是设计的一致性,不是现状的延续性。"假设这个需求第一天就在,我会怎么建",是把设计重新拉回到一个模型上的办法。
它问的问题只有一句:如果我们是带着这个新需求从零开始写,会建出什么。
有个常见的例子。状态本来是个枚举,你要加一个"已归档"。贴的做法是加一个 isArchived 布尔,和原来的 status 并存。重画的做法是把它加进枚举本身。第一种两分钟写完,之后每个人都要问这两个字段谁优先。
它落到动作上是四步。
先读全。 把所有受影响的文件读完,先理解现在的设计是什么样,才谈得上重画。
问那一句。 如果从零写、带着这个需求,我会建出什么。
让改动穿透。 类型、文档、示例、设计理由,一个引用都不漏。漏掉的地方以后会以不一致的形式长回来。
想完再分步交。 先在脑子里完成整个重画,再把它拆成增量交付。不要一边想一边改。
它同时保住了未来的选择权。设计没有被补丁化,以后想换方向,路都还在。
outcome-oriented-execution
朝终态执行的背后是一个关于债的判断:迁移和重写里最贵的代码,不是目标代码,是过渡代码。为了让每一步都不断档,你会写兼容层、双写、临时开关;它们本应该只活几次提交,却常常活成永久设施,因为没有人记得它们是临时的,而删掉又怕出事。所以优化的对象应该是终态:让系统朝一个可验证的终点收敛,允许中间态在计划内、有范围、可回退地坏一段。这需要先声明哪些破损是可接受的,再用一次完整验证收尾。
理由是:让每一个中间步骤都完全稳定,往往会产生临时兼容代码,而临时兼容代码会活成长期债。
一个具体的场景。把同步 store 迁到异步,为了不破坏现有调用方,你留了一层同步适配器。迁移宣布完成了,适配器还在,因为已经没人记得它是临时的。
它有个前提,别用错地方。它只适用于有明确阶段边界的计划性重写和迁移,不是随便一个改动都可以中途弄坏。
在满足前提时,它的规则是这些。
终态完整性优先。 目标架构是对的,比每一步都平滑更重要。
先声明哪里可以坏。 把临时破损的范围明确写出来,计划内、范围清楚、可以回退,这三条同时成立才算数。
迁移期间保住高信号检查。 对正在动的区域保留能报警的检查,别在过渡期把安全网撤了。
完成时做完整验证。 计划收尾时,做一次完整的静态和运行时验证,确保终态真的对。
检验方式:数一数这次迁移里有多少代码只为过渡存在,每一项都应该有一个删除日期。
参考
原文都在 pstack 上游仓库(cursor/plugins):