46 处理无法解决的难题

面对看似无解的问题先枚举真正约束,区分事实、假设和自设框框,再改变可变条件。

学习目标

  • 能把一个看似无解的问题拆成目标、事实约束、隐含假设和可变条件
  • 能用边界样本识别自设框框,区分真正必要条件与团队习惯
  • 能用唯一干预、反例和重放证据验证新解没有越过真实边界

先确认问题是不是无解

本页依据 David Thomas、Andrew Hunt《程序员修炼之道:通向务实的最高境界(第2版)》,云风译,电子工业出版社,2020 年 4 月,ISBN 9787121384356 的公开中文目录,独立重构 46 处理无法解决的难题。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图或答案。

当团队说“这件事做不到”时,困难可能来自真实的资源限制,也可能来自没有被说出的旧流程。务实的处理方式不是立刻寻找更聪明的技巧,而是把目标、约束、假设和边界写出来,再一次只改变一个条件。这样才能知道问题真的无解,还是被一个可以移除的框框挡住了。

三个会让难题继续保持无解的陷阱

五个词拆开一条难题链

<Term def="希望在明确对象、时间和结果条件下达到的状态。">目标</Term>必须描述结果,而不是描述某个既有方案。比如“让用户在当天看到账单”是目标,“必须继续使用夜间批处理”不是目标。

<Term def="如果不满足就不能接受结果的可观察事实、资源边界或规则。">约束</Term>应当有来源。容量、法规、数据保留、接口兼容和安全边界可能是真约束;“我们一直这样做”则需要进一步验证。

<Term def="尚未被证明却会影响候选解空间的判断。">隐含假设</Term>是最值得优先检查的地方。一个假设如果没有所有者、证据和失效条件,就不应直接进入拒绝理由。

<Term def="由习惯、工具、组织边界或表达方式制造的可移动限制。">自设框框</Term>不是虚构困难,而是把可改变的条件误写成不可改变。找到它之后,要记录谁可以改变、代价是什么、改变后哪条真实约束仍然保留。

<Term def="为了让结果成立而必须保留的条件,且能由输入或规则验证。">必要条件</Term>用来防止“跳出框框”变成随意放宽要求。新方案必须满足必要条件,否则只是把失败推迟到下游。

这一链条的方向是:先描述目标,再列约束,检查假设,标出可移动框框,最后验证必要条件。反例负责证明链条没有把特殊成功误认为普遍规律。

难题回路:先识别限制,再改变一个可变条件真实约束守住边界,反例负责检查新解是不是把失败移到了下游1目标结果是什么已核对2约束哪些必须保留已核对3假设什么尚未证明已核对4框框什么可以移动当前干预点5解法反例能否通过待重放先证明哪个限制是真实的,再决定是否值得移动一个框框
专属图示:难题诊断从目标和约束开始,以反例和必要条件检验解法。

提示81:不要跳出框框思考——找到框框

“跳出框框”不能只表示提出一个更大胆的答案。它应当先回答:框框是谁设的?它保护什么?改变它会破坏哪条必要条件?如果答案只是“大家都知道”,就还没有形成可复核的约束。

可以用一个账本区分四类陈述:事实写来源和测量;假设写验证方式和过期时间;偏好写协商对象;必要条件写失败时的拒绝动作。这个区分让团队能够对一个条件动手,而不必同时改掉整个系统。

type Constraint = {
  name: string;
  source: "fact" | "assumption" | "preference" | "required";
  evidence: string;
  movable: boolean;
};
 
const movable = (constraint: Constraint) =>
  constraint.movable && constraint.source !== "required";

这个小函数不负责解决难题,它只让“可以改变”成为显式判断。实际决策还要保存证据和责任人,并在改变后重放相同输入。

最小运行合同

先冻结对象、输入和目标,再指定唯一干预。一次实验只能改变一个条件,例如把“必须整批处理”改成“允许分批提交”;不能同时换存储、重写接口并扩大时间窗口。运行记录至少包含预测节点、实际首差、拒绝原因和恢复动作。

unit: tpp20-topic-46-impossible-puzzles
baseline:
  object: 当日账单
  input: 订单事件与结算窗口
intervention:
  only_change: 是否必须等待完整批次
boundary:
  must_preserve: 金额准确、重复事件幂等、审计可追溯
evidence:
  record: 约束来源、假设验证、首差、反例、恢复

基线样本要能被别人重建。若新解满足速度却破坏幂等或审计,它不是“部分成功”,而是没有满足必要条件;拒绝必须发生在结果被下游接收之前。

选择一个难题样本

Interactive lab

选择样本,定位难题链的首个变化

自设框框

输入证据

团队认为只能等待完整数据集,但这个流程来自旧批处理工具,没有外部来源。

实际首差

假设节点:验证是否可以增量提交,同时保持金额和审计条件。

恢复动作

先保留旧路径作为回退,再用相同输入比较增量与整批结果。

先记录预测,再点击样本;一个更快的结果只有在必要条件仍成立时才算新解。

分步1 / 4

1. 写目标和真实约束

选择一个团队正在争论的问题,写出对象、期望结果、约束来源、时间窗口、资源边界和真正的拒绝条件。把“我们一直这样做”单独标为待验证陈述。

正常、边界与单一故障证据

证据矩阵:可移动不等于可以放弃必要条件每种样本都要记录预测、首差、拒绝理由和恢复动作观察项正常边界故障命题目标清楚边界可判假设失效来源证据可追阈值明确责任可见干预只改一项条件不越界首差暴露恢复结果重放明确拒绝回到基线复核者拿到同一输入、边界和日志后,应能重建结论而不是猜作者意图
专属图示:正常样本展示能力,边界样本限定范围,故障样本验证可恢复性。
样本只改变的变量预期判定必存证据
正常已知输入、完整依赖、明确约束目标达成且必要条件全部满足基线、逐节点输出、结果摘要
边界恰好容量、期限或资源阈值接受或拒绝明确,不产生假完成阈值来源、比较结果、原状态
单一故障一个假设、依赖或角色失效在首个异常点暴露并可恢复首差、失败上下文、恢复与回归

证据不是为了证明每次都成功,而是为了限定结论适用范围。若边界样本显示“分批”破坏了金额一致性,就应撤回方案或增加必要条件;不能只展示速度提升的正常样本。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

目标

在明确对象、时间和结果条件下希望达到的状态。

约束

不满足就不能接受结果的事实、资源边界或规则。

隐含假设

尚未被证明却会影响候选解空间的判断。

自设框框

由习惯、工具、组织边界或表达方式制造的可移动限制。

必要条件

为让结果成立而必须保留且能由输入或规则验证的条件。

练习

练习

问题 1: 团队说“本周无法交付,因为只能等完整数据集”。请列出你会追问的约束和假设。

问题 2: 你把“必须整批处理”改成了“允许分批提交”,速度提高但重复事件导致金额翻倍。如何判定这次尝试?

问题 3: 一个架构限制被证明只是团队习惯,但移除它会增加运维成本。你会怎样记录决策?

资料与写作方式声明

本章以程序员修炼之道权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

本单元回顾

处理无法解决的难题,不是强行乐观,也不是把每条限制都放宽。先区分目标、真实约束、隐含假设和自设框框,再只改变一个可变条件,用边界和反例确认必要条件仍在。能说明新解何时成立、何时拒绝、如何回退,才把提示变成可迁移的工程判断。

前后导航

讨论

评论区加载中…