--- name: think-ought-vs-is description: 思维模型:应然与实然。做设计、实现、优化、重构、定位问题,或准备把一件事交给人定之前,先答三问:它应该是什么样,它现在是什么样,两者差在哪;差异就是全部工作。开始一项设计或一个切片、同一类问题第二次出现、一件事做得比预计久、准备重跑贵的命令找原因时加载;人说「先写应然」「本质解」「别缝缝补补」,或点名 /think-ought-vs-is 时也加载。只查一个已知事实不加载。 --- # 应然与实然 回答的问题:这件事的工作到底是什么。应然是「它应该是什么样」,例如「一次测量的结论只取决于被测代码与测试」。实然是「它现在是什么样」,例如「用例带 5 秒的墙钟时限,机器忙时会超」。两句摆在一起,差的那一处就是工作。 ## 三句动作 1. **应然:它应该是什么样。** 从要回答的问题和要守的性质推出,不从手边的实现推出。问法:把这个要求当成从第一天就有,今天从头设计,它长什么样?它的结果只应该取决于哪些输入? 2. **实然:它现在是什么样。** 读结构,不读表象。证据怎样才算数,加载技能 `think-evidence`。 3. **差异:两者差在哪。** 差异就是全部工作。应然要而实然没有的,建。实然有而应然不要的,删。两边一致的,不动。 三问答不出,说明这件事还没想清楚,回到定义,不往下做。实验、重跑与问人都排在三问之后,只用来分辨三问留下的两三个候选。 ## 各类工作里怎么用 | 这类工作 | 应然问什么 | 实然看什么 | 差异变成什么 | 展开 | | --- | --- | --- | --- | --- | | 增量设计 | 新能力与不变式;它若从第一天就在,这几个领域长什么样 | 现有领域的边界、对象与契约 | 最小的一组改动 | [设计与实现](design-and-build.md) | | 实现一个切片 | 开工包写定的类型、签名与验收标准 | 起点提交上的代码 | 这个切片的提交 | [设计与实现](design-and-build.md) | | 性能优化 | 耗费只应该取决于什么,哪些功是必须做的 | 测量:耗费实际花在哪 | 不必须的功去掉 | [优化与重构](optimize-and-refactor.md) | | 重构 | 这个模块按它真正的职责,今天从头设计是什么形状 | 现在的形状,每处多出来的东西当初为什么加 | 向目标形状收拢的步骤 | [优化与重构](optimize-and-refactor.md) | | 定位问题 | 这次功能或测量必须满足的性质 | 代码与环境里哪一处让性质不成立 | 根因所在的位置 | [定位问题](diagnose.md) | | 决定要不要问人 | 这件事是人的偏好,还是能查、能建模、能论证的 | 查了没有,论证了没有 | 只把真正的取舍交给人 | [上报之前](before-asking.md) | 差异之外的不做:不为将来留扩展点,不变式排除的状态不处理,圈外的不修。见[不多做](no-more.md)。 ## 写在哪 不新开文档。三问写在这件事本来就要写的产出里:细化设计的方案论证、切片开工包的技术细节、诊断类与优化类派发简报的规格一节,都有「应然」「实然」「差异」三行。没有产出的小活,在回复里各写一句。 ## 什么时候必须重做 - 开始一项设计、一个切片、一次优化或重构。 - 同一类失败在修过一次之后又出现。不写下一个补丁,先重写应然。 - 一件事做得比预算久,或同一处的提交越来越多。 - 准备重跑一条贵的命令来找原因。 - 准备把一件事列成「请人决定」,或准备下一个没看过事实的结论。 ## 相邻的模型 `think-orthogonal`:这个问题的空间怎么拆。`think-model-first`:代码该长成什么形状。`think-right-then-well`:按什么顺序建,怎样算好。`think-evidence`:怎么知道它是真的。`think-closed-loop`:这件事该由谁做,一次做多大,多久看一次。